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