Commit 00086336 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 8632e9b5 a088b858
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -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
+2 −1
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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];
+12 −4
Original line number Diff line number Diff line
@@ -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,
+1 −1
Original line number Diff line number Diff line
@@ -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);
Loading