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
218efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,218efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
219 unsigned long descriptor_size,219 unsigned long descriptor_size,
220 u32 descriptor_version,220 u32 descriptor_version,
221 efi_memory_desc_t *virtual_map);221 efi_memory_desc_t *virtual_map,
222 unsigned long systab_phys);
222 223
223/* arch specific definitions used by the stub code */224/* arch specific definitions used by the stub code */
224 225
arch/x86/kernel/asm-offsets_32.c+5−0
@@ -3,6 +3,8 @@ · 2 unmodified lines
3# error "Please do not build this file directly, build asm-offsets.c instead"3# error "Please do not build this file directly, build asm-offsets.c instead"
4#endif4#endif
5 5
6#include <linux/efi.h>
7
6#include <asm/ucontext.h>8#include <asm/ucontext.h>
7 9
8#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,10#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
@@ -64,4 +66,7 @@ void foo(void) · 55 unmodified lines
64 BLANK();66 BLANK();
65 DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);67 DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
66 DEFINE(NR_syscalls, sizeof(syscalls));68 DEFINE(NR_syscalls, sizeof(syscalls));
69
70 BLANK();
71 DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
67}72}
arch/x86/platform/efi/efi.c+6−3
@@ -55,8 +55,8 @@ · 54 unmodified lines
55#include <asm/uv/uv.h>55#include <asm/uv/uv.h>
56 56
57static efi_system_table_t efi_systab __initdata;57static efi_system_table_t efi_systab __initdata;
58static u64 efi_systab_phys __initdata;
59 58
59static unsigned long efi_systab_phys __initdata;
60static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;60static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;
61static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;61static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;
62static unsigned long efi_runtime, efi_nr_tables;62static unsigned long efi_runtime, efi_nr_tables;
@@ -335,7 +335,7 @@ void __init efi_print_memmap(void) · 272 unmodified lines
335 }335 }
336}336}
337 337
338static int __init efi_systab_init(u64 phys)338static int __init efi_systab_init(unsigned long phys)
339{339{
340 int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)340 int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
341 : sizeof(efi_system_table_32_t);341 : sizeof(efi_system_table_32_t);
@@ -949,7 +949,8 @@ static void __init __efi_enter_virtual_mode(void) · 607 unmodified lines
949 status = efi_set_virtual_address_map(efi.memmap.desc_size * count,949 status = efi_set_virtual_address_map(efi.memmap.desc_size * count,
950 efi.memmap.desc_size,950 efi.memmap.desc_size,
951 efi.memmap.desc_version,951 efi.memmap.desc_version,
952 (efi_memory_desc_t *)pa);952 (efi_memory_desc_t *)pa,
953 efi_systab_phys);
953 if (status != EFI_SUCCESS) {954 if (status != EFI_SUCCESS) {
954 pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",955 pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
955 status);956 status);
@@ -983,6 +984,8 @@ void __init efi_enter_virtual_mode(void) · 27 unmodified lines
983 if (efi_enabled(EFI_PARAVIRT))984 if (efi_enabled(EFI_PARAVIRT))
984 return;985 return;
985 986
987 efi.runtime = (efi_runtime_services_t *)efi_runtime;
988
986 if (efi_setup)989 if (efi_setup)
987 kexec_enter_virtual_mode();990 kexec_enter_virtual_mode();
988 else991 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
66void __init efi_map_region_fixed(efi_memory_desc_t *md) {}66void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
67void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}67void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
68 68
69efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *,69efi_status_t efi_call_svam(efi_runtime_services_t * const *,
70 u32, u32, u32, void *);70 u32, u32, u32, void *, u32);
71 71
72efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,72efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
73 unsigned long descriptor_size,73 unsigned long descriptor_size,
74 u32 descriptor_version,74 u32 descriptor_version,
75 efi_memory_desc_t *virtual_map)75 efi_memory_desc_t *virtual_map,
76 unsigned long systab_phys)
76{77{
78 const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
77 struct desc_ptr gdt_descr;79 struct desc_ptr gdt_descr;
78 efi_status_t status;80 efi_status_t status;
79 unsigned long flags;81 unsigned long flags;
@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size, · 10 unmodified lines
90 92
91 /* Disable interrupts around EFI calls: */93 /* Disable interrupts around EFI calls: */
92 local_irq_save(flags);94 local_irq_save(flags);
93 status = efi_call_svam(&efi.systab->runtime->set_virtual_address_map,95 status = efi_call_svam(&systab->runtime,
94 memory_map_size, descriptor_size,96 memory_map_size, descriptor_size,
95 descriptor_version, virtual_map);97 descriptor_version, virtual_map,
98 __pa(&efi.runtime));
96 local_irq_restore(flags);99 local_irq_restore(flags);
97 100
98 load_fixmap_gdt(0);101 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
500 */500 */
501#define __efi_thunk(func, ...) \501#define __efi_thunk(func, ...) \
502({ \502({ \
503 efi_runtime_services_32_t *__rt; \
504 unsigned short __ds, __es; \503 unsigned short __ds, __es; \
505 efi_status_t ____s; \504 efi_status_t ____s; \
506 \505 \
507 __rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime; \
508 \
509 savesegment(ds, __ds); \506 savesegment(ds, __ds); \
510 savesegment(es, __es); \507 savesegment(es, __es); \
511 \508 \
@@ -513,7 +510,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock); · 1 unmodified line
513 loadsegment(ds, __KERNEL_DS); \510 loadsegment(ds, __KERNEL_DS); \
514 loadsegment(es, __KERNEL_DS); \511 loadsegment(es, __KERNEL_DS); \
515 \512 \
516 ____s = efi64_thunk(__rt->func, __VA_ARGS__); \513 ____s = efi64_thunk(efi.runtime->mixed_mode.func, __VA_ARGS__); \
517 \514 \
518 loadsegment(ds, __ds); \515 loadsegment(ds, __ds); \
519 loadsegment(es, __es); \516 loadsegment(es, __es); \
@@ -886,8 +883,10 @@ efi_status_t __init __no_sanitize_address · 366 unmodified lines
886efi_set_virtual_address_map(unsigned long memory_map_size,883efi_set_virtual_address_map(unsigned long memory_map_size,
887 unsigned long descriptor_size,884 unsigned long descriptor_size,
888 u32 descriptor_version,885 u32 descriptor_version,
889 efi_memory_desc_t *virtual_map)886 efi_memory_desc_t *virtual_map,
887 unsigned long systab_phys)
890{888{
889 const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
891 efi_status_t status;890 efi_status_t status;
892 unsigned long flags;891 unsigned long flags;
893 pgd_t *save_pgd = NULL;892 pgd_t *save_pgd = NULL;
@@ -910,13 +909,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size, · 16 unmodified lines
910 909
911 /* Disable interrupts around EFI calls: */910 /* Disable interrupts around EFI calls: */
912 local_irq_save(flags);911 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,
914 memory_map_size, descriptor_size,913 memory_map_size, descriptor_size,
915 descriptor_version, virtual_map);914 descriptor_version, virtual_map);
916 local_irq_restore(flags);915 local_irq_restore(flags);
917 916
918 kernel_fpu_end();917 kernel_fpu_end();
919 918
919 /* grab the virtually remapped EFI runtime services table pointer */
920 efi.runtime = READ_ONCE(systab->runtime);
921
920 if (save_pgd)922 if (save_pgd)
921 efi_uv1_memmap_phys_epilog(save_pgd);923 efi_uv1_memmap_phys_epilog(save_pgd);
922 else924 else
arch/x86/platform/efi/efi_stub_32.S+16−5
@@ -8,14 +8,20 @@ · 7 unmodified lines
8 8
9#include <linux/linkage.h>9#include <linux/linkage.h>
10#include <linux/init.h>10#include <linux/init.h>
11#include <asm/asm-offsets.h>
11#include <asm/page_types.h>12#include <asm/page_types.h>
12 13
13 __INIT14 __INIT
14SYM_FUNC_START(efi_call_svam)15SYM_FUNC_START(efi_call_svam)
15 push 8(%esp)16 push %ebp
16 push 8(%esp)17 movl %esp, %ebp
18 push %ebx
19
20 push 16(%esp)
21 push 16(%esp)
17 push %ecx22 push %ecx
18 push %edx23 push %edx
24 movl %eax, %ebx // &systab_phys->runtime
19 25
20 /*26 /*
21 * Switch to the flat mapped alias of this routine, by jumping to the27 * 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
35 subl $__PAGE_OFFSET, %esp41 subl $__PAGE_OFFSET, %esp
36 42
37 /* call the EFI routine */43 /* call the EFI routine */
38 call *(%eax)44 movl (%eax), %eax
45 call *EFI_svam(%eax)
39 46
40 /* convert ESP back to a kernel VA, and pop the outgoing args */47 /* grab the virtually remapped EFI runtime services table pointer */
41 addl $__PAGE_OFFSET + 16, %esp48 movl (%ebx), %ecx
49 movl 36(%esp), %edx // &efi.runtime
50 movl %ecx, (%edx)
42 51
43 /* re-enable paging */52 /* re-enable paging */
44 movl %cr0, %edx53 movl %cr0, %edx
45 orl $0x80000000, %edx54 orl $0x80000000, %edx
46 movl %edx, %cr055 movl %edx, %cr0
47 56
57 pop %ebx
58 leave
48 ret59 ret
49SYM_FUNC_END(efi_call_svam)60SYM_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
104 if (retval)104 if (retval)
105 goto out;105 goto out;
106 106
107 efi.runtime = efi.systab->runtime;
107 efi.runtime_version = efi.systab->hdr.revision;108 efi.runtime_version = efi.systab->hdr.revision;
108 109
109 efi_systab_report_header(&efi.systab->hdr,110 efi_systab_report_header(&efi.systab->hdr,
drivers/firmware/efi/runtime-wrappers.c+2−2
@@ -40,9 +40,9 @@ · 39 unmodified lines
40 * code doesn't get too cluttered:40 * code doesn't get too cluttered:
41 */41 */
42#define efi_call_virt(f, args...) \42#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)
44#define __efi_call_virt(f, args...) \44#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)
46 46
47struct efi_runtime_work efi_rts_work;47struct efi_runtime_work efi_rts_work;
48 48
include/linux/efi.h+1−0
@@ -529,6 +529,7 @@ typedef struct { · 528 unmodified lines
529 * All runtime access to EFI goes through this structure:529 * All runtime access to EFI goes through this structure:
530 */530 */
531extern struct efi {531extern struct efi {
532 const efi_runtime_services_t *runtime; /* EFI runtime services table */
532 efi_system_table_t *systab; /* EFI system table */533 efi_system_table_t *systab; /* EFI system table */
533 unsigned int runtime_version; /* Runtime services version */534 unsigned int runtime_version; /* Runtime services version */
534 unsigned long acpi; /* ACPI table (IA64 ext 0.71) */535 unsigned long acpi; /* ACPI table (IA64 ext 0.71) */