1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Load ELF vmlinux file for the kexec_file_load syscall. |
4 | * |
5 | * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org> |
6 | * |
7 | */ |
8 | #include <linux/elf.h> |
9 | #include <linux/kexec.h> |
10 | #include <linux/libfdt.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of_fdt.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/types.h> |
15 | |
16 | static void *elf_load(struct kimage *image, char *kernel_buf, |
17 | unsigned long kernel_len, char *initrd, |
18 | unsigned long initrd_len, char *cmdline, |
19 | unsigned long cmdline_len) |
20 | { |
21 | int ret, i; |
22 | unsigned long kernel_load_addr; |
23 | struct elfhdr ehdr; |
24 | struct kexec_elf_info elf_info; |
25 | struct kexec_buf kbuf = { .image = image, .buf_min = 0, |
26 | .buf_max = -1UL, }; |
27 | |
28 | ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); |
29 | if (ret) |
30 | goto out; |
31 | |
32 | ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr); |
33 | if (ret) |
34 | goto out; |
35 | |
36 | image->start = __pa(elf_info.ehdr->e_entry); |
37 | |
38 | for (i = 0; i < image->nr_segments; i++) |
39 | image->segment[i].mem = __pa(image->segment[i].mem); |
40 | |
41 | kexec_dprintk("Loaded the kernel at 0x%lx, entry at 0x%lx\n" , |
42 | kernel_load_addr, image->start); |
43 | |
44 | if (initrd != NULL) { |
45 | kbuf.buffer = initrd; |
46 | kbuf.bufsz = kbuf.memsz = initrd_len; |
47 | kbuf.buf_align = PAGE_SIZE; |
48 | kbuf.top_down = false; |
49 | kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; |
50 | ret = kexec_add_buffer(kbuf: &kbuf); |
51 | if (ret) |
52 | goto out; |
53 | |
54 | kexec_dprintk("Loaded initrd at 0x%lx\n" , kbuf.mem); |
55 | image->arch.initrd_start = kbuf.mem; |
56 | image->arch.initrd_end = kbuf.mem + initrd_len; |
57 | } |
58 | |
59 | if (cmdline != NULL) { |
60 | kbuf.buffer = cmdline; |
61 | kbuf.bufsz = kbuf.memsz = ALIGN(cmdline_len, 8); |
62 | kbuf.buf_align = PAGE_SIZE; |
63 | kbuf.top_down = false; |
64 | kbuf.buf_min = PAGE0->mem_free + PAGE_SIZE; |
65 | kbuf.buf_max = kernel_load_addr; |
66 | kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; |
67 | ret = kexec_add_buffer(kbuf: &kbuf); |
68 | if (ret) |
69 | goto out; |
70 | |
71 | kexec_dprintk("Loaded cmdline at 0x%lx\n" , kbuf.mem); |
72 | image->arch.cmdline = kbuf.mem; |
73 | } |
74 | out: |
75 | return NULL; |
76 | } |
77 | |
78 | const struct kexec_file_ops kexec_elf_ops = { |
79 | .probe = kexec_elf_probe, |
80 | .load = elf_load, |
81 | }; |
82 | |
83 | const struct kexec_file_ops * const kexec_file_loaders[] = { |
84 | &kexec_elf_ops, |
85 | NULL |
86 | }; |
87 | |