|
@@ -31,6 +31,7 @@
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/efi.h>
|
|
|
+#include <linux/efi-bgrt.h>
|
|
|
#include <linux/export.h>
|
|
|
#include <linux/bootmem.h>
|
|
|
#include <linux/memblock.h>
|
|
@@ -419,10 +420,21 @@ void __init efi_reserve_boot_services(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void __init efi_free_boot_services(void)
|
|
|
+static void __init efi_unmap_memmap(void)
|
|
|
+{
|
|
|
+ if (memmap.map) {
|
|
|
+ early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
|
|
|
+ memmap.map = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void __init efi_free_boot_services(void)
|
|
|
{
|
|
|
void *p;
|
|
|
|
|
|
+ if (!efi_native)
|
|
|
+ return;
|
|
|
+
|
|
|
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
|
|
efi_memory_desc_t *md = p;
|
|
|
unsigned long long start = md->phys_addr;
|
|
@@ -438,6 +450,8 @@ static void __init efi_free_boot_services(void)
|
|
|
|
|
|
free_bootmem_late(start, size);
|
|
|
}
|
|
|
+
|
|
|
+ efi_unmap_memmap();
|
|
|
}
|
|
|
|
|
|
static int __init efi_systab_init(void *phys)
|
|
@@ -732,6 +746,11 @@ void __init efi_init(void)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+void __init efi_late_init(void)
|
|
|
+{
|
|
|
+ efi_bgrt_init();
|
|
|
+}
|
|
|
+
|
|
|
void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
|
|
|
{
|
|
|
u64 addr, npages;
|
|
@@ -763,6 +782,34 @@ static void __init runtime_code_page_mkexec(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * We can't ioremap data in EFI boot services RAM, because we've already mapped
|
|
|
+ * it as RAM. So, look it up in the existing EFI memory map instead. Only
|
|
|
+ * callable after efi_enter_virtual_mode and before efi_free_boot_services.
|
|
|
+ */
|
|
|
+void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
|
|
|
+{
|
|
|
+ void *p;
|
|
|
+ if (WARN_ON(!memmap.map))
|
|
|
+ return NULL;
|
|
|
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
|
|
+ efi_memory_desc_t *md = p;
|
|
|
+ u64 size = md->num_pages << EFI_PAGE_SHIFT;
|
|
|
+ u64 end = md->phys_addr + size;
|
|
|
+ if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
|
|
|
+ md->type != EFI_BOOT_SERVICES_CODE &&
|
|
|
+ md->type != EFI_BOOT_SERVICES_DATA)
|
|
|
+ continue;
|
|
|
+ if (!md->virt_addr)
|
|
|
+ continue;
|
|
|
+ if (phys_addr >= md->phys_addr && phys_addr < end) {
|
|
|
+ phys_addr += md->virt_addr - md->phys_addr;
|
|
|
+ return (__force void __iomem *)(unsigned long)phys_addr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This function will switch the EFI runtime services to virtual mode.
|
|
|
* Essentially, look through the EFI memmap and map every region that
|
|
@@ -787,8 +834,10 @@ void __init efi_enter_virtual_mode(void)
|
|
|
* non-native EFI
|
|
|
*/
|
|
|
|
|
|
- if (!efi_native)
|
|
|
- goto out;
|
|
|
+ if (!efi_native) {
|
|
|
+ efi_unmap_memmap();
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
/* Merge contiguous regions of the same type and attribute */
|
|
|
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
|
@@ -877,19 +926,13 @@ void __init efi_enter_virtual_mode(void)
|
|
|
panic("EFI call to SetVirtualAddressMap() failed!");
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Thankfully, it does seem that no runtime services other than
|
|
|
- * SetVirtualAddressMap() will touch boot services code, so we can
|
|
|
- * get rid of it all at this point
|
|
|
- */
|
|
|
- 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.
|
|
|
*
|
|
|
* Call EFI services through wrapper functions.
|
|
|
*/
|
|
|
+ efi.runtime_version = efi_systab.fw_revision;
|
|
|
efi.get_time = virt_efi_get_time;
|
|
|
efi.set_time = virt_efi_set_time;
|
|
|
efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
|
@@ -906,9 +949,6 @@ void __init efi_enter_virtual_mode(void)
|
|
|
if (__supported_pte_mask & _PAGE_NX)
|
|
|
runtime_code_page_mkexec();
|
|
|
|
|
|
-out:
|
|
|
- early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
|
|
|
- memmap.map = NULL;
|
|
|
kfree(new_memmap);
|
|
|
}
|
|
|
|