1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020 Arm Limited
5 * Based on arch/arm64/kernel/machine_kexec_file.c:
6 * Copyright (C) 2018 Linaro Limited
8 * And arch/powerpc/kexec/file_load.c:
9 * Copyright (C) 2016 IBM Corporation
12 #include <linux/ima.h>
13 #include <linux/kernel.h>
14 #include <linux/kexec.h>
15 #include <linux/memblock.h>
16 #include <linux/libfdt.h>
18 #include <linux/of_fdt.h>
19 #include <linux/random.h>
20 #include <linux/slab.h>
21 #include <linux/types.h>
23 #define RNG_SEED_SIZE 128
26 * Additional space needed for the FDT buffer so that we can add initrd,
27 * bootargs, kaslr-seed, rng-seed, useable-memory-range and elfcorehdr.
29 #define FDT_EXTRA_SPACE 0x1000
32 * fdt_find_and_del_mem_rsv - delete memory reservation with given address and size
34 * @fdt: Flattened device tree for the current kernel.
35 * @start: Starting address of the reserved memory.
36 * @size: Size of the reserved memory.
38 * Return: 0 on success, or negative errno on error.
40 static int fdt_find_and_del_mem_rsv(void *fdt
, unsigned long start
, unsigned long size
)
42 int i
, ret
, num_rsvs
= fdt_num_mem_rsv(fdt
);
44 for (i
= 0; i
< num_rsvs
; i
++) {
45 u64 rsv_start
, rsv_size
;
47 ret
= fdt_get_mem_rsv(fdt
, i
, &rsv_start
, &rsv_size
);
49 pr_err("Malformed device tree.\n");
53 if (rsv_start
== start
&& rsv_size
== size
) {
54 ret
= fdt_del_mem_rsv(fdt
, i
);
56 pr_err("Error deleting device tree reservation.\n");
68 * get_addr_size_cells - Get address and size of root node
70 * @addr_cells: Return address of the root node
71 * @size_cells: Return size of the root node
73 * Return: 0 on success, or negative errno on error.
75 static int get_addr_size_cells(int *addr_cells
, int *size_cells
)
77 struct device_node
*root
;
79 root
= of_find_node_by_path("/");
83 *addr_cells
= of_n_addr_cells(root
);
84 *size_cells
= of_n_size_cells(root
);
92 * do_get_kexec_buffer - Get address and size of device tree property
94 * @prop: Device tree property
96 * @addr: Return address of the node
97 * @size: Return size of the node
99 * Return: 0 on success, or negative errno on error.
101 static int do_get_kexec_buffer(const void *prop
, int len
, unsigned long *addr
,
104 int ret
, addr_cells
, size_cells
;
106 ret
= get_addr_size_cells(&addr_cells
, &size_cells
);
110 if (len
< 4 * (addr_cells
+ size_cells
))
113 *addr
= of_read_number(prop
, addr_cells
);
114 *size
= of_read_number(prop
+ 4 * addr_cells
, size_cells
);
119 #ifdef CONFIG_HAVE_IMA_KEXEC
121 * ima_get_kexec_buffer - get IMA buffer from the previous kernel
122 * @addr: On successful return, set to point to the buffer contents.
123 * @size: On successful return, set to the buffer size.
125 * Return: 0 on success, negative errno on error.
127 int __init
ima_get_kexec_buffer(void **addr
, size_t *size
)
130 unsigned long tmp_addr
;
131 unsigned long start_pfn
, end_pfn
;
135 prop
= of_get_property(of_chosen
, "linux,ima-kexec-buffer", &len
);
139 ret
= do_get_kexec_buffer(prop
, len
, &tmp_addr
, &tmp_size
);
143 /* Do some sanity on the returned size for the ima-kexec buffer */
148 * Calculate the PFNs for the buffer and ensure
149 * they are with in addressable memory.
151 start_pfn
= PHYS_PFN(tmp_addr
);
152 end_pfn
= PHYS_PFN(tmp_addr
+ tmp_size
- 1);
153 if (!page_is_ram(start_pfn
) || !page_is_ram(end_pfn
)) {
154 pr_warn("IMA buffer at 0x%lx, size = 0x%zx beyond memory\n",
159 *addr
= __va(tmp_addr
);
166 * ima_free_kexec_buffer - free memory used by the IMA buffer
168 int __init
ima_free_kexec_buffer(void)
173 struct property
*prop
;
175 prop
= of_find_property(of_chosen
, "linux,ima-kexec-buffer", NULL
);
179 ret
= do_get_kexec_buffer(prop
->value
, prop
->length
, &addr
, &size
);
183 ret
= of_remove_property(of_chosen
, prop
);
187 memblock_free_late(addr
, size
);
193 * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
195 * @fdt: Flattened Device Tree to update
196 * @chosen_node: Offset to the chosen node in the device tree
198 * The IMA measurement buffer is of no use to a subsequent kernel, so we always
199 * remove it from the device tree.
201 static void remove_ima_buffer(void *fdt
, int chosen_node
)
208 if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC
))
211 prop
= fdt_getprop(fdt
, chosen_node
, "linux,ima-kexec-buffer", &len
);
215 ret
= do_get_kexec_buffer(prop
, len
, &addr
, &size
);
216 fdt_delprop(fdt
, chosen_node
, "linux,ima-kexec-buffer");
220 ret
= fdt_find_and_del_mem_rsv(fdt
, addr
, size
);
222 pr_debug("Removed old IMA buffer reservation.\n");
225 #ifdef CONFIG_IMA_KEXEC
227 * setup_ima_buffer - add IMA buffer information to the fdt
228 * @image: kexec image being loaded.
229 * @fdt: Flattened device tree for the next kernel.
230 * @chosen_node: Offset to the chosen node.
232 * Return: 0 on success, or negative errno on error.
234 static int setup_ima_buffer(const struct kimage
*image
, void *fdt
,
239 if (!image
->ima_buffer_size
)
242 ret
= fdt_appendprop_addrrange(fdt
, 0, chosen_node
,
243 "linux,ima-kexec-buffer",
244 image
->ima_buffer_addr
,
245 image
->ima_buffer_size
);
249 ret
= fdt_add_mem_rsv(fdt
, image
->ima_buffer_addr
,
250 image
->ima_buffer_size
);
254 pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
255 image
->ima_buffer_addr
, image
->ima_buffer_size
);
259 #else /* CONFIG_IMA_KEXEC */
260 static inline int setup_ima_buffer(const struct kimage
*image
, void *fdt
,
265 #endif /* CONFIG_IMA_KEXEC */
268 * of_kexec_alloc_and_setup_fdt - Alloc and setup a new Flattened Device Tree
270 * @image: kexec image being loaded.
271 * @initrd_load_addr: Address where the next initrd will be loaded.
272 * @initrd_len: Size of the next initrd, or 0 if there will be none.
273 * @cmdline: Command line for the next kernel, or NULL if there will
275 * @extra_fdt_size: Additional size for the new FDT buffer.
277 * Return: fdt on success, or NULL errno on error.
279 void *of_kexec_alloc_and_setup_fdt(const struct kimage
*image
,
280 unsigned long initrd_load_addr
,
281 unsigned long initrd_len
,
282 const char *cmdline
, size_t extra_fdt_size
)
285 int ret
, chosen_node
, len
;
289 fdt_size
= fdt_totalsize(initial_boot_params
) +
290 (cmdline
? strlen(cmdline
) : 0) +
293 fdt
= kvmalloc(fdt_size
, GFP_KERNEL
);
297 ret
= fdt_open_into(initial_boot_params
, fdt
, fdt_size
);
299 pr_err("Error %d setting up the new device tree.\n", ret
);
303 /* Remove memory reservation for the current device tree. */
304 ret
= fdt_find_and_del_mem_rsv(fdt
, initial_boot_params_pa
,
305 fdt_totalsize(initial_boot_params
));
306 if (ret
== -EINVAL
) {
307 pr_err("Error removing memory reservation.\n");
311 chosen_node
= fdt_path_offset(fdt
, "/chosen");
312 if (chosen_node
== -FDT_ERR_NOTFOUND
)
313 chosen_node
= fdt_add_subnode(fdt
, fdt_path_offset(fdt
, "/"),
315 if (chosen_node
< 0) {
320 ret
= fdt_delprop(fdt
, chosen_node
, "linux,elfcorehdr");
321 if (ret
&& ret
!= -FDT_ERR_NOTFOUND
)
323 ret
= fdt_delprop(fdt
, chosen_node
, "linux,usable-memory-range");
324 if (ret
&& ret
!= -FDT_ERR_NOTFOUND
)
327 /* Did we boot using an initrd? */
328 prop
= fdt_getprop(fdt
, chosen_node
, "linux,initrd-start", &len
);
330 u64 tmp_start
, tmp_end
, tmp_size
;
332 tmp_start
= of_read_number(prop
, len
/ 4);
334 prop
= fdt_getprop(fdt
, chosen_node
, "linux,initrd-end", &len
);
340 tmp_end
= of_read_number(prop
, len
/ 4);
343 * kexec reserves exact initrd size, while firmware may
344 * reserve a multiple of PAGE_SIZE, so check for both.
346 tmp_size
= tmp_end
- tmp_start
;
347 ret
= fdt_find_and_del_mem_rsv(fdt
, tmp_start
, tmp_size
);
349 ret
= fdt_find_and_del_mem_rsv(fdt
, tmp_start
,
350 round_up(tmp_size
, PAGE_SIZE
));
356 if (initrd_load_addr
) {
357 ret
= fdt_setprop_u64(fdt
, chosen_node
, "linux,initrd-start",
362 ret
= fdt_setprop_u64(fdt
, chosen_node
, "linux,initrd-end",
363 initrd_load_addr
+ initrd_len
);
367 ret
= fdt_add_mem_rsv(fdt
, initrd_load_addr
, initrd_len
);
372 ret
= fdt_delprop(fdt
, chosen_node
, "linux,initrd-start");
373 if (ret
&& (ret
!= -FDT_ERR_NOTFOUND
))
376 ret
= fdt_delprop(fdt
, chosen_node
, "linux,initrd-end");
377 if (ret
&& (ret
!= -FDT_ERR_NOTFOUND
))
381 if (image
->type
== KEXEC_TYPE_CRASH
) {
382 /* add linux,elfcorehdr */
383 ret
= fdt_appendprop_addrrange(fdt
, 0, chosen_node
,
384 "linux,elfcorehdr", image
->elf_load_addr
,
385 image
->elf_headers_sz
);
390 * Avoid elfcorehdr from being stomped on in kdump kernel by
391 * setting up memory reserve map.
393 ret
= fdt_add_mem_rsv(fdt
, image
->elf_load_addr
,
394 image
->elf_headers_sz
);
398 #ifdef CONFIG_CRASH_DUMP
399 /* add linux,usable-memory-range */
400 ret
= fdt_appendprop_addrrange(fdt
, 0, chosen_node
,
401 "linux,usable-memory-range", crashk_res
.start
,
402 crashk_res
.end
- crashk_res
.start
+ 1);
406 if (crashk_low_res
.end
) {
407 ret
= fdt_appendprop_addrrange(fdt
, 0, chosen_node
,
408 "linux,usable-memory-range",
409 crashk_low_res
.start
,
410 crashk_low_res
.end
- crashk_low_res
.start
+ 1);
419 ret
= fdt_setprop_string(fdt
, chosen_node
, "bootargs", cmdline
);
423 ret
= fdt_delprop(fdt
, chosen_node
, "bootargs");
424 if (ret
&& (ret
!= -FDT_ERR_NOTFOUND
))
429 ret
= fdt_delprop(fdt
, chosen_node
, "kaslr-seed");
430 if (ret
== -FDT_ERR_NOTFOUND
)
435 if (rng_is_initialized()) {
436 u64 seed
= get_random_u64();
438 ret
= fdt_setprop_u64(fdt
, chosen_node
, "kaslr-seed", seed
);
442 pr_notice("RNG is not initialised: omitting \"%s\" property\n",
447 if (rng_is_initialized()) {
450 ret
= fdt_setprop_placeholder(fdt
, chosen_node
, "rng-seed",
451 RNG_SEED_SIZE
, &rng_seed
);
454 get_random_bytes(rng_seed
, RNG_SEED_SIZE
);
456 pr_notice("RNG is not initialised: omitting \"%s\" property\n",
460 ret
= fdt_setprop(fdt
, chosen_node
, "linux,booted-from-kexec", NULL
, 0);
464 remove_ima_buffer(fdt
, chosen_node
);
465 ret
= setup_ima_buffer(image
, fdt
, fdt_path_offset(fdt
, "/chosen"));