Misc EFI fixes, including the boot failure regression caused by the BSS section not being cleared.
-----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAl6WzYwRHG1pbmdvQGtl cm5lbC5vcmcACgkQEnMQ0APhK1jsFRAArMSO7A9NvpkP2rVpI6mHB2tIBDwLoXMC VNoCB9h0oiV7TDKIDv1f5nhtsdQwIqxOtGVjVAraUoEQPi6Ef55pmE4kSlPklGxU 4+W5Ch1g3gbQCK8leB0cxQW/LingG2LEXM6zzAWtmonkIu1t2F3b+8XrSGNPe56e BFnK9/Y9QNKox14ITtv8u9tOXWc7hkZ8W+fpKmQr1PWtZ0FaUDXmxrjJ4FyYwvnT hUNmGfKAngT13WU7glxhh5B9W161XtlMt0sJ62ZQ4I7t77FErFB81fOQ0wmJwnDu Qa9cQAvFEHvXxnQxhq1pmK+w8vyzdtRZD5eF4kLz2lz5tCiduVSHIutM6xXAqVhD eAVL59hSPGwP1+Tc3JS5d1O2smuWclUWsXKN21cTLgOnNltn2Ri4Ij5FTJ1lOAOh RNekYQJLbiVdSDn8cVtmOzx91q9xeTuu9w1NUAXFM+eVTQbRl7lqA1vln56Ccekn dRPJQiGIUDObjY/8T6AtySc1/tDskDrsQkPF9zw90GXDNITX/G3MluUsQ3m1UA4X JBJQs+ORjoD1ujNNe12G823XGssOrY0vOriY4L1vvJnnarFd2Fku8RKa9ZOLa0Ia YrguIVe63guitBoshJHPoSbglgGgKVWtfN5v0cgPpW3YepUG7xMQGdw1TDQlDNV7 H0hiMRtYdVM= =dC6l -----END PGP SIGNATURE----- Merge tag 'efi-urgent-2020-04-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull EFI fixes from Ingo Molnar: "Misc EFI fixes, including the boot failure regression caused by the BSS section not being cleared by the loaders" * tag 'efi-urgent-2020-04-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: efi/x86: Revert struct layout change to fix kexec boot regression efi/x86: Don't remap text<->rodata gap read-only for mixed mode efi/x86: Fix the deletion of variables in mixed mode efi/libstub/file: Merge file name buffers to reduce stack usage Documentation/x86, efi/x86: Clarify EFI handover protocol and its requirements efi/arm: Deal with ADR going out of range in efi_enter_kernel() efi/x86: Always relocate the kernel for EFI handover entry efi/x86: Move efi stub globals from .bss to .data efi/libstub/x86: Remove redundant assignment to pointer hdr efi/cper: Use scnprintf() for avoiding potential buffer overflow
This commit is contained in:
commit
00086336a8
|
@ -1399,8 +1399,8 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
|
|||
must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
|
||||
address of the struct boot_params.
|
||||
|
||||
EFI Handover Protocol
|
||||
=====================
|
||||
EFI Handover Protocol (deprecated)
|
||||
==================================
|
||||
|
||||
This protocol allows boot loaders to defer initialisation to the EFI
|
||||
boot stub. The boot loader is required to load the kernel/initrd(s)
|
||||
|
@ -1408,6 +1408,12 @@ from the boot media and jump to the EFI handover protocol entry point
|
|||
which is hdr->handover_offset bytes from the beginning of
|
||||
startup_{32,64}.
|
||||
|
||||
The boot loader MUST respect the kernel's PE/COFF metadata when it comes
|
||||
to section alignment, the memory footprint of the executable image beyond
|
||||
the size of the file itself, and any other aspect of the PE/COFF header
|
||||
that may affect correct operation of the image as a PE/COFF binary in the
|
||||
execution context provided by the EFI firmware.
|
||||
|
||||
The function prototype for the handover entry point looks like this::
|
||||
|
||||
efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
|
||||
|
@ -1419,9 +1425,18 @@ UEFI specification. 'bp' is the boot loader-allocated boot params.
|
|||
|
||||
The boot loader *must* fill out the following fields in bp::
|
||||
|
||||
- hdr.code32_start
|
||||
- hdr.cmd_line_ptr
|
||||
- hdr.ramdisk_image (if applicable)
|
||||
- hdr.ramdisk_size (if applicable)
|
||||
|
||||
All other fields should be zero.
|
||||
|
||||
NOTE: The EFI Handover Protocol is deprecated in favour of the ordinary PE/COFF
|
||||
entry point, combined with the LINUX_EFI_INITRD_MEDIA_GUID based initrd
|
||||
loading protocol (refer to [0] for an example of the bootloader side of
|
||||
this), which removes the need for any knowledge on the part of the EFI
|
||||
bootloader regarding the internal representation of boot_params or any
|
||||
requirements/limitations regarding the placement of the command line
|
||||
and ramdisk in memory, or the placement of the kernel image itself.
|
||||
|
||||
[0] https://github.com/u-boot/u-boot/commit/ec80b4735a593961fe701cc3a5d717d4739b0fd0
|
||||
|
|
|
@ -1450,7 +1450,8 @@ ENTRY(efi_enter_kernel)
|
|||
@ running beyond the PoU, and so calling cache_off below from
|
||||
@ inside the PE/COFF loader allocated region is unsafe unless
|
||||
@ we explicitly clean it to the PoC.
|
||||
adr r0, call_cache_fn @ region of code we will
|
||||
ARM( adrl r0, call_cache_fn )
|
||||
THUMB( adr r0, call_cache_fn ) @ region of code we will
|
||||
adr r1, 0f @ run with MMU off
|
||||
bl cache_clean_flush
|
||||
bl cache_off
|
||||
|
|
|
@ -178,8 +178,10 @@ extern void efi_free_boot_services(void);
|
|||
extern pgd_t * __init efi_uv1_memmap_phys_prolog(void);
|
||||
extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
|
||||
|
||||
/* kexec external ABI */
|
||||
struct efi_setup_data {
|
||||
u64 fw_vendor;
|
||||
u64 __unused;
|
||||
u64 tables;
|
||||
u64 smbios;
|
||||
u64 reserved[8];
|
||||
|
|
|
@ -202,7 +202,7 @@ virt_to_phys_or_null_size(void *va, unsigned long size)
|
|||
|
||||
int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
||||
{
|
||||
unsigned long pfn, text, pf;
|
||||
unsigned long pfn, text, pf, rodata;
|
||||
struct page *page;
|
||||
unsigned npages;
|
||||
pgd_t *pgd = efi_mm.pgd;
|
||||
|
@ -256,7 +256,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
|||
|
||||
efi_scratch.phys_stack = page_to_phys(page + 1); /* stack grows down */
|
||||
|
||||
npages = (__end_rodata_aligned - _text) >> PAGE_SHIFT;
|
||||
npages = (_etext - _text) >> PAGE_SHIFT;
|
||||
text = __pa(_text);
|
||||
pfn = text >> PAGE_SHIFT;
|
||||
|
||||
|
@ -266,6 +266,14 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
|||
return 1;
|
||||
}
|
||||
|
||||
npages = (__end_rodata - __start_rodata) >> PAGE_SHIFT;
|
||||
rodata = __pa(__start_rodata);
|
||||
pfn = rodata >> PAGE_SHIFT;
|
||||
if (kernel_map_pages_in_pgd(pgd, pfn, rodata, npages, pf)) {
|
||||
pr_err("Failed to map kernel rodata 1:1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -638,7 +646,7 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
|
|||
phys_vendor = virt_to_phys_or_null(vnd);
|
||||
phys_data = virt_to_phys_or_null_size(data, data_size);
|
||||
|
||||
if (!phys_name || !phys_data)
|
||||
if (!phys_name || (data && !phys_data))
|
||||
status = EFI_INVALID_PARAMETER;
|
||||
else
|
||||
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
||||
|
@ -669,7 +677,7 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
|
|||
phys_vendor = virt_to_phys_or_null(vnd);
|
||||
phys_data = virt_to_phys_or_null_size(data, data_size);
|
||||
|
||||
if (!phys_name || !phys_data)
|
||||
if (!phys_name || (data && !phys_data))
|
||||
status = EFI_INVALID_PARAMETER;
|
||||
else
|
||||
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
||||
|
|
|
@ -101,7 +101,7 @@ void cper_print_bits(const char *pfx, unsigned int bits,
|
|||
if (!len)
|
||||
len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
|
||||
else
|
||||
len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
|
||||
len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
|
||||
}
|
||||
if (len)
|
||||
printk("%s\n", buf);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
@ -742,8 +740,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 +758,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,
|
||||
|
|
Loading…
Reference in New Issue