Commit 744937b0 authored by Ingo Molnar's avatar Ingo Molnar Committed by Matt Fleming

efi: Clean up the efi_call_phys_[prolog|epilog]() save/restore interaction

Currently x86-64 efi_call_phys_prolog() saves into a global variable (save_pgd),
and efi_call_phys_epilog() restores the kernel pagetables from that global
variable.

Change this to a cleaner save/restore pattern where the saving function returns
the saved object and the restore function restores that.

Apply the same concept to the 32-bit code as well.

Plus this approach, as an added bonus, allows us to express the
!efi_enabled(EFI_OLD_MEMMAP) situation in a clean fashion as well,
via a 'NULL' return value.

Cc: Tapasweni Pathak <tapaswenipathak@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
parent 23a0d4e8
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#define _ASM_X86_EFI_H #define _ASM_X86_EFI_H
#include <asm/i387.h> #include <asm/i387.h>
#include <asm/pgtable.h>
/* /*
* We map the EFI regions needed for runtime services non-contiguously, * We map the EFI regions needed for runtime services non-contiguously,
* with preserved alignment on virtual addresses starting from -4G down * with preserved alignment on virtual addresses starting from -4G down
...@@ -89,8 +91,8 @@ extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size, ...@@ -89,8 +91,8 @@ extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size,
extern struct efi_scratch efi_scratch; extern struct efi_scratch efi_scratch;
extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
extern int __init efi_memblock_x86_reserve_range(void); extern int __init efi_memblock_x86_reserve_range(void);
extern void __init efi_call_phys_prolog(void); extern pgd_t * __init efi_call_phys_prolog(void);
extern void __init efi_call_phys_epilog(void); extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
extern void __init efi_unmap_memmap(void); extern void __init efi_unmap_memmap(void);
extern void __init efi_memory_uc(u64 addr, unsigned long size); extern void __init efi_memory_uc(u64 addr, unsigned long size);
extern void __init efi_map_region(efi_memory_desc_t *md); extern void __init efi_map_region(efi_memory_desc_t *md);
......
...@@ -86,8 +86,9 @@ static efi_status_t __init phys_efi_set_virtual_address_map( ...@@ -86,8 +86,9 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
{ {
efi_status_t status; efi_status_t status;
unsigned long flags; unsigned long flags;
pgd_t *save_pgd;
efi_call_phys_prolog(); save_pgd = efi_call_phys_prolog();
/* Disable interrupts around EFI calls: */ /* Disable interrupts around EFI calls: */
local_irq_save(flags); local_irq_save(flags);
...@@ -96,7 +97,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map( ...@@ -96,7 +97,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
descriptor_version, virtual_map); descriptor_version, virtual_map);
local_irq_restore(flags); local_irq_restore(flags);
efi_call_phys_epilog(); efi_call_phys_epilog(save_pgd);
return status; return status;
} }
......
...@@ -56,19 +56,24 @@ void __init efi_map_region(efi_memory_desc_t *md) ...@@ -56,19 +56,24 @@ void __init efi_map_region(efi_memory_desc_t *md)
void __init efi_map_region_fixed(efi_memory_desc_t *md) {} void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
void __init efi_call_phys_prolog(void) pgd_t * __init efi_call_phys_prolog(void)
{ {
struct desc_ptr gdt_descr; struct desc_ptr gdt_descr;
pgd_t *save_pgd;
/* Current pgd is swapper_pg_dir, we'll restore it later: */
save_pgd = swapper_pg_dir;
load_cr3(initial_page_table); load_cr3(initial_page_table);
__flush_tlb_all(); __flush_tlb_all();
gdt_descr.address = __pa(get_cpu_gdt_table(0)); gdt_descr.address = __pa(get_cpu_gdt_table(0));
gdt_descr.size = GDT_SIZE - 1; gdt_descr.size = GDT_SIZE - 1;
load_gdt(&gdt_descr); load_gdt(&gdt_descr);
return save_pgd;
} }
void __init efi_call_phys_epilog(void) void __init efi_call_phys_epilog(pgd_t *save_pgd)
{ {
struct desc_ptr gdt_descr; struct desc_ptr gdt_descr;
...@@ -76,7 +81,7 @@ void __init efi_call_phys_epilog(void) ...@@ -76,7 +81,7 @@ void __init efi_call_phys_epilog(void)
gdt_descr.size = GDT_SIZE - 1; gdt_descr.size = GDT_SIZE - 1;
load_gdt(&gdt_descr); load_gdt(&gdt_descr);
load_cr3(swapper_pg_dir); load_cr3(save_pgd);
__flush_tlb_all(); __flush_tlb_all();
} }
......
...@@ -41,8 +41,6 @@ ...@@ -41,8 +41,6 @@
#include <asm/realmode.h> #include <asm/realmode.h>
#include <asm/time.h> #include <asm/time.h>
static pgd_t *save_pgd __initdata;
/* /*
* We allocate runtime services regions bottom-up, starting from -4G, i.e. * We allocate runtime services regions bottom-up, starting from -4G, i.e.
* 0xffff_ffff_0000_0000 and limit EFI VA mapping space to 64G. * 0xffff_ffff_0000_0000 and limit EFI VA mapping space to 64G.
...@@ -77,14 +75,16 @@ static void __init early_code_mapping_set_exec(int executable) ...@@ -77,14 +75,16 @@ static void __init early_code_mapping_set_exec(int executable)
} }
} }
void __init efi_call_phys_prolog(void) pgd_t * __init efi_call_phys_prolog(void)
{ {
unsigned long vaddress; unsigned long vaddress;
pgd_t *save_pgd;
int pgd; int pgd;
int n_pgds; int n_pgds;
if (!efi_enabled(EFI_OLD_MEMMAP)) if (!efi_enabled(EFI_OLD_MEMMAP))
return; return NULL;
early_code_mapping_set_exec(1); early_code_mapping_set_exec(1);
...@@ -97,22 +97,28 @@ void __init efi_call_phys_prolog(void) ...@@ -97,22 +97,28 @@ void __init efi_call_phys_prolog(void)
set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress)); set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress));
} }
__flush_tlb_all(); __flush_tlb_all();
return save_pgd;
} }
void __init efi_call_phys_epilog(void) void __init efi_call_phys_epilog(pgd_t *save_pgd)
{ {
/* /*
* After the lock is released, the original page table is restored. * After the lock is released, the original page table is restored.
*/ */
int pgd; int pgd_idx;
int n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE); int nr_pgds;
if (!efi_enabled(EFI_OLD_MEMMAP)) if (!save_pgd)
return; return;
for (pgd = 0; pgd < n_pgds; pgd++) nr_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]);
for (pgd_idx = 0; pgd_idx < nr_pgds; pgd_idx++)
set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]);
kfree(save_pgd); kfree(save_pgd);
__flush_tlb_all(); __flush_tlb_all();
early_code_mapping_set_exec(0); early_code_mapping_set_exec(0);
} }
......
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