/* * Relocate a kernel image, either compressed or uncompressed. * In the ARM64 case, all kernel images are currently * uncompressed, and as such when we relocate it we need to * allocate additional space for the BSS segment. Any low * memory that this function should avoid needs to be * unavailable in the EFI memory map, as if the preferred * address is not available the lowest available address will * be used. */ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, unsigned long *image_addr, unsigned long image_size, unsigned long alloc_size, unsigned long preferred_addr, unsigned long alignment) { unsigned long cur_image_addr; unsigned long new_addr = 0; efi_status_t status; unsigned long nr_pages; efi_physical_addr_t efi_addr = preferred_addr; if (!image_addr || !image_size || !alloc_size) return EFI_INVALID_PARAMETER; if (alloc_size < image_size) return EFI_INVALID_PARAMETER; cur_image_addr = *image_addr; /* * The EFI firmware loader could have placed the kernel image * anywhere in memory, but the kernel has restrictions on the * max physical address it can run at. Some architectures * also have a prefered address, so first try to relocate * to the preferred address. If that fails, allocate as low * as possible while respecting the required alignment. */ nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, nr_pages, &efi_addr); new_addr = efi_addr; /* * If preferred address allocation failed allocate as low as * possible. */ if (status != EFI_SUCCESS) { status = efi_low_alloc(sys_table_arg, alloc_size, alignment, &new_addr); } if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); return status; } /* * We know source/dest won't overlap since both memory ranges * have been allocated by UEFI, so we can safely use memcpy. */ memcpy((void *)new_addr, (void *)cur_image_addr, image_size); /* Return the new address of the relocated image. */ *image_addr = new_addr; return status; }
/* * Convert the unicode UEFI command line to ASCII to pass to kernel. * Size of memory allocated return in *cmd_line_len. * Returns NULL on error. */ static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, efi_loaded_image_t *image, int *cmd_line_len) { u16 *s2; u8 *s1 = NULL; unsigned long cmdline_addr = 0; int load_options_size = image->load_options_size / 2; /* ASCII */ void *options = image->load_options; int options_size = 0; efi_status_t status; int i; u16 zero = 0; if (options) { s2 = options; while (*s2 && *s2 != '\n' && options_size < load_options_size) { s2++; options_size++; } } if (options_size == 0) { /* No command line options, so return empty string*/ options_size = 1; options = &zero; } options_size++; /* NUL termination */ #ifdef CONFIG_ARM /* * For ARM, allocate at a high address to avoid reserved * regions at low addresses that we don't know the specfics of * at the time we are processing the command line. */ status = efi_high_alloc(sys_table_arg, options_size, 0, &cmdline_addr, 0xfffff000); #else status = efi_low_alloc(sys_table_arg, options_size, 0, &cmdline_addr); #endif if (status != EFI_SUCCESS) return NULL; s1 = (u8 *)cmdline_addr; s2 = (u16 *)options; for (i = 0; i < options_size - 1; i++) *s1++ = *s2++; *s1 = '\0'; *cmd_line_len = options_size; return (char *)cmdline_addr; }
/* * Because the x86 boot code expects to be passed a boot_params we * need to create one ourselves (usually the bootloader would create * one for us). * * The caller is responsible for filling out ->code32_start in the * returned boot_params. */ struct boot_params *make_boot_params(struct efi_config *c) { struct boot_params *boot_params; struct apm_bios_info *bi; struct setup_header *hdr; efi_loaded_image_t *image; void *options, *handle; efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; int options_size = 0; efi_status_t status; char *cmdline_ptr; u16 *s2; u8 *s1; int i; unsigned long ramdisk_addr; unsigned long ramdisk_size; efi_early = c; sys_table = (efi_system_table_t *)(unsigned long)efi_early->table; handle = (void *)(unsigned long)efi_early->image_handle; /* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) return NULL; if (efi_early->is64) setup_boot_services64(efi_early); else setup_boot_services32(efi_early); status = efi_call_early(handle_protocol, handle, &proto, (void *)&image); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); return NULL; } status = efi_low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to alloc lowmem for boot params\n"); return NULL; } memset(boot_params, 0x0, 0x4000); hdr = &boot_params->hdr; bi = &boot_params->apm_bios_info; /* Copy the second sector to boot_params */ memcpy(&hdr->jump, image->image_base + 512, 512); /* * Fill out some of the header fields ourselves because the * EFI firmware loader doesn't load the first sector. */ hdr->root_flags = 1; hdr->vid_mode = 0xffff; hdr->boot_flag = 0xAA55; hdr->type_of_loader = 0x21; /* Convert unicode cmdline to ascii */ cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size); if (!cmdline_ptr) goto fail; hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; /* Fill in upper bits of command line address, NOP on 32 bit */ boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32; hdr->ramdisk_image = 0; hdr->ramdisk_size = 0; /* Clear APM BIOS info */ memset(bi, 0, sizeof(*bi)); status = efi_parse_options(cmdline_ptr); if (status != EFI_SUCCESS) goto fail2; status = handle_cmdline_files(sys_table, image, (char *)(unsigned long)hdr->cmd_line_ptr, "initrd=", hdr->initrd_addr_max, &ramdisk_addr, &ramdisk_size); if (status != EFI_SUCCESS && hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) { efi_printk(sys_table, "Trying to load files to higher address\n"); status = handle_cmdline_files(sys_table, image, (char *)(unsigned long)hdr->cmd_line_ptr, "initrd=", -1UL, &ramdisk_addr, &ramdisk_size); } if (status != EFI_SUCCESS) goto fail2; hdr->ramdisk_image = ramdisk_addr & 0xffffffff; hdr->ramdisk_size = ramdisk_size & 0xffffffff; boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32; boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32; return boot_params; fail2: efi_free(sys_table, options_size, hdr->cmd_line_ptr); fail: efi_free(sys_table, 0x4000, (unsigned long)boot_params); return NULL; }