diff options
Diffstat (limited to 'drivers/firmware/efi/libstub')
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 6 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 15 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/file.c | 27 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/mem.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/tpm.c | 5 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/x86-stub.c | 42 |
6 files changed, 56 insertions, 41 deletions
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 99a5cde7c2d8..48161b1dd098 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -60,7 +60,11 @@ static struct screen_info *setup_graphics(void) si = alloc_screen_info(); if (!si) return NULL; - efi_setup_gop(si, &gop_proto, size); + status = efi_setup_gop(si, &gop_proto, size); + if (status != EFI_SUCCESS) { + free_screen_info(si); + return NULL; + } } return si; } diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index cc90a748bcf0..62943992f02f 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -25,7 +25,7 @@ #define EFI_ALLOC_ALIGN EFI_PAGE_SIZE #endif -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_X86) #define __efistub_global __section(.data) #else #define __efistub_global @@ -92,6 +92,19 @@ extern __pure efi_system_table_t *efi_system_table(void); #define EFI_LOCATE_BY_REGISTER_NOTIFY 1 #define EFI_LOCATE_BY_PROTOCOL 2 +/* + * An efi_boot_memmap is used by efi_get_memory_map() to return the + * EFI memory map in a dynamically allocated buffer. + * + * The buffer allocated for the EFI memory map includes extra room for + * a minimum of EFI_MMAP_NR_SLACK_SLOTS additional EFI memory descriptors. + * This facilitates the reuse of the EFI memory map buffer when a second + * call to ExitBootServices() is needed because of intervening changes to + * the EFI memory map. Other related structures, e.g. x86 e820ext, need + * to factor in this headroom requirement as well. + */ +#define EFI_MMAP_NR_SLACK_SLOTS 8 + struct efi_boot_memmap { efi_memory_desc_t **map; unsigned long *map_size; diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c index d4c7e5f59d2c..ea66b1f16a79 100644 --- a/drivers/firmware/efi/libstub/file.c +++ b/drivers/firmware/efi/libstub/file.c @@ -29,30 +29,31 @@ */ #define EFI_READ_CHUNK_SIZE SZ_1M +struct finfo { + efi_file_info_t info; + efi_char16_t filename[MAX_FILENAME_SIZE]; +}; + static efi_status_t efi_open_file(efi_file_protocol_t *volume, - efi_char16_t *filename_16, + struct finfo *fi, efi_file_protocol_t **handle, unsigned long *file_size) { - struct { - efi_file_info_t info; - efi_char16_t filename[MAX_FILENAME_SIZE]; - } finfo; efi_guid_t info_guid = EFI_FILE_INFO_ID; efi_file_protocol_t *fh; unsigned long info_sz; efi_status_t status; - status = volume->open(volume, &fh, filename_16, EFI_FILE_MODE_READ, 0); + status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0); if (status != EFI_SUCCESS) { pr_efi_err("Failed to open file: "); - efi_char16_printk(filename_16); + efi_char16_printk(fi->filename); efi_printk("\n"); return status; } - info_sz = sizeof(finfo); - status = fh->get_info(fh, &info_guid, &info_sz, &finfo); + info_sz = sizeof(struct finfo); + status = fh->get_info(fh, &info_guid, &info_sz, fi); if (status != EFI_SUCCESS) { pr_efi_err("Failed to get file info\n"); fh->close(fh); @@ -60,7 +61,7 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume, } *handle = fh; - *file_size = finfo.info.file_size; + *file_size = fi->info.file_size; return EFI_SUCCESS; } @@ -146,13 +147,13 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image, alloc_addr = alloc_size = 0; do { - efi_char16_t filename[MAX_FILENAME_SIZE]; + struct finfo fi; unsigned long size; void *addr; offset = find_file_option(cmdline, cmdline_len, optstr, optstr_size, - filename, ARRAY_SIZE(filename)); + fi.filename, ARRAY_SIZE(fi.filename)); if (!offset) break; @@ -166,7 +167,7 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image, return status; } - status = efi_open_file(volume, filename, &file, &size); + status = efi_open_file(volume, &fi, &file, &size); if (status != EFI_SUCCESS) goto err_close_volume; diff --git a/drivers/firmware/efi/libstub/mem.c b/drivers/firmware/efi/libstub/mem.c index 869a79c8946f..09f4fa01914e 100644 --- a/drivers/firmware/efi/libstub/mem.c +++ b/drivers/firmware/efi/libstub/mem.c @@ -5,8 +5,6 @@ #include "efistub.h" -#define EFI_MMAP_NR_SLACK_SLOTS 8 - static inline bool mmap_has_headroom(unsigned long buff_size, unsigned long map_size, unsigned long desc_size) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 1d59e103a2e3..e9a684637b70 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -54,7 +54,7 @@ void efi_retrieve_tpm2_eventlog(void) efi_status_t status; efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; - struct efi_tcg2_final_events_table *final_events_table; + struct efi_tcg2_final_events_table *final_events_table = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; efi_bool_t truncated; @@ -127,7 +127,8 @@ void efi_retrieve_tpm2_eventlog(void) * Figure out whether any events have already been logged to the * final events structure, and if so how much space they take up */ - final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); if (final_events_table && final_events_table->nr_events) { struct tcg_pcr_event2_head *header; int offset; diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index 8d3a707789de..f0339b5d3658 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -20,7 +20,7 @@ /* Maximum physical address for 64-bit kernel with 4-level paging */ #define MAXMEM_X86_64_4LEVEL (1ull << 46) -static efi_system_table_t *sys_table; +static efi_system_table_t *sys_table __efistub_global; extern const bool efi_is64; extern u32 image_offset; @@ -392,8 +392,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, image_base = efi_table_attr(image, image_base); image_offset = (void *)startup_32 - image_base; - hdr = &((struct boot_params *)image_base)->hdr; - status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params, ULONG_MAX); if (status != EFI_SUCCESS) { efi_printk("Failed to allocate lowmem for boot params\n"); @@ -608,24 +606,18 @@ static efi_status_t allocate_e820(struct boot_params *params, struct setup_data **e820ext, u32 *e820ext_size) { - unsigned long map_size, desc_size, buff_size; - struct efi_boot_memmap boot_map; - efi_memory_desc_t *map; + unsigned long map_size, desc_size, map_key; efi_status_t status; - __u32 nr_desc; - - boot_map.map = ↦ - boot_map.map_size = &map_size; - boot_map.desc_size = &desc_size; - boot_map.desc_ver = NULL; - boot_map.key_ptr = NULL; - boot_map.buff_size = &buff_size; + __u32 nr_desc, desc_version; - status = efi_get_memory_map(&boot_map); - if (status != EFI_SUCCESS) - return status; + /* Only need the size of the mem map and size of each mem descriptor */ + map_size = 0; + status = efi_bs_call(get_memory_map, &map_size, NULL, &map_key, + &desc_size, &desc_version); + if (status != EFI_BUFFER_TOO_SMALL) + return (status != EFI_SUCCESS) ? status : EFI_UNSUPPORTED; - nr_desc = buff_size / desc_size; + nr_desc = map_size / desc_size + EFI_MMAP_NR_SLACK_SLOTS; if (nr_desc > ARRAY_SIZE(params->e820_table)) { u32 nr_e820ext = nr_desc - ARRAY_SIZE(params->e820_table); @@ -742,8 +734,15 @@ unsigned long efi_main(efi_handle_t handle, * now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what * KASLR uses. * - * Also relocate it if image_offset is zero, i.e. we weren't loaded by - * LoadImage, but we are not aligned correctly. + * Also relocate it if image_offset is zero, i.e. the kernel wasn't + * loaded by LoadImage, but rather by a bootloader that called the + * handover entry. The reason we must always relocate in this case is + * to handle the case of systemd-boot booting a unified kernel image, + * which is a PE executable that contains the bzImage and an initrd as + * COFF sections. The initrd section is placed after the bzImage + * without ensuring that there are at least init_size bytes available + * for the bzImage, and thus the compressed kernel's startup code may + * overwrite the initrd unless it is moved out of the way. */ buffer_start = ALIGN(bzimage_addr - image_offset, @@ -753,8 +752,7 @@ unsigned long efi_main(efi_handle_t handle, if ((buffer_start < LOAD_PHYSICAL_ADDR) || (IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE) || (IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) || - (image_offset == 0 && !IS_ALIGNED(bzimage_addr, - hdr->kernel_alignment))) { + (image_offset == 0)) { status = efi_relocate_kernel(&bzimage_addr, hdr->init_size, hdr->init_size, hdr->pref_address, |