mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 01:49:36 +00:00
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>
This commit is contained in:
parent
09308012d8
commit
59f2a619a2
9 changed files with 49 additions and 22 deletions
|
@ -218,7 +218,8 @@ extern void efi_thunk_runtime_setup(void);
|
|||
efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
|
||||
unsigned long descriptor_size,
|
||||
u32 descriptor_version,
|
||||
efi_memory_desc_t *virtual_map);
|
||||
efi_memory_desc_t *virtual_map,
|
||||
unsigned long systab_phys);
|
||||
|
||||
/* arch specific definitions used by the stub code */
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
# error "Please do not build this file directly, build asm-offsets.c instead"
|
||||
#endif
|
||||
|
||||
#include <linux/efi.h>
|
||||
|
||||
#include <asm/ucontext.h>
|
||||
|
||||
#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
|
||||
|
@ -64,4 +66,7 @@ void foo(void)
|
|||
BLANK();
|
||||
DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
|
||||
DEFINE(NR_syscalls, sizeof(syscalls));
|
||||
|
||||
BLANK();
|
||||
DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
|
||||
}
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
#include <asm/uv/uv.h>
|
||||
|
||||
static efi_system_table_t efi_systab __initdata;
|
||||
static u64 efi_systab_phys __initdata;
|
||||
|
||||
static unsigned long efi_systab_phys __initdata;
|
||||
static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;
|
||||
static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;
|
||||
static unsigned long efi_runtime, efi_nr_tables;
|
||||
|
@ -335,7 +335,7 @@ void __init efi_print_memmap(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int __init efi_systab_init(u64 phys)
|
||||
static int __init efi_systab_init(unsigned long phys)
|
||||
{
|
||||
int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
|
||||
: sizeof(efi_system_table_32_t);
|
||||
|
@ -949,7 +949,8 @@ static void __init __efi_enter_virtual_mode(void)
|
|||
status = efi_set_virtual_address_map(efi.memmap.desc_size * count,
|
||||
efi.memmap.desc_size,
|
||||
efi.memmap.desc_version,
|
||||
(efi_memory_desc_t *)pa);
|
||||
(efi_memory_desc_t *)pa,
|
||||
efi_systab_phys);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
|
||||
status);
|
||||
|
@ -983,6 +984,8 @@ void __init efi_enter_virtual_mode(void)
|
|||
if (efi_enabled(EFI_PARAVIRT))
|
||||
return;
|
||||
|
||||
efi.runtime = (efi_runtime_services_t *)efi_runtime;
|
||||
|
||||
if (efi_setup)
|
||||
kexec_enter_virtual_mode();
|
||||
else
|
||||
|
|
|
@ -66,14 +66,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
|
|||
void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
|
||||
void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
|
||||
|
||||
efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *,
|
||||
u32, u32, u32, void *);
|
||||
efi_status_t efi_call_svam(efi_runtime_services_t * const *,
|
||||
u32, u32, u32, void *, u32);
|
||||
|
||||
efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
|
||||
unsigned long descriptor_size,
|
||||
u32 descriptor_version,
|
||||
efi_memory_desc_t *virtual_map)
|
||||
efi_memory_desc_t *virtual_map,
|
||||
unsigned long systab_phys)
|
||||
{
|
||||
const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
|
||||
struct desc_ptr gdt_descr;
|
||||
efi_status_t status;
|
||||
unsigned long flags;
|
||||
|
@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
|
|||
|
||||
/* Disable interrupts around EFI calls: */
|
||||
local_irq_save(flags);
|
||||
status = efi_call_svam(&efi.systab->runtime->set_virtual_address_map,
|
||||
status = efi_call_svam(&systab->runtime,
|
||||
memory_map_size, descriptor_size,
|
||||
descriptor_version, virtual_map);
|
||||
descriptor_version, virtual_map,
|
||||
__pa(&efi.runtime));
|
||||
local_irq_restore(flags);
|
||||
|
||||
load_fixmap_gdt(0);
|
||||
|
|
|
@ -500,12 +500,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
|
|||
*/
|
||||
#define __efi_thunk(func, ...) \
|
||||
({ \
|
||||
efi_runtime_services_32_t *__rt; \
|
||||
unsigned short __ds, __es; \
|
||||
efi_status_t ____s; \
|
||||
\
|
||||
__rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime; \
|
||||
\
|
||||
savesegment(ds, __ds); \
|
||||
savesegment(es, __es); \
|
||||
\
|
||||
|
@ -513,7 +510,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
|
|||
loadsegment(ds, __KERNEL_DS); \
|
||||
loadsegment(es, __KERNEL_DS); \
|
||||
\
|
||||
____s = efi64_thunk(__rt->func, __VA_ARGS__); \
|
||||
____s = efi64_thunk(efi.runtime->mixed_mode.func, __VA_ARGS__); \
|
||||
\
|
||||
loadsegment(ds, __ds); \
|
||||
loadsegment(es, __es); \
|
||||
|
@ -886,8 +883,10 @@ efi_status_t __init __no_sanitize_address
|
|||
efi_set_virtual_address_map(unsigned long memory_map_size,
|
||||
unsigned long descriptor_size,
|
||||
u32 descriptor_version,
|
||||
efi_memory_desc_t *virtual_map)
|
||||
efi_memory_desc_t *virtual_map,
|
||||
unsigned long systab_phys)
|
||||
{
|
||||
const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
|
||||
efi_status_t status;
|
||||
unsigned long flags;
|
||||
pgd_t *save_pgd = NULL;
|
||||
|
@ -910,13 +909,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
|
|||
|
||||
/* Disable interrupts around EFI calls: */
|
||||
local_irq_save(flags);
|
||||
status = efi_call(efi.systab->runtime->set_virtual_address_map,
|
||||
status = efi_call(efi.runtime->set_virtual_address_map,
|
||||
memory_map_size, descriptor_size,
|
||||
descriptor_version, virtual_map);
|
||||
local_irq_restore(flags);
|
||||
|
||||
kernel_fpu_end();
|
||||
|
||||
/* grab the virtually remapped EFI runtime services table pointer */
|
||||
efi.runtime = READ_ONCE(systab->runtime);
|
||||
|
||||
if (save_pgd)
|
||||
efi_uv1_memmap_phys_epilog(save_pgd);
|
||||
else
|
||||
|
|
|
@ -8,14 +8,20 @@
|
|||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/page_types.h>
|
||||
|
||||
__INIT
|
||||
SYM_FUNC_START(efi_call_svam)
|
||||
push 8(%esp)
|
||||
push 8(%esp)
|
||||
push %ebp
|
||||
movl %esp, %ebp
|
||||
push %ebx
|
||||
|
||||
push 16(%esp)
|
||||
push 16(%esp)
|
||||
push %ecx
|
||||
push %edx
|
||||
movl %eax, %ebx // &systab_phys->runtime
|
||||
|
||||
/*
|
||||
* Switch to the flat mapped alias of this routine, by jumping to the
|
||||
|
@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam)
|
|||
subl $__PAGE_OFFSET, %esp
|
||||
|
||||
/* call the EFI routine */
|
||||
call *(%eax)
|
||||
movl (%eax), %eax
|
||||
call *EFI_svam(%eax)
|
||||
|
||||
/* convert ESP back to a kernel VA, and pop the outgoing args */
|
||||
addl $__PAGE_OFFSET + 16, %esp
|
||||
/* grab the virtually remapped EFI runtime services table pointer */
|
||||
movl (%ebx), %ecx
|
||||
movl 36(%esp), %edx // &efi.runtime
|
||||
movl %ecx, (%edx)
|
||||
|
||||
/* re-enable paging */
|
||||
movl %cr0, %edx
|
||||
orl $0x80000000, %edx
|
||||
movl %edx, %cr0
|
||||
|
||||
pop %ebx
|
||||
leave
|
||||
ret
|
||||
SYM_FUNC_END(efi_call_svam)
|
||||
|
|
|
@ -104,6 +104,7 @@ static int __init uefi_init(void)
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
efi.runtime = efi.systab->runtime;
|
||||
efi.runtime_version = efi.systab->hdr.revision;
|
||||
|
||||
efi_systab_report_header(&efi.systab->hdr,
|
||||
|
|
|
@ -40,9 +40,9 @@
|
|||
* code doesn't get too cluttered:
|
||||
*/
|
||||
#define efi_call_virt(f, args...) \
|
||||
efi_call_virt_pointer(efi.systab->runtime, f, args)
|
||||
efi_call_virt_pointer(efi.runtime, f, args)
|
||||
#define __efi_call_virt(f, args...) \
|
||||
__efi_call_virt_pointer(efi.systab->runtime, f, args)
|
||||
__efi_call_virt_pointer(efi.runtime, f, args)
|
||||
|
||||
struct efi_runtime_work efi_rts_work;
|
||||
|
||||
|
|
|
@ -529,6 +529,7 @@ typedef struct {
|
|||
* All runtime access to EFI goes through this structure:
|
||||
*/
|
||||
extern struct efi {
|
||||
const efi_runtime_services_t *runtime; /* EFI runtime services table */
|
||||
efi_system_table_t *systab; /* EFI system table */
|
||||
unsigned int runtime_version; /* Runtime services version */
|
||||
unsigned long acpi; /* ACPI table (IA64 ext 0.71) */
|
||||
|
|
Loading…
Reference in a new issue