Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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)

Tested-by: Tony Luck <tony.luck@intel.com> # arch/ia64
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

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