1 // SPDX-License-Identifier: GPL-2.0-only
3 * Load ELF vmlinux file for the kexec_file_load syscall.
5 * Copyright (C) 2004 Adam Litke (agl@us.ibm.com)
6 * Copyright (C) 2004 IBM Corp.
7 * Copyright (C) 2005 R Sharada (sharada@in.ibm.com)
8 * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.com)
9 * Copyright (C) 2016 IBM Corporation
11 * Based on kexec-tools' kexec-elf-exec.c and kexec-elf-ppc64.c.
12 * Heavily modified for the kernel by
13 * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>.
16 #define pr_fmt(fmt) "kexec_elf: " fmt
18 #include <linux/elf.h>
19 #include <linux/kexec.h>
20 #include <linux/libfdt.h>
21 #include <linux/module.h>
22 #include <linux/of_fdt.h>
23 #include <linux/slab.h>
24 #include <linux/types.h>
26 static void *elf64_load(struct kimage
*image
, char *kernel_buf
,
27 unsigned long kernel_len
, char *initrd
,
28 unsigned long initrd_len
, char *cmdline
,
29 unsigned long cmdline_len
)
32 unsigned int fdt_size
;
33 unsigned long kernel_load_addr
;
34 unsigned long initrd_load_addr
= 0, fdt_load_addr
;
36 const void *slave_code
;
38 char *modified_cmdline
= NULL
;
39 struct kexec_elf_info elf_info
;
40 struct kexec_buf kbuf
= { .image
= image
, .buf_min
= 0,
41 .buf_max
= ppc64_rma_size
};
42 struct kexec_buf pbuf
= { .image
= image
, .buf_min
= 0,
43 .buf_max
= ppc64_rma_size
, .top_down
= true,
44 .mem
= KEXEC_BUF_MEM_UNKNOWN
};
46 ret
= kexec_build_elf_info(kernel_buf
, kernel_len
, &ehdr
, &elf_info
);
50 if (image
->type
== KEXEC_TYPE_CRASH
) {
51 /* min & max buffer values for kdump case */
52 kbuf
.buf_min
= pbuf
.buf_min
= crashk_res
.start
;
53 kbuf
.buf_max
= pbuf
.buf_max
=
54 ((crashk_res
.end
< ppc64_rma_size
) ?
55 crashk_res
.end
: (ppc64_rma_size
- 1));
58 ret
= kexec_elf_load(image
, &ehdr
, &elf_info
, &kbuf
, &kernel_load_addr
);
62 pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr
);
64 ret
= kexec_load_purgatory(image
, &pbuf
);
66 pr_err("Loading purgatory failed.\n");
70 pr_debug("Loaded purgatory at 0x%lx\n", pbuf
.mem
);
72 /* Load additional segments needed for panic kernel */
73 if (image
->type
== KEXEC_TYPE_CRASH
) {
74 ret
= load_crashdump_segments_ppc64(image
, &kbuf
);
76 pr_err("Failed to load kdump kernel segments\n");
80 /* Setup cmdline for kdump kernel case */
81 modified_cmdline
= setup_kdump_cmdline(image
, cmdline
,
83 if (!modified_cmdline
) {
84 pr_err("Setting up cmdline for kdump kernel failed\n");
88 cmdline
= modified_cmdline
;
93 kbuf
.bufsz
= kbuf
.memsz
= initrd_len
;
94 kbuf
.buf_align
= PAGE_SIZE
;
95 kbuf
.top_down
= false;
96 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
97 ret
= kexec_add_buffer(&kbuf
);
100 initrd_load_addr
= kbuf
.mem
;
102 pr_debug("Loaded initrd at 0x%lx\n", initrd_load_addr
);
105 fdt_size
= fdt_totalsize(initial_boot_params
) * 2;
106 fdt
= kmalloc(fdt_size
, GFP_KERNEL
);
108 pr_err("Not enough memory for the device tree.\n");
112 ret
= fdt_open_into(initial_boot_params
, fdt
, fdt_size
);
114 pr_err("Error setting up the new device tree.\n");
119 ret
= setup_new_fdt_ppc64(image
, fdt
, initrd_load_addr
,
120 initrd_len
, cmdline
);
127 kbuf
.bufsz
= kbuf
.memsz
= fdt_size
;
128 kbuf
.buf_align
= PAGE_SIZE
;
129 kbuf
.top_down
= true;
130 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
131 ret
= kexec_add_buffer(&kbuf
);
134 fdt_load_addr
= kbuf
.mem
;
136 pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr
);
138 slave_code
= elf_info
.buffer
+ elf_info
.proghdrs
[0].p_offset
;
139 ret
= setup_purgatory_ppc64(image
, slave_code
, fdt
, kernel_load_addr
,
142 pr_err("Error setting up the purgatory.\n");
145 kfree(modified_cmdline
);
146 kexec_free_elf_info(&elf_info
);
148 /* Make kimage_file_post_load_cleanup free the fdt buffer for us. */
149 return ret
? ERR_PTR(ret
) : fdt
;
152 const struct kexec_file_ops kexec_elf64_ops
= {
153 .probe
= kexec_elf_probe
,