|
@@ -879,8 +879,9 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int __init save_runtime_map(void)
|
|
|
+static void __init save_runtime_map(void)
|
|
|
{
|
|
|
+#ifdef CONFIG_KEXEC
|
|
|
efi_memory_desc_t *md;
|
|
|
void *tmp, *p, *q = NULL;
|
|
|
int count = 0;
|
|
@@ -902,28 +903,12 @@ static int __init save_runtime_map(void)
|
|
|
}
|
|
|
|
|
|
efi_runtime_map_setup(q, count, memmap.desc_size);
|
|
|
+ return;
|
|
|
|
|
|
- return 0;
|
|
|
out:
|
|
|
kfree(q);
|
|
|
- return -ENOMEM;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Map efi regions which were passed via setup_data. The virt_addr is a fixed
|
|
|
- * addr which was used in first kernel of a kexec boot.
|
|
|
- */
|
|
|
-static void __init efi_map_regions_fixed(void)
|
|
|
-{
|
|
|
- void *p;
|
|
|
- efi_memory_desc_t *md;
|
|
|
-
|
|
|
- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
|
|
- md = p;
|
|
|
- efi_map_region_fixed(md); /* FIXME: add error handling */
|
|
|
- get_systab_virt_addr(md);
|
|
|
- }
|
|
|
-
|
|
|
+ pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
static void *realloc_pages(void *old_memmap, int old_shift)
|
|
@@ -989,6 +974,72 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
|
|
|
return new_memmap;
|
|
|
}
|
|
|
|
|
|
+static void __init kexec_enter_virtual_mode(void)
|
|
|
+{
|
|
|
+#ifdef CONFIG_KEXEC
|
|
|
+ efi_memory_desc_t *md;
|
|
|
+ void *p;
|
|
|
+
|
|
|
+ efi.systab = NULL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We don't do virtual mode, since we don't do runtime services, on
|
|
|
+ * non-native EFI
|
|
|
+ */
|
|
|
+ if (!efi_is_native()) {
|
|
|
+ efi_unmap_memmap();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Map efi regions which were passed via setup_data. The virt_addr is a
|
|
|
+ * fixed addr which was used in first kernel of a kexec boot.
|
|
|
+ */
|
|
|
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
|
|
+ md = p;
|
|
|
+ efi_map_region_fixed(md); /* FIXME: add error handling */
|
|
|
+ get_systab_virt_addr(md);
|
|
|
+ }
|
|
|
+
|
|
|
+ save_runtime_map();
|
|
|
+
|
|
|
+ BUG_ON(!efi.systab);
|
|
|
+
|
|
|
+ efi_sync_low_kernel_mappings();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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.hdr.revision;
|
|
|
+ efi.get_time = virt_efi_get_time;
|
|
|
+ efi.set_time = virt_efi_set_time;
|
|
|
+ efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
|
|
+ efi.set_wakeup_time = virt_efi_set_wakeup_time;
|
|
|
+ efi.get_variable = virt_efi_get_variable;
|
|
|
+ efi.get_next_variable = virt_efi_get_next_variable;
|
|
|
+ efi.set_variable = virt_efi_set_variable;
|
|
|
+ efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
|
|
|
+ efi.reset_system = virt_efi_reset_system;
|
|
|
+ efi.set_virtual_address_map = NULL;
|
|
|
+ efi.query_variable_info = virt_efi_query_variable_info;
|
|
|
+ efi.update_capsule = virt_efi_update_capsule;
|
|
|
+ efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
|
|
+
|
|
|
+ if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
|
|
|
+ runtime_code_page_mkexec();
|
|
|
+
|
|
|
+ /* clean DUMMY object */
|
|
|
+ efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
|
|
+ EFI_VARIABLE_NON_VOLATILE |
|
|
|
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
|
+ EFI_VARIABLE_RUNTIME_ACCESS,
|
|
|
+ 0, NULL);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This function will switch the EFI runtime services to virtual mode.
|
|
|
* Essentially, we look through the EFI memmap and map every region that
|
|
@@ -1008,11 +1059,12 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
|
|
|
*
|
|
|
* Specially for kexec boot, efi runtime maps in previous kernel should
|
|
|
* be passed in via setup_data. In that case runtime ranges will be mapped
|
|
|
- * to the same virtual addresses as the first kernel.
|
|
|
+ * to the same virtual addresses as the first kernel, see
|
|
|
+ * kexec_enter_virtual_mode().
|
|
|
*/
|
|
|
-void __init efi_enter_virtual_mode(void)
|
|
|
+static void __init __efi_enter_virtual_mode(void)
|
|
|
{
|
|
|
- int err, count = 0, pg_shift = 0;
|
|
|
+ int count = 0, pg_shift = 0;
|
|
|
void *new_memmap = NULL;
|
|
|
efi_status_t status;
|
|
|
|
|
@@ -1027,43 +1079,33 @@ void __init efi_enter_virtual_mode(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (efi_setup) {
|
|
|
- efi_map_regions_fixed();
|
|
|
- } else {
|
|
|
- efi_merge_regions();
|
|
|
- new_memmap = efi_map_regions(&count, &pg_shift);
|
|
|
- if (!new_memmap) {
|
|
|
- pr_err("Error reallocating memory, EFI runtime non-functional!\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- err = save_runtime_map();
|
|
|
- if (err)
|
|
|
- pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
|
|
|
+ efi_merge_regions();
|
|
|
+ new_memmap = efi_map_regions(&count, &pg_shift);
|
|
|
+ if (!new_memmap) {
|
|
|
+ pr_err("Error reallocating memory, EFI runtime non-functional!\n");
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
+ save_runtime_map();
|
|
|
+
|
|
|
BUG_ON(!efi.systab);
|
|
|
|
|
|
- if (!efi_setup) {
|
|
|
- if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
|
|
|
+ return;
|
|
|
|
|
|
efi_sync_low_kernel_mappings();
|
|
|
efi_dump_pagetable();
|
|
|
|
|
|
- if (!efi_setup) {
|
|
|
- status = phys_efi_set_virtual_address_map(
|
|
|
+ status = phys_efi_set_virtual_address_map(
|
|
|
memmap.desc_size * count,
|
|
|
memmap.desc_size,
|
|
|
memmap.desc_version,
|
|
|
(efi_memory_desc_t *)__pa(new_memmap));
|
|
|
|
|
|
- if (status != EFI_SUCCESS) {
|
|
|
- pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
|
|
|
- status);
|
|
|
- panic("EFI call to SetVirtualAddressMap() failed!");
|
|
|
- }
|
|
|
+ if (status != EFI_SUCCESS) {
|
|
|
+ pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
|
|
|
+ status);
|
|
|
+ panic("EFI call to SetVirtualAddressMap() failed!");
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1089,7 +1131,6 @@ void __init efi_enter_virtual_mode(void)
|
|
|
|
|
|
efi_runtime_mkexec();
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
* We mapped the descriptor array into the EFI pagetable above but we're
|
|
|
* not unmapping it here. Here's why:
|
|
@@ -1116,8 +1157,7 @@ void __init efi_enter_virtual_mode(void)
|
|
|
*
|
|
|
* efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift);
|
|
|
*/
|
|
|
- if (!efi_setup)
|
|
|
- free_pages((unsigned long)new_memmap, pg_shift);
|
|
|
+ free_pages((unsigned long)new_memmap, pg_shift);
|
|
|
|
|
|
/* clean DUMMY object */
|
|
|
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
|
@@ -1127,6 +1167,14 @@ void __init efi_enter_virtual_mode(void)
|
|
|
0, NULL);
|
|
|
}
|
|
|
|
|
|
+void __init efi_enter_virtual_mode(void)
|
|
|
+{
|
|
|
+ if (efi_setup)
|
|
|
+ kexec_enter_virtual_mode();
|
|
|
+ else
|
|
|
+ __efi_enter_virtual_mode();
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Convenience functions to obtain memory types and attributes
|
|
|
*/
|