Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 684019dd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull EFI updates from Ingo Molnar:
 "The main changes in this cycle were:

   - Allocate the E820 buffer before doing the
     GetMemoryMap/ExitBootServices dance so we don't run out of space

   - Clear EFI boot services mappings when freeing the memory

   - Harden efivars against callers that invoke it on non-EFI boots

   - Reduce the number of memblock reservations resulting from extensive
     use of the new efi_mem_reserve_persistent() API

   - Other assorted fixes and cleanups"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/efi: Don't unmap EFI boot services code/data regions for EFI_OLD_MEMMAP and EFI_MIXED_MODE
  efi: Reduce the amount of memblock reservations for persistent allocations
  efi: Permit multiple entries in persistent memreserve data structure
  efi/libstub: Disable some warnings for x86{,_64}
  x86/efi: Move efi_<reserve/free>_boot_services() to arch/x86
  x86/efi: Unmap EFI boot services code/data regions from efi_pgd
  x86/mm/pageattr: Introduce helper function to unmap EFI boot services
  efi/fdt: Simplify the get_fdt() flow
  efi/fdt: Indentation fix
  firmware/efi: Add NULL pointer checks in efivars API functions
parents 792bf4d8 1debf095
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -141,6 +141,8 @@ extern int __init efi_reuse_config(u64 tables, int nr_tables);
extern void efi_delete_dummy_variable(void);
extern void efi_switch_mm(struct mm_struct *mm);
extern void efi_recover_from_page_fault(unsigned long phys_addr);
extern void efi_free_boot_services(void);
extern void efi_reserve_boot_services(void);

struct efi_setup_data {
	u64 fw_vendor;
+6 −2
Original line number Diff line number Diff line
@@ -564,8 +564,12 @@ extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
				    unsigned int *level);
extern pmd_t *lookup_pmd_address(unsigned long address);
extern phys_addr_t slow_virt_to_phys(void *__address);
extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
				   unsigned numpages, unsigned long page_flags);
extern int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn,
					  unsigned long address,
					  unsigned numpages,
					  unsigned long page_flags);
extern int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
					    unsigned long numpages);
#endif	/* !__ASSEMBLY__ */

#endif /* _ASM_X86_PGTABLE_DEFS_H */
+38 −2
Original line number Diff line number Diff line
@@ -2346,7 +2346,7 @@ bool kernel_page_present(struct page *page)

#endif /* CONFIG_DEBUG_PAGEALLOC */

int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
				   unsigned numpages, unsigned long page_flags)
{
	int retval = -EINVAL;
@@ -2361,6 +2361,8 @@ int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
		.flags = 0,
	};

	WARN_ONCE(num_online_cpus() > 1, "Don't call after initializing SMP");

	if (!(__supported_pte_mask & _PAGE_NX))
		goto out;

@@ -2382,6 +2384,40 @@ int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
	return retval;
}

/*
 * __flush_tlb_all() flushes mappings only on current CPU and hence this
 * function shouldn't be used in an SMP environment. Presently, it's used only
 * during boot (way before smp_init()) by EFI subsystem and hence is ok.
 */
int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
				     unsigned long numpages)
{
	int retval;

	/*
	 * The typical sequence for unmapping is to find a pte through
	 * lookup_address_in_pgd() (ideally, it should never return NULL because
	 * the address is already mapped) and change it's protections. As pfn is
	 * the *target* of a mapping, it's not useful while unmapping.
	 */
	struct cpa_data cpa = {
		.vaddr		= &address,
		.pfn		= 0,
		.pgd		= pgd,
		.numpages	= numpages,
		.mask_set	= __pgprot(0),
		.mask_clr	= __pgprot(_PAGE_PRESENT | _PAGE_RW),
		.flags		= 0,
	};

	WARN_ONCE(num_online_cpus() > 1, "Don't call after initializing SMP");

	retval = __change_page_attr_set_clr(&cpa, 0);
	__flush_tlb_all();

	return retval;
}

/*
 * The testcases use internal knowledge of the implementation that shouldn't
 * be exposed to the rest of the kernel. Include these directly here.
+2 −0
Original line number Diff line number Diff line
@@ -993,6 +993,8 @@ static void __init __efi_enter_virtual_mode(void)
		panic("EFI call to SetVirtualAddressMap() failed!");
	}

	efi_free_boot_services();

	/*
	 * Now that EFI is in virtual mode, update the function
	 * pointers in the runtime service table to the new virtual addresses.
+41 −0
Original line number Diff line number Diff line
@@ -369,6 +369,40 @@ void __init efi_reserve_boot_services(void)
	}
}

/*
 * Apart from having VA mappings for EFI boot services code/data regions,
 * (duplicate) 1:1 mappings were also created as a quirk for buggy firmware. So,
 * unmap both 1:1 and VA mappings.
 */
static void __init efi_unmap_pages(efi_memory_desc_t *md)
{
	pgd_t *pgd = efi_mm.pgd;
	u64 pa = md->phys_addr;
	u64 va = md->virt_addr;

	/*
	 * To Do: Remove this check after adding functionality to unmap EFI boot
	 * services code/data regions from direct mapping area because
	 * "efi=old_map" maps EFI regions in swapper_pg_dir.
	 */
	if (efi_enabled(EFI_OLD_MEMMAP))
		return;

	/*
	 * EFI mixed mode has all RAM mapped to access arguments while making
	 * EFI runtime calls, hence don't unmap EFI boot services code/data
	 * regions.
	 */
	if (!efi_is_native())
		return;

	if (kernel_unmap_pages_in_pgd(pgd, pa, md->num_pages))
		pr_err("Failed to unmap 1:1 mapping for 0x%llx\n", pa);

	if (kernel_unmap_pages_in_pgd(pgd, va, md->num_pages))
		pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
}

void __init efi_free_boot_services(void)
{
	phys_addr_t new_phys, new_size;
@@ -393,6 +427,13 @@ void __init efi_free_boot_services(void)
			continue;
		}

		/*
		 * Before calling set_virtual_address_map(), EFI boot services
		 * code/data regions were mapped as a quirk for buggy firmware.
		 * Unmap them from efi_pgd before freeing them up.
		 */
		efi_unmap_pages(md);

		/*
		 * Nasty quirk: if all sub-1MB memory is used for boot
		 * services, we can get here without having allocated the
Loading