diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-03-03 01:48:50 -0500 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2015-04-01 07:46:22 -0400 |
commit | 744937b0b12a669f298949c4a810794c59fead98 (patch) | |
tree | d7d4082f50f1b56a6844012aaf5ff95690686aa1 | |
parent | 23a0d4e8fa6d3a1d7fb819f79bcc0a3739c30ba9 (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.h | 6 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi.c | 5 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_32.c | 11 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_64.c | 26 |
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, | |||
89 | extern struct efi_scratch efi_scratch; | 91 | extern struct efi_scratch efi_scratch; |
90 | extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); | 92 | extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); |
91 | extern int __init efi_memblock_x86_reserve_range(void); | 93 | extern int __init efi_memblock_x86_reserve_range(void); |
92 | extern void __init efi_call_phys_prolog(void); | 94 | extern pgd_t * __init efi_call_phys_prolog(void); |
93 | extern void __init efi_call_phys_epilog(void); | 95 | extern void __init efi_call_phys_epilog(pgd_t *save_pgd); |
94 | extern void __init efi_unmap_memmap(void); | 96 | extern void __init efi_unmap_memmap(void); |
95 | extern void __init efi_memory_uc(u64 addr, unsigned long size); | 97 | extern void __init efi_memory_uc(u64 addr, unsigned long size); |
96 | extern void __init efi_map_region(efi_memory_desc_t *md); | 98 | extern 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) | |||
56 | void __init efi_map_region_fixed(efi_memory_desc_t *md) {} | 56 | void __init efi_map_region_fixed(efi_memory_desc_t *md) {} |
57 | void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} | 57 | void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} |
58 | 58 | ||
59 | void __init efi_call_phys_prolog(void) | 59 | pgd_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 | ||
71 | void __init efi_call_phys_epilog(void) | 76 | void __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 | ||
44 | static 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 | ||
80 | void __init efi_call_phys_prolog(void) | 78 | pgd_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 | ||
102 | void __init efi_call_phys_epilog(void) | 104 | void __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 | } |