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 | kexec_dprintk("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 | #ifdef CONFIG_CRASH_DUMP |
267 | if (image->type == KEXEC_TYPE_CRASH) { |
268 | ret = crash_setup_memmap_entries(image, params); |
269 | if (ret) |
270 | return ret; |
271 | } else |
272 | #endif |
273 | setup_e820_entries(params); |
274 | |
275 | nr_e820_entries = params->e820_entries; |
276 | |
277 | kexec_dprintk("E820 memmap:\n" ); |
278 | for (i = 0; i < nr_e820_entries; i++) { |
279 | kexec_dprintk("%016llx-%016llx (%d)\n" , |
280 | params->e820_table[i].addr, |
281 | params->e820_table[i].addr + params->e820_table[i].size - 1, |
282 | params->e820_table[i].type); |
283 | if (params->e820_table[i].type != E820_TYPE_RAM) |
284 | continue; |
285 | start = params->e820_table[i].addr; |
286 | end = params->e820_table[i].addr + params->e820_table[i].size - 1; |
287 | |
288 | if ((start <= 0x100000) && end > 0x100000) { |
289 | mem_k = (end >> 10) - (0x100000 >> 10); |
290 | params->screen_info.ext_mem_k = mem_k; |
291 | params->alt_mem_k = mem_k; |
292 | if (mem_k > 0xfc00) |
293 | params->screen_info.ext_mem_k = 0xfc00; /* 64M*/ |
294 | if (mem_k > 0xffffffff) |
295 | params->alt_mem_k = 0xffffffff; |
296 | } |
297 | } |
298 | |
299 | #ifdef CONFIG_EFI |
300 | /* Setup EFI state */ |
301 | setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz, |
302 | efi_setup_data_offset: setup_data_offset); |
303 | setup_data_offset += sizeof(struct setup_data) + |
304 | sizeof(struct efi_setup_data); |
305 | #endif |
306 | |
307 | if (IS_ENABLED(CONFIG_IMA_KEXEC)) { |
308 | /* Setup IMA log buffer state */ |
309 | setup_ima_state(image, params, params_load_addr, |
310 | ima_setup_data_offset: setup_data_offset); |
311 | setup_data_offset += sizeof(struct setup_data) + |
312 | sizeof(struct ima_setup_data); |
313 | } |
314 | |
315 | /* Setup RNG seed */ |
316 | setup_rng_seed(params, params_load_addr, rng_seed_setup_data_offset: setup_data_offset); |
317 | |
318 | /* Setup EDD info */ |
319 | memcpy(params->eddbuf, boot_params.eddbuf, |
320 | EDDMAXNR * sizeof(struct edd_info)); |
321 | params->eddbuf_entries = boot_params.eddbuf_entries; |
322 | |
323 | memcpy(params->edd_mbr_sig_buffer, boot_params.edd_mbr_sig_buffer, |
324 | EDD_MBR_SIG_MAX * sizeof(unsigned int)); |
325 | |
326 | return ret; |
327 | } |
328 | |
329 | static int bzImage64_probe(const char *buf, unsigned long len) |
330 | { |
331 | int ret = -ENOEXEC; |
332 | struct setup_header *; |
333 | |
334 | /* kernel should be at least two sectors long */ |
335 | if (len < 2 * 512) { |
336 | pr_err("File is too short to be a bzImage\n" ); |
337 | return ret; |
338 | } |
339 | |
340 | header = (struct setup_header *)(buf + offsetof(struct boot_params, hdr)); |
341 | if (memcmp(p: (char *)&header->header, q: "HdrS" , size: 4) != 0) { |
342 | pr_err("Not a bzImage\n" ); |
343 | return ret; |
344 | } |
345 | |
346 | if (header->boot_flag != 0xAA55) { |
347 | pr_err("No x86 boot sector present\n" ); |
348 | return ret; |
349 | } |
350 | |
351 | if (header->version < 0x020C) { |
352 | pr_err("Must be at least protocol version 2.12\n" ); |
353 | return ret; |
354 | } |
355 | |
356 | if (!(header->loadflags & LOADED_HIGH)) { |
357 | pr_err("zImage not a bzImage\n" ); |
358 | return ret; |
359 | } |
360 | |
361 | if (!(header->xloadflags & XLF_KERNEL_64)) { |
362 | pr_err("Not a bzImage64. XLF_KERNEL_64 is not set.\n" ); |
363 | return ret; |
364 | } |
365 | |
366 | if (!(header->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G)) { |
367 | pr_err("XLF_CAN_BE_LOADED_ABOVE_4G is not set.\n" ); |
368 | return ret; |
369 | } |
370 | |
371 | /* |
372 | * Can't handle 32bit EFI as it does not allow loading kernel |
373 | * above 4G. This should be handled by 32bit bzImage loader |
374 | */ |
375 | if (efi_enabled(EFI_RUNTIME_SERVICES) && !efi_enabled(EFI_64BIT)) { |
376 | pr_debug("EFI is 32 bit. Can't load kernel above 4G.\n" ); |
377 | return ret; |
378 | } |
379 | |
380 | if (!(header->xloadflags & XLF_5LEVEL) && pgtable_l5_enabled()) { |
381 | pr_err("bzImage cannot handle 5-level paging mode.\n" ); |
382 | return ret; |
383 | } |
384 | |
385 | /* I've got a bzImage */ |
386 | pr_debug("It's a relocatable bzImage64\n" ); |
387 | ret = 0; |
388 | |
389 | return ret; |
390 | } |
391 | |
392 | static void *bzImage64_load(struct kimage *image, char *kernel, |
393 | unsigned long kernel_len, char *initrd, |
394 | unsigned long initrd_len, char *cmdline, |
395 | unsigned long cmdline_len) |
396 | { |
397 | |
398 | struct setup_header *; |
399 | int setup_sects, kern16_size, ret = 0; |
400 | unsigned long , params_cmdline_sz; |
401 | struct boot_params *params; |
402 | unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr; |
403 | struct bzimage64_data *ldata; |
404 | struct kexec_entry64_regs regs64; |
405 | void *stack; |
406 | unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr); |
407 | unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset; |
408 | struct kexec_buf kbuf = { .image = image, .buf_max = ULONG_MAX, |
409 | .top_down = true }; |
410 | struct kexec_buf pbuf = { .image = image, .buf_min = MIN_PURGATORY_ADDR, |
411 | .buf_max = ULONG_MAX, .top_down = true }; |
412 | |
413 | header = (struct setup_header *)(kernel + setup_hdr_offset); |
414 | setup_sects = header->setup_sects; |
415 | if (setup_sects == 0) |
416 | setup_sects = 4; |
417 | |
418 | kern16_size = (setup_sects + 1) * 512; |
419 | if (kernel_len < kern16_size) { |
420 | pr_err("bzImage truncated\n" ); |
421 | return ERR_PTR(error: -ENOEXEC); |
422 | } |
423 | |
424 | if (cmdline_len > header->cmdline_size) { |
425 | pr_err("Kernel command line too long\n" ); |
426 | return ERR_PTR(error: -EINVAL); |
427 | } |
428 | |
429 | /* |
430 | * In case of crash dump, we will append elfcorehdr=<addr> to |
431 | * command line. Make sure it does not overflow |
432 | */ |
433 | if (cmdline_len + MAX_ELFCOREHDR_STR_LEN > header->cmdline_size) { |
434 | pr_err("Appending elfcorehdr=<addr> to command line exceeds maximum allowed length\n" ); |
435 | return ERR_PTR(error: -EINVAL); |
436 | } |
437 | |
438 | #ifdef CONFIG_CRASH_DUMP |
439 | /* Allocate and load backup region */ |
440 | if (image->type == KEXEC_TYPE_CRASH) { |
441 | ret = crash_load_segments(image); |
442 | if (ret) |
443 | return ERR_PTR(error: ret); |
444 | } |
445 | #endif |
446 | |
447 | /* |
448 | * Load purgatory. For 64bit entry point, purgatory code can be |
449 | * anywhere. |
450 | */ |
451 | ret = kexec_load_purgatory(image, kbuf: &pbuf); |
452 | if (ret) { |
453 | pr_err("Loading purgatory failed\n" ); |
454 | return ERR_PTR(error: ret); |
455 | } |
456 | |
457 | kexec_dprintk("Loaded purgatory at 0x%lx\n" , pbuf.mem); |
458 | |
459 | |
460 | /* |
461 | * Load Bootparams and cmdline and space for efi stuff. |
462 | * |
463 | * Allocate memory together for multiple data structures so |
464 | * that they all can go in single area/segment and we don't |
465 | * have to create separate segment for each. Keeps things |
466 | * little bit simple |
467 | */ |
468 | efi_map_sz = efi_get_runtime_map_size(); |
469 | params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + |
470 | MAX_ELFCOREHDR_STR_LEN; |
471 | params_cmdline_sz = ALIGN(params_cmdline_sz, 16); |
472 | kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) + |
473 | sizeof(struct setup_data) + |
474 | sizeof(struct efi_setup_data) + |
475 | sizeof(struct setup_data) + |
476 | RNG_SEED_LENGTH; |
477 | |
478 | if (IS_ENABLED(CONFIG_IMA_KEXEC)) |
479 | kbuf.bufsz += sizeof(struct setup_data) + |
480 | sizeof(struct ima_setup_data); |
481 | |
482 | params = kzalloc(size: kbuf.bufsz, GFP_KERNEL); |
483 | if (!params) |
484 | return ERR_PTR(error: -ENOMEM); |
485 | efi_map_offset = params_cmdline_sz; |
486 | efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16); |
487 | |
488 | /* Copy setup header onto bootparams. Documentation/arch/x86/boot.rst */ |
489 | setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset; |
490 | |
491 | /* Is there a limit on setup header size? */ |
492 | memcpy(¶ms->hdr, (kernel + setup_hdr_offset), setup_header_size); |
493 | |
494 | kbuf.buffer = params; |
495 | kbuf.memsz = kbuf.bufsz; |
496 | kbuf.buf_align = 16; |
497 | kbuf.buf_min = MIN_BOOTPARAM_ADDR; |
498 | ret = kexec_add_buffer(kbuf: &kbuf); |
499 | if (ret) |
500 | goto out_free_params; |
501 | bootparam_load_addr = kbuf.mem; |
502 | kexec_dprintk("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , |
503 | bootparam_load_addr, kbuf.bufsz, kbuf.memsz); |
504 | |
505 | /* Load kernel */ |
506 | kbuf.buffer = kernel + kern16_size; |
507 | kbuf.bufsz = kernel_len - kern16_size; |
508 | kbuf.memsz = PAGE_ALIGN(header->init_size); |
509 | kbuf.buf_align = header->kernel_alignment; |
510 | if (header->pref_address < MIN_KERNEL_LOAD_ADDR) |
511 | kbuf.buf_min = MIN_KERNEL_LOAD_ADDR; |
512 | else |
513 | kbuf.buf_min = header->pref_address; |
514 | kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; |
515 | ret = kexec_add_buffer(kbuf: &kbuf); |
516 | if (ret) |
517 | goto out_free_params; |
518 | kernel_load_addr = kbuf.mem; |
519 | |
520 | kexec_dprintk("Loaded 64bit kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , |
521 | kernel_load_addr, kbuf.bufsz, kbuf.memsz); |
522 | |
523 | /* Load initrd high */ |
524 | if (initrd) { |
525 | kbuf.buffer = initrd; |
526 | kbuf.bufsz = kbuf.memsz = initrd_len; |
527 | kbuf.buf_align = PAGE_SIZE; |
528 | kbuf.buf_min = MIN_INITRD_LOAD_ADDR; |
529 | kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; |
530 | ret = kexec_add_buffer(kbuf: &kbuf); |
531 | if (ret) |
532 | goto out_free_params; |
533 | initrd_load_addr = kbuf.mem; |
534 | |
535 | kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n" , |
536 | initrd_load_addr, initrd_len, initrd_len); |
537 | |
538 | setup_initrd(params, initrd_load_addr, initrd_len); |
539 | } |
540 | |
541 | setup_cmdline(image, params, bootparams_load_addr: bootparam_load_addr, |
542 | cmdline_offset: sizeof(struct boot_params), cmdline, cmdline_len); |
543 | |
544 | /* bootloader info. Do we need a separate ID for kexec kernel loader? */ |
545 | params->hdr.type_of_loader = 0x0D << 4; |
546 | params->hdr.loadflags = 0; |
547 | |
548 | /* Setup purgatory regs for entry */ |
549 | ret = kexec_purgatory_get_set_symbol(image, name: "entry64_regs" , buf: ®s64, |
550 | size: sizeof(regs64), get_value: 1); |
551 | if (ret) |
552 | goto out_free_params; |
553 | |
554 | regs64.rbx = 0; /* Bootstrap Processor */ |
555 | regs64.rsi = bootparam_load_addr; |
556 | regs64.rip = kernel_load_addr + 0x200; |
557 | stack = kexec_purgatory_get_symbol_addr(image, name: "stack_end" ); |
558 | if (IS_ERR(ptr: stack)) { |
559 | pr_err("Could not find address of symbol stack_end\n" ); |
560 | ret = -EINVAL; |
561 | goto out_free_params; |
562 | } |
563 | |
564 | regs64.rsp = (unsigned long)stack; |
565 | ret = kexec_purgatory_get_set_symbol(image, name: "entry64_regs" , buf: ®s64, |
566 | size: sizeof(regs64), get_value: 0); |
567 | if (ret) |
568 | goto out_free_params; |
569 | |
570 | ret = setup_boot_parameters(image, params, params_load_addr: bootparam_load_addr, |
571 | efi_map_offset, efi_map_sz, |
572 | setup_data_offset: efi_setup_data_offset); |
573 | if (ret) |
574 | goto out_free_params; |
575 | |
576 | /* Allocate loader specific data */ |
577 | ldata = kzalloc(size: sizeof(struct bzimage64_data), GFP_KERNEL); |
578 | if (!ldata) { |
579 | ret = -ENOMEM; |
580 | goto out_free_params; |
581 | } |
582 | |
583 | /* |
584 | * Store pointer to params so that it could be freed after loading |
585 | * params segment has been loaded and contents have been copied |
586 | * somewhere else. |
587 | */ |
588 | ldata->bootparams_buf = params; |
589 | return ldata; |
590 | |
591 | out_free_params: |
592 | kfree(objp: params); |
593 | return ERR_PTR(error: ret); |
594 | } |
595 | |
596 | /* This cleanup function is called after various segments have been loaded */ |
597 | static int bzImage64_cleanup(void *loader_data) |
598 | { |
599 | struct bzimage64_data *ldata = loader_data; |
600 | |
601 | if (!ldata) |
602 | return 0; |
603 | |
604 | kfree(objp: ldata->bootparams_buf); |
605 | ldata->bootparams_buf = NULL; |
606 | |
607 | return 0; |
608 | } |
609 | |
610 | const struct kexec_file_ops kexec_bzImage64_ops = { |
611 | .probe = bzImage64_probe, |
612 | .load = bzImage64_load, |
613 | .cleanup = bzImage64_cleanup, |
614 | #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG |
615 | .verify_sig = kexec_kernel_verify_pe_sig, |
616 | #endif |
617 | }; |
618 | |