forked from luck/tmp_suning_uos_patched
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
|
must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
|
||||||
address of the struct boot_params.
|
address of the struct boot_params.
|
||||||
|
|
||||||
EFI Handover Protocol
|
EFI Handover Protocol (deprecated)
|
||||||
=====================
|
==================================
|
||||||
|
|
||||||
This protocol allows boot loaders to defer initialisation to the EFI
|
This protocol allows boot loaders to defer initialisation to the EFI
|
||||||
boot stub. The boot loader is required to load the kernel/initrd(s)
|
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
|
which is hdr->handover_offset bytes from the beginning of
|
||||||
startup_{32,64}.
|
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::
|
The function prototype for the handover entry point looks like this::
|
||||||
|
|
||||||
efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
|
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::
|
The boot loader *must* fill out the following fields in bp::
|
||||||
|
|
||||||
- hdr.code32_start
|
|
||||||
- hdr.cmd_line_ptr
|
- hdr.cmd_line_ptr
|
||||||
- hdr.ramdisk_image (if applicable)
|
- hdr.ramdisk_image (if applicable)
|
||||||
- hdr.ramdisk_size (if applicable)
|
- hdr.ramdisk_size (if applicable)
|
||||||
|
|
||||||
All other fields should be zero.
|
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
|
@ running beyond the PoU, and so calling cache_off below from
|
||||||
@ inside the PE/COFF loader allocated region is unsafe unless
|
@ inside the PE/COFF loader allocated region is unsafe unless
|
||||||
@ we explicitly clean it to the PoC.
|
@ 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
|
adr r1, 0f @ run with MMU off
|
||||||
bl cache_clean_flush
|
bl cache_clean_flush
|
||||||
bl cache_off
|
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 pgd_t * __init efi_uv1_memmap_phys_prolog(void);
|
||||||
extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
|
extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
|
||||||
|
|
||||||
|
/* kexec external ABI */
|
||||||
struct efi_setup_data {
|
struct efi_setup_data {
|
||||||
u64 fw_vendor;
|
u64 fw_vendor;
|
||||||
|
u64 __unused;
|
||||||
u64 tables;
|
u64 tables;
|
||||||
u64 smbios;
|
u64 smbios;
|
||||||
u64 reserved[8];
|
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)
|
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;
|
struct page *page;
|
||||||
unsigned npages;
|
unsigned npages;
|
||||||
pgd_t *pgd = efi_mm.pgd;
|
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 */
|
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);
|
text = __pa(_text);
|
||||||
pfn = text >> PAGE_SHIFT;
|
pfn = text >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
@ -266,6 +266,14 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
||||||
return 1;
|
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;
|
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_vendor = virt_to_phys_or_null(vnd);
|
||||||
phys_data = virt_to_phys_or_null_size(data, data_size);
|
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;
|
status = EFI_INVALID_PARAMETER;
|
||||||
else
|
else
|
||||||
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
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_vendor = virt_to_phys_or_null(vnd);
|
||||||
phys_data = virt_to_phys_or_null_size(data, data_size);
|
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;
|
status = EFI_INVALID_PARAMETER;
|
||||||
else
|
else
|
||||||
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
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)
|
if (!len)
|
||||||
len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
|
len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
|
||||||
else
|
else
|
||||||
len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
|
len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
|
||||||
}
|
}
|
||||||
if (len)
|
if (len)
|
||||||
printk("%s\n", buf);
|
printk("%s\n", buf);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
|
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ARM
|
#if defined(CONFIG_ARM) || defined(CONFIG_X86)
|
||||||
#define __efistub_global __section(.data)
|
#define __efistub_global __section(.data)
|
||||||
#else
|
#else
|
||||||
#define __efistub_global
|
#define __efistub_global
|
||||||
|
|
|
@ -29,30 +29,31 @@
|
||||||
*/
|
*/
|
||||||
#define EFI_READ_CHUNK_SIZE SZ_1M
|
#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,
|
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,
|
efi_file_protocol_t **handle,
|
||||||
unsigned long *file_size)
|
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_guid_t info_guid = EFI_FILE_INFO_ID;
|
||||||
efi_file_protocol_t *fh;
|
efi_file_protocol_t *fh;
|
||||||
unsigned long info_sz;
|
unsigned long info_sz;
|
||||||
efi_status_t status;
|
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) {
|
if (status != EFI_SUCCESS) {
|
||||||
pr_efi_err("Failed to open file: ");
|
pr_efi_err("Failed to open file: ");
|
||||||
efi_char16_printk(filename_16);
|
efi_char16_printk(fi->filename);
|
||||||
efi_printk("\n");
|
efi_printk("\n");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
info_sz = sizeof(finfo);
|
info_sz = sizeof(struct finfo);
|
||||||
status = fh->get_info(fh, &info_guid, &info_sz, &finfo);
|
status = fh->get_info(fh, &info_guid, &info_sz, fi);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
pr_efi_err("Failed to get file info\n");
|
pr_efi_err("Failed to get file info\n");
|
||||||
fh->close(fh);
|
fh->close(fh);
|
||||||
|
@ -60,7 +61,7 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
|
||||||
}
|
}
|
||||||
|
|
||||||
*handle = fh;
|
*handle = fh;
|
||||||
*file_size = finfo.info.file_size;
|
*file_size = fi->info.file_size;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,13 +147,13 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
||||||
|
|
||||||
alloc_addr = alloc_size = 0;
|
alloc_addr = alloc_size = 0;
|
||||||
do {
|
do {
|
||||||
efi_char16_t filename[MAX_FILENAME_SIZE];
|
struct finfo fi;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
void *addr;
|
void *addr;
|
||||||
|
|
||||||
offset = find_file_option(cmdline, cmdline_len,
|
offset = find_file_option(cmdline, cmdline_len,
|
||||||
optstr, optstr_size,
|
optstr, optstr_size,
|
||||||
filename, ARRAY_SIZE(filename));
|
fi.filename, ARRAY_SIZE(fi.filename));
|
||||||
|
|
||||||
if (!offset)
|
if (!offset)
|
||||||
break;
|
break;
|
||||||
|
@ -166,7 +167,7 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = efi_open_file(volume, filename, &file, &size);
|
status = efi_open_file(volume, &fi, &file, &size);
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
goto err_close_volume;
|
goto err_close_volume;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
/* Maximum physical address for 64-bit kernel with 4-level paging */
|
/* Maximum physical address for 64-bit kernel with 4-level paging */
|
||||||
#define MAXMEM_X86_64_4LEVEL (1ull << 46)
|
#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 const bool efi_is64;
|
||||||
extern u32 image_offset;
|
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_base = efi_table_attr(image, image_base);
|
||||||
image_offset = (void *)startup_32 - 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);
|
status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params, ULONG_MAX);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk("Failed to allocate lowmem for boot params\n");
|
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
|
* now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what
|
||||||
* KASLR uses.
|
* KASLR uses.
|
||||||
*
|
*
|
||||||
* Also relocate it if image_offset is zero, i.e. we weren't loaded by
|
* Also relocate it if image_offset is zero, i.e. the kernel wasn't
|
||||||
* LoadImage, but we are not aligned correctly.
|
* 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,
|
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) ||
|
if ((buffer_start < LOAD_PHYSICAL_ADDR) ||
|
||||||
(IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE) ||
|
(IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE) ||
|
||||||
(IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
|
(IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
|
||||||
(image_offset == 0 && !IS_ALIGNED(bzimage_addr,
|
(image_offset == 0)) {
|
||||||
hdr->kernel_alignment))) {
|
|
||||||
status = efi_relocate_kernel(&bzimage_addr,
|
status = efi_relocate_kernel(&bzimage_addr,
|
||||||
hdr->init_size, hdr->init_size,
|
hdr->init_size, hdr->init_size,
|
||||||
hdr->pref_address,
|
hdr->pref_address,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user