aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-03-03 01:48:50 -0500
committerMatt Fleming <matt.fleming@intel.com>2015-04-01 07:46:22 -0400
commit744937b0b12a669f298949c4a810794c59fead98 (patch)
treed7d4082f50f1b56a6844012aaf5ff95690686aa1
parent23a0d4e8fa6d3a1d7fb819f79bcc0a3739c30ba9 (diff)
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: Ingo Molnar <mingo@kernel.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/x86/include/asm/efi.h6
-rw-r--r--arch/x86/platform/efi/efi.c5
-rw-r--r--arch/x86/platform/efi/efi_32.c11
-rw-r--r--arch/x86/platform/efi/efi_64.c26
4 files changed, 31 insertions, 17 deletions
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 25bce45c6fc4..3738b138b843 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -2,6 +2,8 @@
2#define _ASM_X86_EFI_H 2#define _ASM_X86_EFI_H
3 3
4#include <asm/i387.h> 4#include <asm/i387.h>
5#include <asm/pgtable.h>
6
5/* 7/*
6 * We map the EFI regions needed for runtime services non-contiguously, 8 * We map the EFI regions needed for runtime services non-contiguously,
7 * with preserved alignment on virtual addresses starting from -4G down 9 * 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,
89extern struct efi_scratch efi_scratch; 91extern struct efi_scratch efi_scratch;
90extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); 92extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
91extern int __init efi_memblock_x86_reserve_range(void); 93extern int __init efi_memblock_x86_reserve_range(void);
92extern void __init efi_call_phys_prolog(void); 94extern pgd_t * __init efi_call_phys_prolog(void);
93extern void __init efi_call_phys_epilog(void); 95extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
94extern void __init efi_unmap_memmap(void); 96extern void __init efi_unmap_memmap(void);
95extern void __init efi_memory_uc(u64 addr, unsigned long size); 97extern void __init efi_memory_uc(u64 addr, unsigned long size);
96extern void __init efi_map_region(efi_memory_desc_t *md); 98extern void __init efi_map_region(efi_memory_desc_t *md);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index e7a01e32db95..02744df576d5 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -86,8 +86,9 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
86{ 86{
87 efi_status_t status; 87 efi_status_t status;
88 unsigned long flags; 88 unsigned long flags;
89 pgd_t *save_pgd;
89 90
90 efi_call_phys_prolog(); 91 save_pgd = efi_call_phys_prolog();
91 92
92 /* Disable interrupts around EFI calls: */ 93 /* Disable interrupts around EFI calls: */
93 local_irq_save(flags); 94 local_irq_save(flags);
@@ -96,7 +97,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
96 descriptor_version, virtual_map); 97 descriptor_version, virtual_map);
97 local_irq_restore(flags); 98 local_irq_restore(flags);
98 99
99 efi_call_phys_epilog(); 100 efi_call_phys_epilog(save_pgd);
100 101
101 return status; 102 return status;
102} 103}
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index abecc6e1dc90..ed5b67338294 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -56,19 +56,24 @@ void __init efi_map_region(efi_memory_desc_t *md)
56void __init efi_map_region_fixed(efi_memory_desc_t *md) {} 56void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
57void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} 57void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
58 58
59void __init efi_call_phys_prolog(void) 59pgd_t * __init efi_call_phys_prolog(void)
60{ 60{
61 struct desc_ptr gdt_descr; 61 struct desc_ptr gdt_descr;
62 pgd_t *save_pgd;
62 63
64 /* Current pgd is swapper_pg_dir, we'll restore it later: */
65 save_pgd = swapper_pg_dir;
63 load_cr3(initial_page_table); 66 load_cr3(initial_page_table);
64 __flush_tlb_all(); 67 __flush_tlb_all();
65 68
66 gdt_descr.address = __pa(get_cpu_gdt_table(0)); 69 gdt_descr.address = __pa(get_cpu_gdt_table(0));
67 gdt_descr.size = GDT_SIZE - 1; 70 gdt_descr.size = GDT_SIZE - 1;
68 load_gdt(&gdt_descr); 71 load_gdt(&gdt_descr);
72
73 return save_pgd;
69} 74}
70 75
71void __init efi_call_phys_epilog(void) 76void __init efi_call_phys_epilog(pgd_t *save_pgd)
72{ 77{
73 struct desc_ptr gdt_descr; 78 struct desc_ptr gdt_descr;
74 79
@@ -76,7 +81,7 @@ void __init efi_call_phys_epilog(void)
76 gdt_descr.size = GDT_SIZE - 1; 81 gdt_descr.size = GDT_SIZE - 1;
77 load_gdt(&gdt_descr); 82 load_gdt(&gdt_descr);
78 83
79 load_cr3(swapper_pg_dir); 84 load_cr3(save_pgd);
80 __flush_tlb_all(); 85 __flush_tlb_all();
81} 86}
82 87
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 427eb3540e5f..a0ac0f9c307f 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -41,8 +41,6 @@
41#include <asm/realmode.h> 41#include <asm/realmode.h>
42#include <asm/time.h> 42#include <asm/time.h>
43 43
44static pgd_t *save_pgd __initdata;
45
46/* 44/*
47 * We allocate runtime services regions bottom-up, starting from -4G, i.e. 45 * We allocate runtime services regions bottom-up, starting from -4G, i.e.
48 * 0xffff_ffff_0000_0000 and limit EFI VA mapping space to 64G. 46 * 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 } 75 }
78} 76}
79 77
80void __init efi_call_phys_prolog(void) 78pgd_t * __init efi_call_phys_prolog(void)
81{ 79{
82 unsigned long vaddress; 80 unsigned long vaddress;
81 pgd_t *save_pgd;
82
83 int pgd; 83 int pgd;
84 int n_pgds; 84 int n_pgds;
85 85
86 if (!efi_enabled(EFI_OLD_MEMMAP)) 86 if (!efi_enabled(EFI_OLD_MEMMAP))
87 return; 87 return NULL;
88 88
89 early_code_mapping_set_exec(1); 89 early_code_mapping_set_exec(1);
90 90
@@ -97,22 +97,28 @@ void __init efi_call_phys_prolog(void)
97 set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress)); 97 set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress));
98 } 98 }
99 __flush_tlb_all(); 99 __flush_tlb_all();
100
101 return save_pgd;
100} 102}
101 103
102void __init efi_call_phys_epilog(void) 104void __init efi_call_phys_epilog(pgd_t *save_pgd)
103{ 105{
104 /* 106 /*
105 * After the lock is released, the original page table is restored. 107 * After the lock is released, the original page table is restored.
106 */ 108 */
107 int pgd; 109 int pgd_idx;
108 int n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE); 110 int nr_pgds;
109 111
110 if (!efi_enabled(EFI_OLD_MEMMAP)) 112 if (!save_pgd)
111 return; 113 return;
112 114
113 for (pgd = 0; pgd < n_pgds; pgd++) 115 nr_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
114 set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]); 116
117 for (pgd_idx = 0; pgd_idx < nr_pgds; pgd_idx++)
118 set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]);
119
115 kfree(save_pgd); 120 kfree(save_pgd);
121
116 __flush_tlb_all(); 122 __flush_tlb_all();
117 early_code_mapping_set_exec(0); 123 early_code_mapping_set_exec(0);
118} 124}