Commit fabb37c7 authored by Borislav Petkov's avatar Borislav Petkov Committed by Matt Fleming

x86/efi: Split efi_enter_virtual_mode

... into a kexec flavor for better code readability and simplicity. The
original one was getting ugly with ifdeffery.
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Tested-by: default avatarToshi Kani <toshi.kani@hp.com>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
parent b7b898ae
...@@ -879,8 +879,9 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md) ...@@ -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; efi_memory_desc_t *md;
void *tmp, *p, *q = NULL; void *tmp, *p, *q = NULL;
int count = 0; int count = 0;
...@@ -902,28 +903,12 @@ static int __init save_runtime_map(void) ...@@ -902,28 +903,12 @@ static int __init save_runtime_map(void)
} }
efi_runtime_map_setup(q, count, memmap.desc_size); efi_runtime_map_setup(q, count, memmap.desc_size);
return;
return 0;
out: out:
kfree(q); kfree(q);
return -ENOMEM; pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
} #endif
/*
* 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);
}
} }
static void *realloc_pages(void *old_memmap, int old_shift) 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) ...@@ -989,6 +974,72 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
return new_memmap; 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. * This function will switch the EFI runtime services to virtual mode.
* Essentially, we look through the EFI memmap and map every region that * 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) ...@@ -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 * 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 * 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; void *new_memmap = NULL;
efi_status_t status; efi_status_t status;
...@@ -1027,9 +1079,6 @@ void __init efi_enter_virtual_mode(void) ...@@ -1027,9 +1079,6 @@ void __init efi_enter_virtual_mode(void)
return; return;
} }
if (efi_setup) {
efi_map_regions_fixed();
} else {
efi_merge_regions(); efi_merge_regions();
new_memmap = efi_map_regions(&count, &pg_shift); new_memmap = efi_map_regions(&count, &pg_shift);
if (!new_memmap) { if (!new_memmap) {
...@@ -1037,22 +1086,16 @@ void __init efi_enter_virtual_mode(void) ...@@ -1037,22 +1086,16 @@ void __init efi_enter_virtual_mode(void)
return; return;
} }
err = save_runtime_map(); save_runtime_map();
if (err)
pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
}
BUG_ON(!efi.systab); BUG_ON(!efi.systab);
if (!efi_setup) {
if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
return; return;
}
efi_sync_low_kernel_mappings(); efi_sync_low_kernel_mappings();
efi_dump_pagetable(); 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 * count,
memmap.desc_size, memmap.desc_size,
...@@ -1064,7 +1107,6 @@ void __init efi_enter_virtual_mode(void) ...@@ -1064,7 +1107,6 @@ void __init efi_enter_virtual_mode(void)
status); status);
panic("EFI call to SetVirtualAddressMap() failed!"); panic("EFI call to SetVirtualAddressMap() failed!");
} }
}
/* /*
* Now that EFI is in virtual mode, update the function * Now that EFI is in virtual mode, update the function
...@@ -1089,7 +1131,6 @@ void __init efi_enter_virtual_mode(void) ...@@ -1089,7 +1131,6 @@ void __init efi_enter_virtual_mode(void)
efi_runtime_mkexec(); efi_runtime_mkexec();
/* /*
* We mapped the descriptor array into the EFI pagetable above but we're * We mapped the descriptor array into the EFI pagetable above but we're
* not unmapping it here. Here's why: * not unmapping it here. Here's why:
...@@ -1116,7 +1157,6 @@ void __init efi_enter_virtual_mode(void) ...@@ -1116,7 +1157,6 @@ void __init efi_enter_virtual_mode(void)
* *
* efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift); * 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 */ /* clean DUMMY object */
...@@ -1127,6 +1167,14 @@ void __init efi_enter_virtual_mode(void) ...@@ -1127,6 +1167,14 @@ void __init efi_enter_virtual_mode(void)
0, NULL); 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 * Convenience functions to obtain memory types and attributes
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment