History

x86/kexec: carry forward the boot DTB on kexec

Currently, the kexec_file_load syscall on x86 does not support passing a device tree blob to the new kernel. Some embedded x86 systems use device trees. On these systems, failing to pass a device tree to the new kernel causes a boot failure. To add support for this, we copy the behavior of ARM64 and PowerPC and copy the current boot's device tree blob for use in the new kernel. We do this on x86 by passing the device tree blob as a setup_data entry in accordance with the x86 boot protocol. This behavior is gated behind the KEXEC_FILE_FORCE_DTB flag.

Brian Mak committed 1 year ago

Commit f3674741 parent 14406484 files · +53 −4Browse files

Unified · Split

4 files
  1. arch/x86/kernel/kexec-bzimage64.c +44 −3
  2. include/linux/kexec.h +4 −1
  3. include/uapi/linux/kexec.h +4 −0
  4. kernel/kexec_file.c +1 −0
arch/x86/kernel/kexec-bzimage64.c+44−3
@@ -16,6 +16,8 @@ · 15 unmodified lines
16#include <linux/kexec.h>16#include <linux/kexec.h>
17#include <linux/kernel.h>17#include <linux/kernel.h>
18#include <linux/mm.h>18#include <linux/mm.h>
19#include <linux/libfdt.h>
20#include <linux/of_fdt.h>
19#include <linux/efi.h>21#include <linux/efi.h>
20#include <linux/random.h>22#include <linux/random.h>
21 23
@@ -212,6 +214,28 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr, · 190 unmodified lines
212}214}
213#endif /* CONFIG_EFI */215#endif /* CONFIG_EFI */
214 216
217#ifdef CONFIG_OF_FLATTREE
218static void setup_dtb(struct boot_params *params,
219 unsigned long params_load_addr,
220 unsigned int dtb_setup_data_offset)
221{
222 struct setup_data *sd = (void *)params + dtb_setup_data_offset;
223 unsigned long setup_data_phys, dtb_len;
224
225 dtb_len = fdt_totalsize(initial_boot_params);
226 sd->type = SETUP_DTB;
227 sd->len = dtb_len;
228
229 /* Carry over current boot DTB with setup_data */
230 memcpy(sd->data, initial_boot_params, dtb_len);
231
232 /* Add setup data */
233 setup_data_phys = params_load_addr + dtb_setup_data_offset;
234 sd->next = params->hdr.setup_data;
235 params->hdr.setup_data = setup_data_phys;
236}
237#endif /* CONFIG_OF_FLATTREE */
238
215static void239static void
216setup_ima_state(const struct kimage *image, struct boot_params *params,240setup_ima_state(const struct kimage *image, struct boot_params *params,
217 unsigned long params_load_addr,241 unsigned long params_load_addr,
@@ -336,6 +360,17 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, · 118 unmodified lines
336 sizeof(struct efi_setup_data);360 sizeof(struct efi_setup_data);
337#endif361#endif
338 362
363#ifdef CONFIG_OF_FLATTREE
364 if (image->force_dtb && initial_boot_params) {
365 setup_dtb(params, params_load_addr, setup_data_offset);
366 setup_data_offset += sizeof(struct setup_data) +
367 fdt_totalsize(initial_boot_params);
368 } else {
369 pr_debug("Not carrying over DTB, force_dtb = %d\n",
370 image->force_dtb);
371 }
372#endif
373
339 if (IS_ENABLED(CONFIG_IMA_KEXEC)) {374 if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
340 /* Setup IMA log buffer state */375 /* Setup IMA log buffer state */
341 setup_ima_state(image, params, params_load_addr,376 setup_ima_state(image, params, params_load_addr,
@@ -529,6 +564,12 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 187 unmodified lines
529 sizeof(struct setup_data) +564 sizeof(struct setup_data) +
530 RNG_SEED_LENGTH;565 RNG_SEED_LENGTH;
531 566
567#ifdef CONFIG_OF_FLATTREE
568 if (image->force_dtb && initial_boot_params)
569 kbuf.bufsz += sizeof(struct setup_data) +
570 fdt_totalsize(initial_boot_params);
571#endif
572
532 if (IS_ENABLED(CONFIG_IMA_KEXEC))573 if (IS_ENABLED(CONFIG_IMA_KEXEC))
533 kbuf.bufsz += sizeof(struct setup_data) +574 kbuf.bufsz += sizeof(struct setup_data) +
534 sizeof(struct ima_setup_data);575 sizeof(struct ima_setup_data);
@@ -537,7 +578,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 2 unmodified lines
537 kbuf.bufsz += sizeof(struct setup_data) +578 kbuf.bufsz += sizeof(struct setup_data) +
538 sizeof(struct kho_data);579 sizeof(struct kho_data);
539 580
540 params = kzalloc(kbuf.bufsz, GFP_KERNEL);581 params = kvzalloc(kbuf.bufsz, GFP_KERNEL);
541 if (!params)582 if (!params)
542 return ERR_PTR(-ENOMEM);583 return ERR_PTR(-ENOMEM);
543 efi_map_offset = params_cmdline_sz;584 efi_map_offset = params_cmdline_sz;
@@ -647,7 +688,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 103 unmodified lines
647 return ldata;688 return ldata;
648 689
649out_free_params:690out_free_params:
650 kfree(params);691 kvfree(params);
651 return ERR_PTR(ret);692 return ERR_PTR(ret);
652}693}
653 694
@@ -659,7 +700,7 @@ static int bzImage64_cleanup(void *loader_data) · 5 unmodified lines
659 if (!ldata)700 if (!ldata)
660 return 0;701 return 0;
661 702
662 kfree(ldata->bootparams_buf);703 kvfree(ldata->bootparams_buf);
663 ldata->bootparams_buf = NULL;704 ldata->bootparams_buf = NULL;
664 705
665 return 0;706 return 0;
include/linux/kexec.h+4−1
@@ -395,6 +395,9 @@ struct kimage { · 394 unmodified lines
395 395
396 /* Information for loading purgatory */396 /* Information for loading purgatory */
397 struct purgatory_info purgatory_info;397 struct purgatory_info purgatory_info;
398
399 /* Force carrying over the DTB from the current boot */
400 bool force_dtb;
398#endif401#endif
399 402
400#ifdef CONFIG_CRASH_HOTPLUG403#ifdef CONFIG_CRASH_HOTPLUG
@@ -461,7 +464,7 @@ bool kexec_load_permitted(int kexec_image_type); · 60 unmodified lines
461/* List of defined/legal kexec file flags */464/* List of defined/legal kexec file flags */
462#define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \465#define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \
463 KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG | \466 KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG | \
464 KEXEC_FILE_NO_CMA)467 KEXEC_FILE_NO_CMA | KEXEC_FILE_FORCE_DTB)
465 468
466/* flag to track if kexec reboot is in progress */469/* flag to track if kexec reboot is in progress */
467extern bool kexec_in_progress;470extern bool kexec_in_progress;
include/uapi/linux/kexec.h+4−0
@@ -22,12 +22,16 @@ · 21 unmodified lines
22 * KEXEC_FILE_ON_CRASH : Load/unload operation belongs to kdump image.22 * KEXEC_FILE_ON_CRASH : Load/unload operation belongs to kdump image.
23 * KEXEC_FILE_NO_INITRAMFS : No initramfs is being loaded. Ignore the initrd23 * KEXEC_FILE_NO_INITRAMFS : No initramfs is being loaded. Ignore the initrd
24 * fd field.24 * fd field.
25 * KEXEC_FILE_FORCE_DTB : Force carrying over the current boot's DTB to the new
26 * kernel on x86. This is already the default behavior on
27 * some other architectures, like ARM64 and PowerPC.
25 */28 */
26#define KEXEC_FILE_UNLOAD 0x0000000129#define KEXEC_FILE_UNLOAD 0x00000001
27#define KEXEC_FILE_ON_CRASH 0x0000000230#define KEXEC_FILE_ON_CRASH 0x00000002
28#define KEXEC_FILE_NO_INITRAMFS 0x0000000431#define KEXEC_FILE_NO_INITRAMFS 0x00000004
29#define KEXEC_FILE_DEBUG 0x0000000832#define KEXEC_FILE_DEBUG 0x00000008
30#define KEXEC_FILE_NO_CMA 0x0000001033#define KEXEC_FILE_NO_CMA 0x00000010
34#define KEXEC_FILE_FORCE_DTB 0x00000020
31 35
32/* These values match the ELF architecture values.36/* These values match the ELF architecture values.
33 * Unless there is a good reason that should continue to be the case.37 * Unless there is a good reason that should continue to be the case.
kernel/kexec_file.c+1−0
@@ -255,6 +255,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, · 254 unmodified lines
255 }255 }
256 256
257 image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);257 image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);
258 image->force_dtb = flags & KEXEC_FILE_FORCE_DTB;
258 259
259 if (cmdline_len) {260 if (cmdline_len) {
260 image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);261 image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);