1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Kexec bzImage loader |
4 | * |
5 | * Copyright (C) 2014 Red Hat Inc. |
6 | * Authors: |
7 | * Vivek Goyal <vgoyal@redhat.com> |
8 | */ |
9 | |
10 | #define pr_fmt(fmt) "kexec-bzImage64: " fmt |
11 | |
12 | #include <linux/string.h> |
13 | #include <linux/printk.h> |
14 | #include <linux/errno.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/kexec.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/mm.h> |
19 | #include <linux/efi.h> |
20 | #include <linux/random.h> |
21 | |
22 | #include <asm/bootparam.h> |
23 | #include <asm/setup.h> |
24 | #include <asm/crash.h> |
25 | #include <asm/efi.h> |
26 | #include <asm/e820/api.h> |
27 | #include <asm/kexec-bzimage64.h> |
28 | |
29 | #define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */ |
30 | |
31 | /* |
32 | * Defines lowest physical address for various segments. Not sure where |
33 | * exactly these limits came from. Current bzimage64 loader in kexec-tools |
34 | * uses these so I am retaining it. It can be changed over time as we gain |
35 | * more insight. |
36 | */ |
37 | #define MIN_PURGATORY_ADDR 0x3000 |
38 | #define MIN_BOOTPARAM_ADDR 0x3000 |
39 | #define MIN_KERNEL_LOAD_ADDR 0x100000 |
40 | #define MIN_INITRD_LOAD_ADDR 0x1000000 |
41 | |
42 | /* |
43 | * This is a place holder for all boot loader specific data structure which |
44 | * gets allocated in one call but gets freed much later during cleanup |
45 | * time. Right now there is only one field but it can grow as need be. |
46 | */ |
47 | struct bzimage64_data { |
48 | /* |
49 | * Temporary buffer to hold bootparams buffer. This should be |
50 | * freed once the bootparam segment has been loaded. |
51 | */ |
52 | void *bootparams_buf; |
53 | }; |
54 | |
55 | static int setup_initrd(struct boot_params *params, |
56 | unsigned long initrd_load_addr, unsigned long initrd_len) |
57 | { |
58 | params->hdr.ramdisk_image = initrd_load_addr & 0xffffffffUL; |
59 | params->hdr.ramdisk_size = initrd_len & 0xffffffffUL; |
60 | |
61 | params->ext_ramdisk_image = initrd_load_addr >> 32; |
62 | params->ext_ramdisk_size = initrd_len >> 32; |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | static int setup_cmdline(struct kimage *image, struct boot_params *params, |
68 | unsigned long bootparams_load_addr, |
69 | unsigned long cmdline_offset, char *cmdline, |
70 | unsigned long cmdline_len) |
71 | { |
72 | char *cmdline_ptr = ((char *)params) + cmdline_offset; |
73 | unsigned long cmdline_ptr_phys, len = 0; |
74 | uint32_t cmdline_low_32, cmdline_ext_32; |
75 | |
76 | if (image->type == KEXEC_TYPE_CRASH) { |
77 | len = sprintf(buf: cmdline_ptr, |
78 | fmt: "elfcorehdr=0x%lx " , image->elf_load_addr); |
79 | } |
80 | memcpy(cmdline_ptr + len, cmdline, cmdline_len); |
81 | cmdline_len += len; |
82 | |
83 | cmdline_ptr[cmdline_len - 1] = '\0'; |
84 | |
85 | pr_debug("Final command line is: %s\n" , cmdline_ptr); |
86 | cmdline_ptr_phys = bootparams_load_addr + cmdline_offset; |
87 | cmdline_low_32 = cmdline_ptr_phys & 0xffffffffUL; |
88 | cmdline_ext_32 = cmdline_ptr_phys >> 32; |
89 | |
90 | params->hdr.cmd_line_ptr = cmdline_low_32; |
91 | if (cmdline_ext_32) |
92 | params->ext_cmd_line_ptr = cmdline_ext_32; |
93 | |
94 | return 0; |
95 | } |
96 | |
97 | static int setup_e820_entries(struct boot_params *params) |
98 | { |
99 | unsigned int nr_e820_entries; |
100 | |
101 | nr_e820_entries = e820_table_kexec->nr_entries; |
102 | |
103 | /* TODO: Pass entries more than E820_MAX_ENTRIES_ZEROPAGE in bootparams setup data */ |
104 | if (nr_e820_entries > E820_MAX_ENTRIES_ZEROPAGE) |
105 | nr_e820_entries = E820_MAX_ENTRIES_ZEROPAGE; |
106 | |
107 | params->e820_entries = nr_e820_entries; |
108 | memcpy(¶ms->e820_table, &e820_table_kexec->entries, nr_e820_entries*sizeof(struct e820_entry)); |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | enum { RNG_SEED_LENGTH = 32 }; |
114 | |
115 | static void |
116 | setup_rng_seed(struct boot_params *params, unsigned long params_load_addr, |
117 | unsigned int rng_seed_setup_data_offset) |
118 | { |
119 | struct setup_data *sd = (void *)params + rng_seed_setup_data_offset; |
120 | unsigned long setup_data_phys; |
121 | |
122 | if (!rng_is_initialized()) |
123 | return; |
124 | |
125 | sd->type = SETUP_RNG_SEED; |
126 | sd->len = RNG_SEED_LENGTH; |
127 | get_random_bytes(buf: sd->data, len: RNG_SEED_LENGTH); |
128 | setup_data_phys = params_load_addr + rng_seed_setup_data_offset; |
129 | sd->next = params->hdr.setup_data; |
130 | params->hdr.setup_data = setup_data_phys; |
131 | } |
132 | |
133 | #ifdef CONFIG_EFI |
134 | static int setup_efi_info_memmap(struct boot_params *params, |
135 | unsigned long params_load_addr, |
136 | unsigned int efi_map_offset, |
137 | unsigned int efi_map_sz) |
138 | { |
139 | void *efi_map = (void *)params + efi_map_offset; |
140 | unsigned long efi_map_phys_addr = params_load_addr + efi_map_offset; |
141 | struct efi_info *ei = ¶ms->efi_info; |
142 | |
143 | if (!efi_map_sz) |
144 | return 0; |
145 | |
146 | efi_runtime_map_copy(buf: efi_map, bufsz: efi_map_sz); |
147 | |
148 | ei->efi_memmap = efi_map_phys_addr & 0xffffffff; |
149 | ei->efi_memmap_hi = efi_map_phys_addr >> 32; |
150 | ei->efi_memmap_size = efi_map_sz; |
151 | |
152 | return 0; |
153 | } |
154 | |
155 | static int |
156 | prepare_add_efi_setup_data(struct boot_params *params, |
157 | unsigned long params_load_addr, |
158 | unsigned int efi_setup_data_offset) |
159 | { |
160 | unsigned long setup_data_phys; |
161 | struct setup_data *sd = (void *)params + efi_setup_data_offset; |
162 | struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data); |
163 | |
164 | esd->fw_vendor = efi_fw_vendor; |
165 | esd->tables = efi_config_table; |
166 | esd->smbios = efi.smbios; |
167 | |
168 | sd->type = SETUP_EFI; |
169 | sd->len = sizeof(struct efi_setup_data); |
170 | |
171 | /* Add setup data */ |
172 | setup_data_phys = params_load_addr + efi_setup_data_offset; |
173 | sd->next = params->hdr.setup_data; |
174 | params->hdr.setup_data = setup_data_phys; |
175 | |
176 | return 0; |
177 | } |
178 | |
179 | static int |
180 | setup_efi_state(struct boot_params *params, unsigned long params_load_addr, |
181 | unsigned int efi_map_offset, unsigned int efi_map_sz, |
182 | unsigned int efi_setup_data_offset) |
183 | { |
184 | struct efi_info *current_ei = &boot_params.efi_info; |
185 | struct efi_info *ei = ¶ms->efi_info; |
186 | |
187 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) |
188 | return 0; |
189 | |
190 | if (!current_ei->efi_memmap_size) |
191 | return 0; |
192 | |
193 | params->secure_boot = boot_params.secure_boot; |
194 | ei->efi_loader_signature = current_ei->efi_loader_signature; |
195 | ei->efi_systab = current_ei->efi_systab; |
196 | ei->efi_systab_hi = current_ei->efi_systab_hi; |
197 | |
198 | ei->efi_memdesc_version = current_ei->efi_memdesc_version; |
199 | ei->efi_memdesc_size = efi_get_runtime_map_desc_size(); |
200 | |
201 | setup_efi_info_memmap(params, params_load_addr, efi_map_offset, |
202 | efi_map_sz); |
203 | prepare_add_efi_setup_data(params, params_load_addr, |
204 | efi_setup_data_offset); |
205 | return 0; |
206 | } |
207 | #endif /* CONFIG_EFI */ |
208 | |
209 | static void |
210 | setup_ima_state(const struct kimage *image, struct boot_params *params, |
211 | unsigned long params_load_addr, |
212 | unsigned int ima_setup_data_offset) |
213 | { |
214 | #ifdef CONFIG_IMA_KEXEC |
215 | struct setup_data *sd = (void *)params + ima_setup_data_offset; |
216 | unsigned long setup_data_phys; |
217 | struct ima_setup_data *ima; |
218 | |
219 | if (!image->ima_buffer_size) |
220 | return; |
221 | |
222 | sd->type = SETUP_IMA; |
223 | sd->len = sizeof(*ima); |
224 | |
225 | ima = (void *)sd + sizeof(struct setup_data); |
226 | ima->addr = image->ima_buffer_addr; |
227 | ima->size = image->ima_buffer_size; |
228 | |
229 | /* Add setup data */ |
230 | setup_data_phys = params_load_addr + ima_setup_data_offset; |
231 | sd->next = params->hdr.setup_data; |
232 | params->hdr.setup_data = setup_data_phys; |
233 | #endif /* CONFIG_IMA_KEXEC */ |
234 | } |
235 | |
236 | static int |
237 | setup_boot_parameters(struct kimage *image, struct boot_params *params, |
238 | unsigned long params_load_addr, |
239 | unsigned int efi_map_offset, unsigned int efi_map_sz, |
240 | unsigned int setup_data_offset) |
241 | { |
242 | unsigned int nr_e820_entries; |
243 | unsigned long long mem_k, start, end; |
244 | int i, ret = 0; |
245 | |
246 | /* Get subarch from existing bootparams */ |
247 | params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch; |
248 | |
249 | /* Copying screen_info will do? */ |
250 | memcpy(¶ms->screen_info, &screen_info, sizeof(struct screen_info)); |
251 | |
252 | /* Fill in memsize later */ |
253 | params->screen_info.ext_mem_k = 0; |
254 | params->alt_mem_k = 0; |
255 | |
256 | /* Always fill in RSDP: it is either 0 or a valid value */ |
257 | params->acpi_rsdp_addr = boot_params.acpi_rsdp_addr; |
258 | |
259 | /* Default APM info */ |
260 | memset(¶ms->apm_bios_info, 0, sizeof(params->apm_bios_info)); |
261 | |
262 | /* Default drive info */ |
263 | memset(¶ms->hd0_info, 0, sizeof(params->hd0_info)); |
264 | memset(¶ms->hd1_info, 0, sizeof(params->hd1_info)); |
265 | |
266 | if (image->type == KEXEC_TYPE_CRASH) { |
267 | ret = crash_setup_memmap_entries(image, params); |
268 | if (ret) |
269 | return ret; |
270 | } else |
271 | setup_e820_entries(params); |
272 | |
273 | nr_e820_entries = params->e820_entries; |
274 | |
275 | for (i = 0; i < nr_e820_entries; i++) { |
276 | if (params->e820_table[i].type != E820_TYPE_RAM) |
277 | continue; |
278 | start = params->e820_table[i].addr; |
279 | end = params->e820_table[i].addr + params->e820_table[i].size - 1; |
280 | |
281 | if ((start <= 0x100000) && end > 0x100000) { |
282 | mem_k = (end >> 10) - (0x100000 >> 10); |
283 | params->screen_info.ext_mem_k = mem_k; |
284 | params->alt_mem_k = mem_k; |
285 | if (mem_k > 0xfc00) |
286 | params->screen_info.ext_mem_k = 0xfc00; /* 64M*/ |
287 | if (mem_k > 0xffffffff) |
288 | params->alt_mem_k = 0xffffffff; |
289 | } |
290 | } |
291 | |
292 | #ifdef CONFIG_EFI |
293 | /* Setup EFI state */ |
294 | setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz, |
295 | efi_setup_data_offset: setup_data_offset); |
296 | setup_data_offset += sizeof(struct setup_data) + |
297 | sizeof(struct efi_setup_data); |
298 | #endif |
299 | |
300 | if (IS_ENABLED(CONFIG_IMA_KEXEC)) { |
301 | /* Setup IMA log buffer state */ |
302 | setup_ima_state(image, params, params_load_addr, |
303 | ima_setup_data_offset: setup_data_offset); |
304 | setup_data_offset += sizeof(struct setup_data) + |
305 | sizeof(struct ima_setup_data); |
306 | } |
307 | |
308 | /* Setup RNG seed */ |
309 | setup_rng_seed(params, params_load_addr, rng_seed_setup_data_offset: setup_data_offset); |
310 | |
311 | /* Setup EDD info */ |
312 | memcpy(params->eddbuf, boot_params.eddbuf, |
313 | EDDMAXNR * sizeof(struct edd_info)); |
314 | params->eddbuf_entries = boot_params.eddbuf_entries; |
315 | |
316 | memcpy(params->edd_mbr_sig_buffer, boot_params.edd_mbr_sig_buffer, |
317 | EDD_MBR_SIG_MAX * sizeof(unsigned int)); |
318 | |
319 | return ret; |
320 | } |
321 | |
322 | static int bzImage64_probe(const char *buf, unsigned long len) |
323 | { |
324 | int ret = -ENOEXEC; |
325 | struct setup_header *; |
326 | |
327 | /* kernel should be at least two sectors long */ |
328 | if (len < 2 * 512) { |
329 | pr_err("File is too short to be a bzImage\n" ); |
330 | return ret; |
331 | } |
332 | |
333 | header = (struct setup_header *)(buf + offsetof(struct boot_params, hdr)); |
334 | if (memcmp(p: (char *)&header->header, q: "HdrS" , size: 4) != 0) { |
335 | pr_err("Not a bzImage\n" ); |
336 | return ret; |
337 | } |
338 | |
339 | if (header->boot_flag != 0xAA55) { |
340 | pr_err("No x86 boot sector present\n" ); |
341 | return ret; |
342 | } |
343 | |
344 | if (header->version < 0x020C) { |
345 | pr_err("Must be at least protocol version 2.12\n" ); |
346 | return ret; |
347 | } |
348 | |
349 | if (!(header->loadflags & LOADED_HIGH)) { |
350 | pr_err("zImage not a bzImage\n" ); |
351 | return ret; |
352 | } |
353 | |
354 | if (!(header->xloadflags & XLF_KERNEL_64)) { |
355 | pr_err("Not a bzImage64. XLF_KERNEL_64 is not set.\n" ); |
356 | return ret; |
357 | } |
358 | |
359 | if (!(header->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G)) { |
360 | pr_err("XLF_CAN_BE_LOADED_ABOVE_4G is not set.\n" ); |
361 | return ret; |
362 | } |
363 | |
364 | /* |
365 | * Can't handle 32bit EFI as it does not allow loading kernel |
366 | * above 4G. This should be handled by 32bit bzImage loader |
367 | */ |
368 | if (efi_enabled(EFI_RUNTIME_SERVICES) && !efi_enabled(EFI_64BIT)) { |
369 | pr_debug("EFI is 32 bit. Can't load kernel above 4G.\n" ); |
370 | return ret; |
371 | } |
372 | |
373 | if (!(header->xloadflags & XLF_5LEVEL) && pgtable_l5_enabled()) { |
374 | pr_err("bzImage cannot handle 5-level paging mode.\n" ); |
375 | return ret; |
376 | } |
377 | |
378 | /* I've got a bzImage */ |
379 | pr_debug("It's a relocatable bzImage64\n" ); |
380 | ret = 0; |
381 | |
382 | return ret; |
383 | } |
384 | |
385 | static void *bzImage64_load(struct kimage *image, char *kernel, |
386 | unsigned long kernel_len, char *initrd, |
387 | unsigned long initrd_len, char *cmdline, |
388 | unsigned long cmdline_len) |
389 | { |
390 | |
391 | struct setup_header *; |
392 | int setup_sects, kern16_size, ret = 0; |
393 | unsigned long , params_cmdline_sz; |
394 | struct boot_params *params; |
395 | unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr; |
396 | struct bzimage64_data *ldata; |
397 | struct kexec_entry64_regs regs64; |
398 | void *stack; |
399 | unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr); |
400 | unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset; |
401 | struct kexec_buf kbuf = { .image = image, .buf_max = ULONG_MAX, |
402 | .top_down = true }; |
403 | struct kexec_buf pbuf = { .image = image, .buf_min = MIN_PURGATORY_ADDR, |
404 | .buf_max = ULONG_MAX, .top_down = true }; |
405 | |
406 | header = (struct setup_header *)(kernel + setup_hdr_offset); |
407 | setup_sects = header->setup_sects; |
408 | if (setup_sects == 0) |
409 | setup_sects = 4; |
410 | |
411 | kern16_size = (setup_sects + 1) * 512; |
412 | if (kernel_len < kern16_size) { |
413 | pr_err("bzImage truncated\n" ); |
414 | return ERR_PTR(error: -ENOEXEC); |
415 | } |
416 | |
417 | if (cmdline_len > header->cmdline_size) { |
418 | pr_err("Kernel command line too long\n" ); |
419 | return ERR_PTR(error: -EINVAL); |
420 | } |
421 | |
422 | /* |
423 | * In case of crash dump, we will append elfcorehdr=<addr> to |
424 | * command line. Make sure it does not overflow |
425 | */ |
426 | if (cmdline_len + MAX_ELFCOREHDR_STR_LEN > header->cmdline_size) { |
427 | pr_debug("Appending elfcorehdr=<addr> to command line exceeds maximum allowed length\n" ); |
428 | return ERR_PTR(error: -EINVAL); |
429 | } |
430 | |
431 | /* Allocate and load backup region */ |
432 | if (image->type == KEXEC_TYPE_CRASH) { |
433 | ret = crash_load_segments(image); |
434 | if (ret) |
435 | return ERR_PTR(error: ret); |
436 | } |
437 | |
438 | /* |
439 | * Load purgatory. For 64bit entry point, purgatory code can be |
440 | * anywhere. |
441 | */ |
442 | ret = kexec_load_purgatory(image, kbuf: &pbuf); |
443 | if (ret) { |
444 | pr_err("Loading purgatory failed\n" ); |
445 | return ERR_PTR(error: ret); |
446 | } |
447 | |
448 | pr_debug("Loaded purgatory at 0x%lx\n" , pbuf.mem); |
449 | |
450 | |
451 | /* |
452 | * Load Bootparams and cmdline and space for efi stuff. |
453 | * |
454 | * Allocate memory together for multiple data structures so |
455 | * that they all can go in single area/segment and we don't |
456 | * have to create separate segment for each. Keeps things |
457 | * little bit simple |
458 | */ |
459 | efi_map_sz = efi_get_runtime_map_size(); |
460 | params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + |
461 | MAX_ELFCOREHDR_STR_LEN; |
462 | params_cmdline_sz = ALIGN(params_cmdline_sz, 16); |
463 | kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) + |
464 | sizeof(struct setup_data) + |
465 | sizeof(struct efi_setup_data) + |
466 | sizeof(struct setup_data) + |
467 | RNG_SEED_LENGTH; |
468 | |
469 | if (IS_ENABLED(CONFIG_IMA_KEXEC)) |
470 | kbuf.bufsz += sizeof(struct setup_data) + |
471 | sizeof(struct ima_setup_data); |
472 | |
473 | params = kzalloc(size: kbuf.bufsz, GFP_KERNEL); |
474 | if (!params) |
475 | return ERR_PTR(error: -ENOMEM); |
476 | efi_map_offset = params_cmdline_sz; |
477 | efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16); |
478 | |
479 | /* Copy setup header onto bootparams. Documentation/arch/x86/boot.rst */ |
480 | setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset; |
481 | |
482 | /* Is there a limit on setup header size? */ |
483 | memcpy(¶ms->hdr, (kernel + setup_hdr_offset), setup_header_size); |
484 | |
485 | kbuf.buffer = params; |
486 | kbuf.memsz = kbuf.bufsz; |
487 | kbuf.buf_align = 16; |
488 | kbuf.buf_min = MIN_BOOTPARAM_ADDR; |
489 | ret = kexec_add_buffer(kbuf: &kbuf); |
490 | if (ret) |
491 | goto out_free_params; |
492 | bootparam_load_addr = kbuf.mem; |
493 | pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , |
494 | bootparam_load_addr, kbuf.bufsz, kbuf.bufsz); |
495 | |
496 | /* Load kernel */ |
497 | kbuf.buffer = kernel + kern16_size; |
498 | kbuf.bufsz = kernel_len - kern16_size; |
499 | kbuf.memsz = PAGE_ALIGN(header->init_size); |
500 | kbuf.buf_align = header->kernel_alignment; |
501 | kbuf.buf_min = MIN_KERNEL_LOAD_ADDR; |
502 | kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; |
503 | ret = kexec_add_buffer(kbuf: &kbuf); |
504 | if (ret) |
505 | goto out_free_params; |
506 | kernel_load_addr = kbuf.mem; |
507 | |
508 | pr_debug("Loaded 64bit kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , |
509 | kernel_load_addr, kbuf.bufsz, kbuf.memsz); |
510 | |
511 | /* Load initrd high */ |
512 | if (initrd) { |
513 | kbuf.buffer = initrd; |
514 | kbuf.bufsz = kbuf.memsz = initrd_len; |
515 | kbuf.buf_align = PAGE_SIZE; |
516 | kbuf.buf_min = MIN_INITRD_LOAD_ADDR; |
517 | kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; |
518 | ret = kexec_add_buffer(kbuf: &kbuf); |
519 | if (ret) |
520 | goto out_free_params; |
521 | initrd_load_addr = kbuf.mem; |
522 | |
523 | pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , |
524 | initrd_load_addr, initrd_len, initrd_len); |
525 | |
526 | setup_initrd(params, initrd_load_addr, initrd_len); |
527 | } |
528 | |
529 | setup_cmdline(image, params, bootparams_load_addr: bootparam_load_addr, |
530 | cmdline_offset: sizeof(struct boot_params), cmdline, cmdline_len); |
531 | |
532 | /* bootloader info. Do we need a separate ID for kexec kernel loader? */ |
533 | params->hdr.type_of_loader = 0x0D << 4; |
534 | params->hdr.loadflags = 0; |
535 | |
536 | /* Setup purgatory regs for entry */ |
537 | ret = kexec_purgatory_get_set_symbol(image, name: "entry64_regs" , buf: ®s64, |
538 | size: sizeof(regs64), get_value: 1); |
539 | if (ret) |
540 | goto out_free_params; |
541 | |
542 | regs64.rbx = 0; /* Bootstrap Processor */ |
543 | regs64.rsi = bootparam_load_addr; |
544 | regs64.rip = kernel_load_addr + 0x200; |
545 | stack = kexec_purgatory_get_symbol_addr(image, name: "stack_end" ); |
546 | if (IS_ERR(ptr: stack)) { |
547 | pr_err("Could not find address of symbol stack_end\n" ); |
548 | ret = -EINVAL; |
549 | goto out_free_params; |
550 | } |
551 | |
552 | regs64.rsp = (unsigned long)stack; |
553 | ret = kexec_purgatory_get_set_symbol(image, name: "entry64_regs" , buf: ®s64, |
554 | size: sizeof(regs64), get_value: 0); |
555 | if (ret) |
556 | goto out_free_params; |
557 | |
558 | ret = setup_boot_parameters(image, params, params_load_addr: bootparam_load_addr, |
559 | efi_map_offset, efi_map_sz, |
560 | setup_data_offset: efi_setup_data_offset); |
561 | if (ret) |
562 | goto out_free_params; |
563 | |
564 | /* Allocate loader specific data */ |
565 | ldata = kzalloc(size: sizeof(struct bzimage64_data), GFP_KERNEL); |
566 | if (!ldata) { |
567 | ret = -ENOMEM; |
568 | goto out_free_params; |
569 | } |
570 | |
571 | /* |
572 | * Store pointer to params so that it could be freed after loading |
573 | * params segment has been loaded and contents have been copied |
574 | * somewhere else. |
575 | */ |
576 | ldata->bootparams_buf = params; |
577 | return ldata; |
578 | |
579 | out_free_params: |
580 | kfree(objp: params); |
581 | return ERR_PTR(error: ret); |
582 | } |
583 | |
584 | /* This cleanup function is called after various segments have been loaded */ |
585 | static int bzImage64_cleanup(void *loader_data) |
586 | { |
587 | struct bzimage64_data *ldata = loader_data; |
588 | |
589 | if (!ldata) |
590 | return 0; |
591 | |
592 | kfree(objp: ldata->bootparams_buf); |
593 | ldata->bootparams_buf = NULL; |
594 | |
595 | return 0; |
596 | } |
597 | |
598 | const struct kexec_file_ops kexec_bzImage64_ops = { |
599 | .probe = bzImage64_probe, |
600 | .load = bzImage64_load, |
601 | .cleanup = bzImage64_cleanup, |
602 | #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG |
603 | .verify_sig = kexec_kernel_verify_pe_sig, |
604 | #endif |
605 | }; |
606 | |