1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2018 Linaro Limited
6 * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
8 * Most code is derived from arm64 port of kexec-tools
11 #define pr_fmt(fmt) "kexec_file: " fmt
13 #include <linux/ioport.h>
14 #include <linux/kernel.h>
15 #include <linux/kexec.h>
16 #include <linux/libfdt.h>
17 #include <linux/memblock.h>
18 #include <linux/of_fdt.h>
19 #include <linux/random.h>
20 #include <linux/slab.h>
21 #include <linux/string.h>
22 #include <linux/types.h>
23 #include <linux/vmalloc.h>
24 #include <asm/byteorder.h>
26 /* relevant device tree properties */
27 #define FDT_PROP_KEXEC_ELFHDR "linux,elfcorehdr"
28 #define FDT_PROP_MEM_RANGE "linux,usable-memory-range"
29 #define FDT_PROP_INITRD_START "linux,initrd-start"
30 #define FDT_PROP_INITRD_END "linux,initrd-end"
31 #define FDT_PROP_BOOTARGS "bootargs"
32 #define FDT_PROP_KASLR_SEED "kaslr-seed"
33 #define FDT_PROP_RNG_SEED "rng-seed"
34 #define RNG_SEED_SIZE 128
36 const struct kexec_file_ops
* const kexec_file_loaders
[] = {
41 int arch_kimage_file_post_load_cleanup(struct kimage
*image
)
43 vfree(image
->arch
.dtb
);
44 image
->arch
.dtb
= NULL
;
46 vfree(image
->arch
.elf_headers
);
47 image
->arch
.elf_headers
= NULL
;
48 image
->arch
.elf_headers_sz
= 0;
50 return kexec_image_post_load_cleanup_default(image
);
53 static int setup_dtb(struct kimage
*image
,
54 unsigned long initrd_load_addr
, unsigned long initrd_len
,
55 char *cmdline
, void *dtb
)
59 ret
= fdt_path_offset(dtb
, "/chosen");
65 ret
= fdt_delprop(dtb
, off
, FDT_PROP_KEXEC_ELFHDR
);
66 if (ret
&& ret
!= -FDT_ERR_NOTFOUND
)
68 ret
= fdt_delprop(dtb
, off
, FDT_PROP_MEM_RANGE
);
69 if (ret
&& ret
!= -FDT_ERR_NOTFOUND
)
72 if (image
->type
== KEXEC_TYPE_CRASH
) {
73 /* add linux,elfcorehdr */
74 ret
= fdt_appendprop_addrrange(dtb
, 0, off
,
75 FDT_PROP_KEXEC_ELFHDR
,
76 image
->arch
.elf_headers_mem
,
77 image
->arch
.elf_headers_sz
);
79 return (ret
== -FDT_ERR_NOSPACE
? -ENOMEM
: -EINVAL
);
81 /* add linux,usable-memory-range */
82 ret
= fdt_appendprop_addrrange(dtb
, 0, off
,
85 crashk_res
.end
- crashk_res
.start
+ 1);
87 return (ret
== -FDT_ERR_NOSPACE
? -ENOMEM
: -EINVAL
);
92 ret
= fdt_setprop_string(dtb
, off
, FDT_PROP_BOOTARGS
, cmdline
);
96 ret
= fdt_delprop(dtb
, off
, FDT_PROP_BOOTARGS
);
97 if (ret
&& (ret
!= -FDT_ERR_NOTFOUND
))
102 if (initrd_load_addr
) {
103 ret
= fdt_setprop_u64(dtb
, off
, FDT_PROP_INITRD_START
,
108 ret
= fdt_setprop_u64(dtb
, off
, FDT_PROP_INITRD_END
,
109 initrd_load_addr
+ initrd_len
);
113 ret
= fdt_delprop(dtb
, off
, FDT_PROP_INITRD_START
);
114 if (ret
&& (ret
!= -FDT_ERR_NOTFOUND
))
117 ret
= fdt_delprop(dtb
, off
, FDT_PROP_INITRD_END
);
118 if (ret
&& (ret
!= -FDT_ERR_NOTFOUND
))
123 ret
= fdt_delprop(dtb
, off
, FDT_PROP_KASLR_SEED
);
124 if (ret
== -FDT_ERR_NOTFOUND
)
129 if (rng_is_initialized()) {
130 u64 seed
= get_random_u64();
131 ret
= fdt_setprop_u64(dtb
, off
, FDT_PROP_KASLR_SEED
, seed
);
135 pr_notice("RNG is not initialised: omitting \"%s\" property\n",
136 FDT_PROP_KASLR_SEED
);
140 if (rng_is_initialized()) {
142 ret
= fdt_setprop_placeholder(dtb
, off
, FDT_PROP_RNG_SEED
,
143 RNG_SEED_SIZE
, &rng_seed
);
146 get_random_bytes(rng_seed
, RNG_SEED_SIZE
);
148 pr_notice("RNG is not initialised: omitting \"%s\" property\n",
154 return (ret
== -FDT_ERR_NOSPACE
) ? -ENOMEM
: -EINVAL
;
160 * More space needed so that we can add initrd, bootargs, kaslr-seed,
161 * rng-seed, userable-memory-range and elfcorehdr.
163 #define DTB_EXTRA_SPACE 0x1000
165 static int create_dtb(struct kimage
*image
,
166 unsigned long initrd_load_addr
, unsigned long initrd_len
,
167 char *cmdline
, void **dtb
)
174 cmdline_len
= cmdline
? strlen(cmdline
) : 0;
175 buf_size
= fdt_totalsize(initial_boot_params
)
176 + cmdline_len
+ DTB_EXTRA_SPACE
;
179 buf
= vmalloc(buf_size
);
183 /* duplicate a device tree blob */
184 ret
= fdt_open_into(initial_boot_params
, buf
, buf_size
);
188 ret
= setup_dtb(image
, initrd_load_addr
, initrd_len
,
192 if (ret
== -ENOMEM
) {
193 /* unlikely, but just in case */
194 buf_size
+= DTB_EXTRA_SPACE
;
209 static int prepare_elf_headers(void **addr
, unsigned long *sz
)
211 struct crash_mem
*cmem
;
212 unsigned int nr_ranges
;
215 phys_addr_t start
, end
;
217 nr_ranges
= 1; /* for exclusion of crashkernel region */
218 for_each_mem_range(i
, &start
, &end
)
221 cmem
= kmalloc(struct_size(cmem
, ranges
, nr_ranges
), GFP_KERNEL
);
225 cmem
->max_nr_ranges
= nr_ranges
;
227 for_each_mem_range(i
, &start
, &end
) {
228 cmem
->ranges
[cmem
->nr_ranges
].start
= start
;
229 cmem
->ranges
[cmem
->nr_ranges
].end
= end
- 1;
233 /* Exclude crashkernel region */
234 ret
= crash_exclude_mem_range(cmem
, crashk_res
.start
, crashk_res
.end
);
237 ret
= crash_prepare_elf64_headers(cmem
, true, addr
, sz
);
244 * Tries to add the initrd and DTB to the image. If it is not possible to find
245 * valid locations, this function will undo changes to the image and return non
248 int load_other_segments(struct kimage
*image
,
249 unsigned long kernel_load_addr
,
250 unsigned long kernel_size
,
251 char *initrd
, unsigned long initrd_len
,
254 struct kexec_buf kbuf
;
255 void *headers
, *dtb
= NULL
;
256 unsigned long headers_sz
, initrd_load_addr
= 0, dtb_len
,
257 orig_segments
= image
->nr_segments
;
261 /* not allocate anything below the kernel */
262 kbuf
.buf_min
= kernel_load_addr
+ kernel_size
;
264 /* load elf core header */
265 if (image
->type
== KEXEC_TYPE_CRASH
) {
266 ret
= prepare_elf_headers(&headers
, &headers_sz
);
268 pr_err("Preparing elf core header failed\n");
272 kbuf
.buffer
= headers
;
273 kbuf
.bufsz
= headers_sz
;
274 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
275 kbuf
.memsz
= headers_sz
;
276 kbuf
.buf_align
= SZ_64K
; /* largest supported page size */
277 kbuf
.buf_max
= ULONG_MAX
;
278 kbuf
.top_down
= true;
280 ret
= kexec_add_buffer(&kbuf
);
285 image
->arch
.elf_headers
= headers
;
286 image
->arch
.elf_headers_mem
= kbuf
.mem
;
287 image
->arch
.elf_headers_sz
= headers_sz
;
289 pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
290 image
->arch
.elf_headers_mem
, kbuf
.bufsz
, kbuf
.memsz
);
295 kbuf
.buffer
= initrd
;
296 kbuf
.bufsz
= initrd_len
;
297 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
298 kbuf
.memsz
= initrd_len
;
300 /* within 1GB-aligned window of up to 32GB in size */
301 kbuf
.buf_max
= round_down(kernel_load_addr
, SZ_1G
)
302 + (unsigned long)SZ_1G
* 32;
303 kbuf
.top_down
= false;
305 ret
= kexec_add_buffer(&kbuf
);
308 initrd_load_addr
= kbuf
.mem
;
310 pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
311 initrd_load_addr
, kbuf
.bufsz
, kbuf
.memsz
);
315 ret
= create_dtb(image
, initrd_load_addr
, initrd_len
, cmdline
, &dtb
);
317 pr_err("Preparing for new dtb failed\n");
321 dtb_len
= fdt_totalsize(dtb
);
323 kbuf
.bufsz
= dtb_len
;
324 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
325 kbuf
.memsz
= dtb_len
;
326 /* not across 2MB boundary */
327 kbuf
.buf_align
= SZ_2M
;
328 kbuf
.buf_max
= ULONG_MAX
;
329 kbuf
.top_down
= true;
331 ret
= kexec_add_buffer(&kbuf
);
334 image
->arch
.dtb
= dtb
;
335 image
->arch
.dtb_mem
= kbuf
.mem
;
337 pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
338 kbuf
.mem
, kbuf
.bufsz
, kbuf
.memsz
);
343 image
->nr_segments
= orig_segments
;