History

efi: Add 'runtime' pointer to struct efi

Instead of going through the EFI system table each time, just copy the runtime services table pointer into struct efi directly. This is the last use of the system table pointer in struct efi, allowing us to drop it in a future patch, along with a fair amount of quirky handling of the translated address. Note that usually, the runtime services pointer changes value during the call to SetVirtualAddressMap(), so grab the updated value as soon as that call returns. (Mixed mode uses a 1:1 mapping, and kexec boot enters with the updated address in the system table, so in those cases, we don't need to do anything here)

Ard Biesheuvel committed 6 years ago

Commit 59f2a611 parent 09308019 files · +49 −22Browse files

Unified · Split

9 files
  1. arch/x86/include/asm/efi.h +2 −1
  2. arch/x86/kernel/asm-offsets_32.c +5 −0
  3. arch/x86/platform/efi/efi.c +6 −3
  4. arch/x86/platform/efi/efi_32.c +8 −5
  5. arch/x86/platform/efi/efi_64.c +8 −6
  6. arch/x86/platform/efi/efi_stub_32.S +16 −5
  7. drivers/firmware/efi/arm-init.c +1 −0
  8. drivers/firmware/efi/runtime-wrappers.c +2 −2
  9. include/linux/efi.h +1 −0
arch/x86/include/asm/efi.h+2−1
@@ -218,7 +218,8 @@ extern void efi_thunk_runtime_setup(void); · 217 unmodified lines
218218 efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
219219 unsigned long descriptor_size,
220220 u32 descriptor_version,
221− efi_memory_desc_t *virtual_map);
221+ efi_memory_desc_t *virtual_map,
222+ unsigned long systab_phys);
222223
223224 /* arch specific definitions used by the stub code */
224225
arch/x86/kernel/asm-offsets_32.c+5−0
@@ -3,6 +3,8 @@ · 2 unmodified lines
33 # error "Please do not build this file directly, build asm-offsets.c instead"
44 #endif
55
6+#include <linux/efi.h>
7+
68 #include <asm/ucontext.h>
79
810 #define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
@@ -64,4 +66,7 @@ void foo(void) · 55 unmodified lines
6466 BLANK();
6567 DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
6668 DEFINE(NR_syscalls, sizeof(syscalls));
69+
70+ BLANK();
71+ DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
6772 }
arch/x86/platform/efi/efi.c+6−3
@@ -55,8 +55,8 @@ · 54 unmodified lines
5555 #include <asm/uv/uv.h>
5656
5757 static efi_system_table_t efi_systab __initdata;
58−static u64 efi_systab_phys __initdata;
5958
59+static unsigned long efi_systab_phys __initdata;
6060 static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;
6161 static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;
6262 static unsigned long efi_runtime, efi_nr_tables;
@@ -335,7 +335,7 @@ void __init efi_print_memmap(void) · 272 unmodified lines
335335 }
336336 }
337337
338−static int __init efi_systab_init(u64 phys)
338+static int __init efi_systab_init(unsigned long phys)
339339 {
340340 int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
341341 : sizeof(efi_system_table_32_t);
@@ -949,7 +949,8 @@ static void __init __efi_enter_virtual_mode(void) · 607 unmodified lines
949949 status = efi_set_virtual_address_map(efi.memmap.desc_size * count,
950950 efi.memmap.desc_size,
951951 efi.memmap.desc_version,
952− (efi_memory_desc_t *)pa);
952+ (efi_memory_desc_t *)pa,
953+ efi_systab_phys);
953954 if (status != EFI_SUCCESS) {
954955 pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
955956 status);
@@ -983,6 +984,8 @@ void __init efi_enter_virtual_mode(void) · 27 unmodified lines
983984 if (efi_enabled(EFI_PARAVIRT))
984985 return;
985986
987+ efi.runtime = (efi_runtime_services_t *)efi_runtime;
988+
986989 if (efi_setup)
987990 kexec_enter_virtual_mode();
988991 else
arch/x86/platform/efi/efi_32.c+8−5
@@ -66,14 +66,16 @@ void __init efi_map_region(efi_memory_desc_t *md) · 65 unmodified lines
6666 void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
6767 void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
6868
69−efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *,
70− u32, u32, u32, void *);
69+efi_status_t efi_call_svam(efi_runtime_services_t * const *,
70+ u32, u32, u32, void *, u32);
7171
7272 efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
7373 unsigned long descriptor_size,
7474 u32 descriptor_version,
75− efi_memory_desc_t *virtual_map)
75+ efi_memory_desc_t *virtual_map,
76+ unsigned long systab_phys)
7677 {
78+ const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
7779 struct desc_ptr gdt_descr;
7880 efi_status_t status;
7981 unsigned long flags;
@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size, · 10 unmodified lines
9092
9193 /* Disable interrupts around EFI calls: */
9294 local_irq_save(flags);
93− status = efi_call_svam(&efi.systab->runtime->set_virtual_address_map,
95+ status = efi_call_svam(&systab->runtime,
9496 memory_map_size, descriptor_size,
95− descriptor_version, virtual_map);
97+ descriptor_version, virtual_map,
98+ __pa(&efi.runtime));
9699 local_irq_restore(flags);
97100
98101 load_fixmap_gdt(0);
arch/x86/platform/efi/efi_64.c+8−6
@@ -500,12 +500,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock); · 499 unmodified lines
500500 */
501501 #define __efi_thunk(func, ...) \
502502 ({ \
503− efi_runtime_services_32_t *__rt; \
504503 unsigned short __ds, __es; \
505504 efi_status_t ____s; \
506505 \
507− __rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime; \
508− \
509506 savesegment(ds, __ds); \
510507 savesegment(es, __es); \
511508 \
@@ -513,7 +510,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock); · 1 unmodified line
513510 loadsegment(ds, __KERNEL_DS); \
514511 loadsegment(es, __KERNEL_DS); \
515512 \
516− ____s = efi64_thunk(__rt->func, __VA_ARGS__); \
513+ ____s = efi64_thunk(efi.runtime->mixed_mode.func, __VA_ARGS__); \
517514 \
518515 loadsegment(ds, __ds); \
519516 loadsegment(es, __es); \
@@ -886,8 +883,10 @@ efi_status_t __init __no_sanitize_address · 366 unmodified lines
886883 efi_set_virtual_address_map(unsigned long memory_map_size,
887884 unsigned long descriptor_size,
888885 u32 descriptor_version,
889− efi_memory_desc_t *virtual_map)
886+ efi_memory_desc_t *virtual_map,
887+ unsigned long systab_phys)
890888 {
889+ const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
891890 efi_status_t status;
892891 unsigned long flags;
893892 pgd_t *save_pgd = NULL;
@@ -910,13 +909,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size, · 16 unmodified lines
910909
911910 /* Disable interrupts around EFI calls: */
912911 local_irq_save(flags);
913− status = efi_call(efi.systab->runtime->set_virtual_address_map,
912+ status = efi_call(efi.runtime->set_virtual_address_map,
914913 memory_map_size, descriptor_size,
915914 descriptor_version, virtual_map);
916915 local_irq_restore(flags);
917916
918917 kernel_fpu_end();
919918
919+ /* grab the virtually remapped EFI runtime services table pointer */
920+ efi.runtime = READ_ONCE(systab->runtime);
921+
920922 if (save_pgd)
921923 efi_uv1_memmap_phys_epilog(save_pgd);
922924 else
arch/x86/platform/efi/efi_stub_32.S+16−5
@@ -8,14 +8,20 @@ · 7 unmodified lines
88
99 #include <linux/linkage.h>
1010 #include <linux/init.h>
11+#include <asm/asm-offsets.h>
1112 #include <asm/page_types.h>
1213
1314 __INIT
1415 SYM_FUNC_START(efi_call_svam)
15− push 8(%esp)
16− push 8(%esp)
16+ push %ebp
17+ movl %esp, %ebp
18+ push %ebx
19+
20+ push 16(%esp)
21+ push 16(%esp)
1722 push %ecx
1823 push %edx
24+ movl %eax, %ebx // &systab_phys->runtime
1925
2026 /*
2127 * Switch to the flat mapped alias of this routine, by jumping to the
@@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam) · 13 unmodified lines
3541 subl $__PAGE_OFFSET, %esp
3642
3743 /* call the EFI routine */
38− call *(%eax)
44+ movl (%eax), %eax
45+ call *EFI_svam(%eax)
3946
40− /* convert ESP back to a kernel VA, and pop the outgoing args */
41− addl $__PAGE_OFFSET + 16, %esp
47+ /* grab the virtually remapped EFI runtime services table pointer */
48+ movl (%ebx), %ecx
49+ movl 36(%esp), %edx // &efi.runtime
50+ movl %ecx, (%edx)
4251
4352 /* re-enable paging */
4453 movl %cr0, %edx
4554 orl $0x80000000, %edx
4655 movl %edx, %cr0
4756
57+ pop %ebx
58+ leave
4859 ret
4960 SYM_FUNC_END(efi_call_svam)
drivers/firmware/efi/arm-init.c+1−0
@@ -104,6 +104,7 @@ static int __init uefi_init(void) · 103 unmodified lines
104104 if (retval)
105105 goto out;
106106
107+ efi.runtime = efi.systab->runtime;
107108 efi.runtime_version = efi.systab->hdr.revision;
108109
109110 efi_systab_report_header(&efi.systab->hdr,
drivers/firmware/efi/runtime-wrappers.c+2−2
@@ -40,9 +40,9 @@ · 39 unmodified lines
4040 * code doesn't get too cluttered:
4141 */
4242 #define efi_call_virt(f, args...) \
43− efi_call_virt_pointer(efi.systab->runtime, f, args)
43+ efi_call_virt_pointer(efi.runtime, f, args)
4444 #define __efi_call_virt(f, args...) \
45− __efi_call_virt_pointer(efi.systab->runtime, f, args)
45+ __efi_call_virt_pointer(efi.runtime, f, args)
4646
4747 struct efi_runtime_work efi_rts_work;
4848
include/linux/efi.h+1−0
@@ -529,6 +529,7 @@ typedef struct { · 528 unmodified lines
529529 * All runtime access to EFI goes through this structure:
530530 */
531531 extern struct efi {
532+ const efi_runtime_services_t *runtime; /* EFI runtime services table */
532533 efi_system_table_t *systab; /* EFI system table */
533534 unsigned int runtime_version; /* Runtime services version */
534535 unsigned long acpi; /* ACPI table (IA64 ext 0.71) */