/* * Defines lowest physical address for various segments. Not sure where * exactly these limits came from. Current bzimage64 loader in kexec-tools * uses these so I am retaining it. It can be changed over time as we gain * more insight.
*/ #define MIN_PURGATORY_ADDR 0x3000 #define MIN_BOOTPARAM_ADDR 0x3000 #define MIN_KERNEL_LOAD_ADDR 0x100000 #define MIN_INITRD_LOAD_ADDR 0x1000000
/* * This is a place holder for all boot loader specific data structure which * gets allocated in one call but gets freed much later during cleanup * time. Right now there is only one field but it can grow as need be.
*/ struct bzimage64_data { /* * Temporary buffer to hold bootparams buffer. This should be * freed once the bootparam segment has been loaded.
*/ void *bootparams_buf;
};
/* TODO: Pass entries more than E820_MAX_ENTRIES_ZEROPAGE in bootparams setup data */ if (nr_e820_entries > E820_MAX_ENTRIES_ZEROPAGE)
nr_e820_entries = E820_MAX_ENTRIES_ZEROPAGE;
if (header->boot_flag != 0xAA55) {
pr_err("No x86 boot sector present\n"); return ret;
}
if (header->version < 0x020C) {
pr_err("Must be at least protocol version 2.12\n"); return ret;
}
if (!(header->loadflags & LOADED_HIGH)) {
pr_err("zImage not a bzImage\n"); return ret;
}
if (!(header->xloadflags & XLF_KERNEL_64)) {
pr_err("Not a bzImage64. XLF_KERNEL_64 is not set.\n"); return ret;
}
if (!(header->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G)) {
pr_err("XLF_CAN_BE_LOADED_ABOVE_4G is not set.\n"); return ret;
}
/* * Can't handle 32bit EFI as it does not allow loading kernel * above 4G. This should be handled by 32bit bzImage loader
*/ if (efi_enabled(EFI_RUNTIME_SERVICES) && !efi_enabled(EFI_64BIT)) {
pr_debug("EFI is 32 bit. Can't load kernel above 4G.\n"); return ret;
}
if (cmdline_len > header->cmdline_size) {
pr_err("Kernel command line too long\n"); return ERR_PTR(-EINVAL);
}
/* * In case of crash dump, we will append elfcorehdr=<addr> to * command line. Make sure it does not overflow
*/ if (cmdline_len + MAX_ELFCOREHDR_STR_LEN > header->cmdline_size) {
pr_err("Appending elfcorehdr=<addr> to command line exceeds maximum allowed length\n"); return ERR_PTR(-EINVAL);
}
#ifdef CONFIG_CRASH_DUMP /* Allocate and load backup region */ if (image->type == KEXEC_TYPE_CRASH) {
ret = crash_load_segments(image); if (ret) return ERR_PTR(ret);
ret = crash_load_dm_crypt_keys(image); if (ret == -ENOENT) {
kexec_dprintk("No dm crypt key to load\n");
} elseif (ret) {
pr_err("Failed to load dm crypt keys\n"); return ERR_PTR(ret);
} if (image->dm_crypt_keys_addr &&
cmdline_len + MAX_ELFCOREHDR_STR_LEN + MAX_DMCRYPTKEYS_STR_LEN >
header->cmdline_size) {
pr_err("Appending dmcryptkeys=<addr> to command line exceeds maximum allowed length\n"); return ERR_PTR(-EINVAL);
}
} #endif
/* * Load purgatory. For 64bit entry point, purgatory code can be * anywhere.
*/
ret = kexec_load_purgatory(image, &pbuf); if (ret) {
pr_err("Loading purgatory failed\n"); return ERR_PTR(ret);
}
kexec_dprintk("Loaded purgatory at 0x%lx\n", pbuf.mem);
/* * Load Bootparams and cmdline and space for efi stuff. * * Allocate memory together for multiple data structures so * that they all can go in single area/segment and we don't * have to create separate segment for each. Keeps things * little bit simple
*/
efi_map_sz = efi_get_runtime_map_size();
params_cmdline_sz = sizeof(struct boot_params) + cmdline_len +
MAX_ELFCOREHDR_STR_LEN; if (image->dm_crypt_keys_addr)
params_cmdline_sz += MAX_DMCRYPTKEYS_STR_LEN;
params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) + sizeof(struct setup_data) + sizeof(struct efi_setup_data) + sizeof(struct setup_data) +
RNG_SEED_LENGTH;
if (IS_ENABLED(CONFIG_IMA_KEXEC))
kbuf.bufsz += sizeof(struct setup_data) + sizeof(struct ima_setup_data);
if (IS_ENABLED(CONFIG_KEXEC_HANDOVER))
kbuf.bufsz += sizeof(struct setup_data) + sizeof(struct kho_data);
/* bootloader info. Do we need a separate ID for kexec kernel loader? */
params->hdr.type_of_loader = 0x0D << 4;
params->hdr.loadflags = 0;
/* Setup purgatory regs for entry */
ret = kexec_purgatory_get_set_symbol(image, "entry64_regs", ®s64, sizeof(regs64), 1); if (ret) goto out_free_params;
regs64.rbx = 0; /* Bootstrap Processor */
regs64.rsi = bootparam_load_addr;
regs64.rip = kernel_load_addr + 0x200;
stack = kexec_purgatory_get_symbol_addr(image, "stack_end"); if (IS_ERR(stack)) {
pr_err("Could not find address of symbol stack_end\n");
ret = -EINVAL; goto out_free_params;
}
regs64.rsp = (unsignedlong)stack;
ret = kexec_purgatory_get_set_symbol(image, "entry64_regs", ®s64, sizeof(regs64), 0); if (ret) goto out_free_params;
ret = setup_boot_parameters(image, params, bootparam_load_addr,
efi_map_offset, efi_map_sz,
efi_setup_data_offset); if (ret) goto out_free_params;
/* Allocate loader specific data */
ldata = kzalloc(sizeof(struct bzimage64_data), GFP_KERNEL); if (!ldata) {
ret = -ENOMEM; goto out_free_params;
}
/* * Store pointer to params so that it could be freed after loading * params segment has been loaded and contents have been copied * somewhere else.
*/
ldata->bootparams_buf = params; return ldata;
/* This cleanup function is called after various segments have been loaded */ staticint bzImage64_cleanup(void *loader_data)
{ struct bzimage64_data *ldata = loader_data;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.