EFI updates for v6.6

- one bugfix for x86 mixed mode that did not make it into v6.5
 - first pass of cleanup for the EFI runtime wrappers
 - some cosmetic touchups
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQQm/3uucuRGn1Dmh0wbglWLn0tXAUCZOx+LAAKCRAwbglWLn0t
 XKzLAPwK8wIZ14NlC55NCtdvKEzK3N/muxKRqg2MAHfrbnREFgD9GgUxSbIEU2gz
 BXQM9GLaP86qCXkZlPYktjP6RVfDYAk=
 =e2mx
 -----END PGP SIGNATURE-----

Merge tag 'efi-next-for-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi

Pull EFI updates from Ard Biesheuvel:
 "This primarily covers some cleanup work on the EFI runtime wrappers,
  which are shared between all EFI architectures except Itanium, and
  which provide some level of isolation to prevent faults occurring in
  the firmware code (which runs at the same privilege level as the
  kernel) from bringing down the system.

  Beyond that, there is a fix that did not make it into v6.5, and some
  doc fixes and dead code cleanup.

   - one bugfix for x86 mixed mode that did not make it into v6.5

   - first pass of cleanup for the EFI runtime wrappers

   - some cosmetic touchups"

* tag 'efi-next-for-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
  x86/efistub: Fix PCI ROM preservation in mixed mode
  efi/runtime-wrappers: Clean up white space and add __init annotation
  acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers
  efi/runtime-wrappers: Don't duplicate setup/teardown code
  efi/runtime-wrappers: Remove duplicated macro for service returning void
  efi/runtime-wrapper: Move workqueue manipulation out of line
  efi/runtime-wrappers: Use type safe encapsulation of call arguments
  efi/riscv: Move EFI runtime call setup/teardown helpers out of line
  efi/arm64: Move EFI runtime call setup/teardown helpers out of line
  efi/riscv: libstub: Fix comment about absolute relocation
  efi: memmap: Remove kernel-doc warnings
  efi: Remove unused extern declaration efi_lookup_mapped_addr()
This commit is contained in:
Linus Torvalds 2023-08-28 16:25:45 -07:00
commit d7dd9b449f
12 changed files with 299 additions and 191 deletions

View File

@ -30,28 +30,16 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md,
bool has_bti);
#define arch_efi_call_virt_setup() \
({ \
efi_virtmap_load(); \
__efi_fpsimd_begin(); \
raw_spin_lock(&efi_rt_lock); \
})
#undef arch_efi_call_virt
#define arch_efi_call_virt(p, f, args...) \
__efi_rt_asm_wrapper((p)->f, #f, args)
#define arch_efi_call_virt_teardown() \
({ \
raw_spin_unlock(&efi_rt_lock); \
__efi_fpsimd_end(); \
efi_virtmap_unload(); \
})
extern raw_spinlock_t efi_rt_lock;
extern u64 *efi_rt_stack_top;
efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
void arch_efi_call_virt_setup(void);
void arch_efi_call_virt_teardown(void);
/*
* efi_rt_stack_top[-1] contains the value the stack pointer had before
* switching to the EFI runtime stack.

View File

@ -158,7 +158,21 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)
return s;
}
DEFINE_RAW_SPINLOCK(efi_rt_lock);
static DEFINE_RAW_SPINLOCK(efi_rt_lock);
void arch_efi_call_virt_setup(void)
{
efi_virtmap_load();
__efi_fpsimd_begin();
raw_spin_lock(&efi_rt_lock);
}
void arch_efi_call_virt_teardown(void)
{
raw_spin_unlock(&efi_rt_lock);
__efi_fpsimd_end();
efi_virtmap_unload();
}
asmlinkage u64 *efi_rt_stack_top __ro_after_init;

View File

@ -21,12 +21,6 @@ extern void efi_init(void);
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md, bool);
#define arch_efi_call_virt_setup() ({ \
sync_kernel_mappings(efi_mm.pgd); \
efi_virtmap_load(); \
})
#define arch_efi_call_virt_teardown() efi_virtmap_unload()
#define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)
/* Load initrd anywhere in system RAM */
@ -46,8 +40,8 @@ static inline unsigned long efi_get_kimg_min_align(void)
#define EFI_KIMG_PREFERRED_ADDRESS efi_get_kimg_min_align()
void efi_virtmap_load(void);
void efi_virtmap_unload(void);
void arch_efi_call_virt_setup(void);
void arch_efi_call_virt_teardown(void);
unsigned long stext_offset(void);

View File

@ -10,6 +10,7 @@
* Copyright (c) Russ Anderson <rja@sgi.com>
*/
#include <linux/efi.h>
#include <linux/rtc.h>
/*
@ -115,7 +116,8 @@ struct uv_arch_type_entry {
struct uv_systab {
char signature[4]; /* must be UV_SYSTAB_SIG */
u32 revision; /* distinguish different firmware revs */
u64 function; /* BIOS runtime callback function ptr */
u64 (__efiapi *function)(enum uv_bios_cmd, ...);
/* BIOS runtime callback function ptr */
u32 size; /* systab size (starting with _VERSION_UV4) */
struct {
u32 type:8; /* type of entry */

View File

@ -82,7 +82,7 @@ int __init efi_memmap_alloc(unsigned int num_entries,
/**
* efi_memmap_install - Install a new EFI memory map in efi.memmap
* @ctx: map allocation parameters (address, size, flags)
* @data: efi memmap installation parameters
*
* Unlike efi_memmap_init_*(), this function does not allow the caller
* to switch from early to late mappings. It simply uses the existing

View File

@ -581,7 +581,7 @@ config ACPI_VIOT
config ACPI_PRMT
bool "Platform Runtime Mechanism Support"
depends on EFI && (X86_64 || ARM64)
depends on EFI_RUNTIME_WRAPPERS && (X86_64 || ARM64)
default y
help
Platform Runtime Mechanism (PRM) is a firmware interface exposing a

View File

@ -53,7 +53,7 @@ static LIST_HEAD(prm_module_list);
struct prm_handler_info {
guid_t guid;
void *handler_addr;
efi_status_t (__efiapi *handler_addr)(u64, void *);
u64 static_data_buffer_addr;
u64 acpi_param_buffer_addr;
@ -260,9 +260,9 @@ static acpi_status acpi_platformrt_space_handler(u32 function,
context.static_data_buffer = handler->static_data_buffer_addr;
context.mmio_ranges = module->mmio_info;
status = efi_call_virt_pointer(handler, handler_addr,
handler->acpi_param_buffer_addr,
&context);
status = efi_call_acpi_prm_handler(handler->handler_addr,
handler->acpi_param_buffer_addr,
&context);
if (status == EFI_SUCCESS) {
buffer->prm_status = PRM_HANDLER_SUCCESS;
} else {

View File

@ -147,7 +147,7 @@ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS
# For RISC-V, we don't need anything special other than arm64. Keep all the
# symbols in .init section and make sure that no absolute symbols references
# doesn't exist.
# exist.
STUBCOPY_FLAGS-$(CONFIG_RISCV) += --prefix-alloc-sections=.init \
--prefix-symbols=__efistub_
STUBCOPY_RELOC-$(CONFIG_RISCV) := R_RISCV_HI20

View File

@ -72,7 +72,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
rom->data.type = SETUP_PCI;
rom->data.len = size - sizeof(struct setup_data);
rom->data.next = 0;
rom->pcilen = pci->romsize;
rom->pcilen = romsize;
*__rom = rom;
status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,

View File

@ -130,14 +130,25 @@ static int __init riscv_enable_runtime_services(void)
}
early_initcall(riscv_enable_runtime_services);
void efi_virtmap_load(void)
static void efi_virtmap_load(void)
{
preempt_disable();
switch_mm(current->active_mm, &efi_mm, NULL);
}
void efi_virtmap_unload(void)
static void efi_virtmap_unload(void)
{
switch_mm(&efi_mm, current->active_mm, NULL);
preempt_enable();
}
void arch_efi_call_virt_setup(void)
{
sync_kernel_mappings(efi_mm.pgd);
efi_virtmap_load();
}
void arch_efi_call_virt_teardown(void)
{
efi_virtmap_unload();
}

View File

@ -40,55 +40,97 @@
* code doesn't get too cluttered:
*/
#define efi_call_virt(f, args...) \
efi_call_virt_pointer(efi.runtime, f, args)
#define __efi_call_virt(f, args...) \
__efi_call_virt_pointer(efi.runtime, f, args)
arch_efi_call_virt(efi.runtime, f, args)
union efi_rts_args {
struct {
efi_time_t *time;
efi_time_cap_t *capabilities;
} GET_TIME;
struct {
efi_time_t *time;
} SET_TIME;
struct {
efi_bool_t *enabled;
efi_bool_t *pending;
efi_time_t *time;
} GET_WAKEUP_TIME;
struct {
efi_bool_t enable;
efi_time_t *time;
} SET_WAKEUP_TIME;
struct {
efi_char16_t *name;
efi_guid_t *vendor;
u32 *attr;
unsigned long *data_size;
void *data;
} GET_VARIABLE;
struct {
unsigned long *name_size;
efi_char16_t *name;
efi_guid_t *vendor;
} GET_NEXT_VARIABLE;
struct {
efi_char16_t *name;
efi_guid_t *vendor;
u32 attr;
unsigned long data_size;
void *data;
} SET_VARIABLE;
struct {
u32 attr;
u64 *storage_space;
u64 *remaining_space;
u64 *max_variable_size;
} QUERY_VARIABLE_INFO;
struct {
u32 *high_count;
} GET_NEXT_HIGH_MONO_COUNT;
struct {
efi_capsule_header_t **capsules;
unsigned long count;
unsigned long sg_list;
} UPDATE_CAPSULE;
struct {
efi_capsule_header_t **capsules;
unsigned long count;
u64 *max_size;
int *reset_type;
} QUERY_CAPSULE_CAPS;
struct {
efi_status_t (__efiapi *acpi_prm_handler)(u64, void *);
u64 param_buffer_addr;
void *context;
} ACPI_PRM_HANDLER;
};
struct efi_runtime_work efi_rts_work;
/*
* efi_queue_work: Queue efi_runtime_service() and wait until it's done
* @rts: efi_runtime_service() function identifier
* @rts_arg<1-5>: efi_runtime_service() function arguments
* efi_queue_work: Queue EFI runtime service call and wait for completion
* @_rts: EFI runtime service function identifier
* @_args: Arguments to pass to the EFI runtime service
*
* Accesses to efi_runtime_services() are serialized by a binary
* semaphore (efi_runtime_lock) and caller waits until the work is
* finished, hence _only_ one work is queued at a time and the caller
* thread waits for completion.
*/
#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \
({ \
efi_rts_work.status = EFI_ABORTED; \
\
if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \
pr_warn_once("EFI Runtime Services are disabled!\n"); \
efi_rts_work.status = EFI_DEVICE_ERROR; \
goto exit; \
} \
\
init_completion(&efi_rts_work.efi_rts_comp); \
INIT_WORK(&efi_rts_work.work, efi_call_rts); \
efi_rts_work.arg1 = _arg1; \
efi_rts_work.arg2 = _arg2; \
efi_rts_work.arg3 = _arg3; \
efi_rts_work.arg4 = _arg4; \
efi_rts_work.arg5 = _arg5; \
efi_rts_work.efi_rts_id = _rts; \
\
/* \
* queue_work() returns 0 if work was already on queue, \
* _ideally_ this should never happen. \
*/ \
if (queue_work(efi_rts_wq, &efi_rts_work.work)) \
wait_for_completion(&efi_rts_work.efi_rts_comp); \
else \
pr_err("Failed to queue work to efi_rts_wq.\n"); \
\
WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED); \
exit: \
efi_rts_work.efi_rts_id = EFI_NONE; \
efi_rts_work.status; \
})
#define efi_queue_work(_rts, _args...) \
__efi_queue_work(EFI_ ## _rts, \
&(union efi_rts_args){ ._rts = { _args }})
#ifndef arch_efi_save_flags
#define arch_efi_save_flags(state_flags) local_save_flags(state_flags)
@ -103,7 +145,7 @@ unsigned long efi_call_virt_save_flags(void)
return flags;
}
void efi_call_virt_check_flags(unsigned long flags, const char *call)
void efi_call_virt_check_flags(unsigned long flags, const void *caller)
{
unsigned long cur_flags, mismatch;
@ -114,8 +156,8 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
return;
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE);
pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n",
flags, cur_flags, call);
pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI call from %pS\n",
flags, cur_flags, caller ?: __builtin_return_address(0));
arch_efi_restore_flags(flags);
}
@ -170,74 +212,90 @@ extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
/*
* Calls the appropriate efi_runtime_service() with the appropriate
* arguments.
*
* Semantics followed by efi_call_rts() to understand efi_runtime_work:
* 1. If argument was a pointer, recast it from void pointer to original
* pointer type.
* 2. If argument was a value, recast it from void pointer to original
* pointer type and dereference it.
*/
static void efi_call_rts(struct work_struct *work)
{
void *arg1, *arg2, *arg3, *arg4, *arg5;
const union efi_rts_args *args = efi_rts_work.args;
efi_status_t status = EFI_NOT_FOUND;
unsigned long flags;
arg1 = efi_rts_work.arg1;
arg2 = efi_rts_work.arg2;
arg3 = efi_rts_work.arg3;
arg4 = efi_rts_work.arg4;
arg5 = efi_rts_work.arg5;
arch_efi_call_virt_setup();
flags = efi_call_virt_save_flags();
switch (efi_rts_work.efi_rts_id) {
case EFI_GET_TIME:
status = efi_call_virt(get_time, (efi_time_t *)arg1,
(efi_time_cap_t *)arg2);
status = efi_call_virt(get_time,
args->GET_TIME.time,
args->GET_TIME.capabilities);
break;
case EFI_SET_TIME:
status = efi_call_virt(set_time, (efi_time_t *)arg1);
status = efi_call_virt(set_time,
args->SET_TIME.time);
break;
case EFI_GET_WAKEUP_TIME:
status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
(efi_bool_t *)arg2, (efi_time_t *)arg3);
status = efi_call_virt(get_wakeup_time,
args->GET_WAKEUP_TIME.enabled,
args->GET_WAKEUP_TIME.pending,
args->GET_WAKEUP_TIME.time);
break;
case EFI_SET_WAKEUP_TIME:
status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
(efi_time_t *)arg2);
status = efi_call_virt(set_wakeup_time,
args->SET_WAKEUP_TIME.enable,
args->SET_WAKEUP_TIME.time);
break;
case EFI_GET_VARIABLE:
status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
(efi_guid_t *)arg2, (u32 *)arg3,
(unsigned long *)arg4, (void *)arg5);
status = efi_call_virt(get_variable,
args->GET_VARIABLE.name,
args->GET_VARIABLE.vendor,
args->GET_VARIABLE.attr,
args->GET_VARIABLE.data_size,
args->GET_VARIABLE.data);
break;
case EFI_GET_NEXT_VARIABLE:
status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
(efi_char16_t *)arg2,
(efi_guid_t *)arg3);
status = efi_call_virt(get_next_variable,
args->GET_NEXT_VARIABLE.name_size,
args->GET_NEXT_VARIABLE.name,
args->GET_NEXT_VARIABLE.vendor);
break;
case EFI_SET_VARIABLE:
status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
(efi_guid_t *)arg2, *(u32 *)arg3,
*(unsigned long *)arg4, (void *)arg5);
status = efi_call_virt(set_variable,
args->SET_VARIABLE.name,
args->SET_VARIABLE.vendor,
args->SET_VARIABLE.attr,
args->SET_VARIABLE.data_size,
args->SET_VARIABLE.data);
break;
case EFI_QUERY_VARIABLE_INFO:
status = efi_call_virt(query_variable_info, *(u32 *)arg1,
(u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
status = efi_call_virt(query_variable_info,
args->QUERY_VARIABLE_INFO.attr,
args->QUERY_VARIABLE_INFO.storage_space,
args->QUERY_VARIABLE_INFO.remaining_space,
args->QUERY_VARIABLE_INFO.max_variable_size);
break;
case EFI_GET_NEXT_HIGH_MONO_COUNT:
status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
status = efi_call_virt(get_next_high_mono_count,
args->GET_NEXT_HIGH_MONO_COUNT.high_count);
break;
case EFI_UPDATE_CAPSULE:
status = efi_call_virt(update_capsule,
(efi_capsule_header_t **)arg1,
*(unsigned long *)arg2,
*(unsigned long *)arg3);
args->UPDATE_CAPSULE.capsules,
args->UPDATE_CAPSULE.count,
args->UPDATE_CAPSULE.sg_list);
break;
case EFI_QUERY_CAPSULE_CAPS:
status = efi_call_virt(query_capsule_caps,
(efi_capsule_header_t **)arg1,
*(unsigned long *)arg2, (u64 *)arg3,
(int *)arg4);
args->QUERY_CAPSULE_CAPS.capsules,
args->QUERY_CAPSULE_CAPS.count,
args->QUERY_CAPSULE_CAPS.max_size,
args->QUERY_CAPSULE_CAPS.reset_type);
break;
case EFI_ACPI_PRM_HANDLER:
#ifdef CONFIG_ACPI_PRMT
status = arch_efi_call_virt(args, ACPI_PRM_HANDLER.acpi_prm_handler,
args->ACPI_PRM_HANDLER.param_buffer_addr,
args->ACPI_PRM_HANDLER.context);
break;
#endif
default:
/*
* Ideally, we should never reach here because a caller of this
@ -246,17 +304,53 @@ static void efi_call_rts(struct work_struct *work)
*/
pr_err("Requested executing invalid EFI Runtime Service.\n");
}
efi_call_virt_check_flags(flags, efi_rts_work.caller);
arch_efi_call_virt_teardown();
efi_rts_work.status = status;
complete(&efi_rts_work.efi_rts_comp);
}
static efi_status_t __efi_queue_work(enum efi_rts_ids id,
union efi_rts_args *args)
{
efi_rts_work.efi_rts_id = id;
efi_rts_work.args = args;
efi_rts_work.caller = __builtin_return_address(0);
efi_rts_work.status = EFI_ABORTED;
if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
pr_warn_once("EFI Runtime Services are disabled!\n");
efi_rts_work.status = EFI_DEVICE_ERROR;
goto exit;
}
init_completion(&efi_rts_work.efi_rts_comp);
INIT_WORK(&efi_rts_work.work, efi_call_rts);
/*
* queue_work() returns 0 if work was already on queue,
* _ideally_ this should never happen.
*/
if (queue_work(efi_rts_wq, &efi_rts_work.work))
wait_for_completion(&efi_rts_work.efi_rts_comp);
else
pr_err("Failed to queue work to efi_rts_wq.\n");
WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED);
exit:
efi_rts_work.efi_rts_id = EFI_NONE;
return efi_rts_work.status;
}
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{
efi_status_t status;
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_GET_TIME, tm, tc, NULL, NULL, NULL);
status = efi_queue_work(GET_TIME, tm, tc);
up(&efi_runtime_lock);
return status;
}
@ -267,7 +361,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_SET_TIME, tm, NULL, NULL, NULL, NULL);
status = efi_queue_work(SET_TIME, tm);
up(&efi_runtime_lock);
return status;
}
@ -280,8 +374,7 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_GET_WAKEUP_TIME, enabled, pending, tm, NULL,
NULL);
status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm);
up(&efi_runtime_lock);
return status;
}
@ -292,8 +385,7 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
NULL);
status = efi_queue_work(SET_WAKEUP_TIME, enabled, tm);
up(&efi_runtime_lock);
return status;
}
@ -308,7 +400,7 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_GET_VARIABLE, name, vendor, attr, data_size,
status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
data);
up(&efi_runtime_lock);
return status;
@ -322,8 +414,7 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_GET_NEXT_VARIABLE, name_size, name, vendor,
NULL, NULL);
status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor);
up(&efi_runtime_lock);
return status;
}
@ -338,24 +429,23 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_SET_VARIABLE, name, vendor, &attr, &data_size,
status = efi_queue_work(SET_VARIABLE, name, vendor, attr, data_size,
data);
up(&efi_runtime_lock);
return status;
}
static efi_status_t
virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
u32 attr, unsigned long data_size,
void *data)
virt_efi_set_variable_nb(efi_char16_t *name, efi_guid_t *vendor, u32 attr,
unsigned long data_size, void *data)
{
efi_status_t status;
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
status = efi_call_virt(set_variable, name, vendor, attr, data_size,
data);
status = efi_call_virt_pointer(efi.runtime, set_variable, name, vendor,
attr, data_size, data);
up(&efi_runtime_lock);
return status;
}
@ -373,17 +463,15 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_QUERY_VARIABLE_INFO, &attr, storage_space,
remaining_space, max_variable_size, NULL);
status = efi_queue_work(QUERY_VARIABLE_INFO, attr, storage_space,
remaining_space, max_variable_size);
up(&efi_runtime_lock);
return status;
}
static efi_status_t
virt_efi_query_variable_info_nonblocking(u32 attr,
u64 *storage_space,
u64 *remaining_space,
u64 *max_variable_size)
virt_efi_query_variable_info_nb(u32 attr, u64 *storage_space,
u64 *remaining_space, u64 *max_variable_size)
{
efi_status_t status;
@ -393,8 +481,9 @@ virt_efi_query_variable_info_nonblocking(u32 attr,
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
status = efi_call_virt(query_variable_info, attr, storage_space,
remaining_space, max_variable_size);
status = efi_call_virt_pointer(efi.runtime, query_variable_info, attr,
storage_space, remaining_space,
max_variable_size);
up(&efi_runtime_lock);
return status;
}
@ -405,8 +494,7 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
NULL, NULL);
status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count);
up(&efi_runtime_lock);
return status;
}
@ -421,8 +509,13 @@ static void virt_efi_reset_system(int reset_type,
"could not get exclusive access to the firmware\n");
return;
}
arch_efi_call_virt_setup();
efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM;
__efi_call_virt(reset_system, reset_type, status, data_size, data);
arch_efi_call_virt(efi.runtime, reset_system, reset_type, status,
data_size, data);
arch_efi_call_virt_teardown();
up(&efi_runtime_lock);
}
@ -437,8 +530,7 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_UPDATE_CAPSULE, capsules, &count, &sg_list,
NULL, NULL);
status = efi_queue_work(UPDATE_CAPSULE, capsules, count, sg_list);
up(&efi_runtime_lock);
return status;
}
@ -455,26 +547,44 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(EFI_QUERY_CAPSULE_CAPS, capsules, &count,
max_size, reset_type, NULL);
status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, count,
max_size, reset_type);
up(&efi_runtime_lock);
return status;
}
void efi_native_runtime_setup(void)
void __init efi_native_runtime_setup(void)
{
efi.get_time = virt_efi_get_time;
efi.set_time = virt_efi_set_time;
efi.get_wakeup_time = virt_efi_get_wakeup_time;
efi.set_wakeup_time = virt_efi_set_wakeup_time;
efi.get_variable = virt_efi_get_variable;
efi.get_next_variable = virt_efi_get_next_variable;
efi.set_variable = virt_efi_set_variable;
efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
efi.reset_system = virt_efi_reset_system;
efi.query_variable_info = virt_efi_query_variable_info;
efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
efi.update_capsule = virt_efi_update_capsule;
efi.query_capsule_caps = virt_efi_query_capsule_caps;
efi.get_time = virt_efi_get_time;
efi.set_time = virt_efi_set_time;
efi.get_wakeup_time = virt_efi_get_wakeup_time;
efi.set_wakeup_time = virt_efi_set_wakeup_time;
efi.get_variable = virt_efi_get_variable;
efi.get_next_variable = virt_efi_get_next_variable;
efi.set_variable = virt_efi_set_variable;
efi.set_variable_nonblocking = virt_efi_set_variable_nb;
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
efi.reset_system = virt_efi_reset_system;
efi.query_variable_info = virt_efi_query_variable_info;
efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nb;
efi.update_capsule = virt_efi_update_capsule;
efi.query_capsule_caps = virt_efi_query_capsule_caps;
}
#ifdef CONFIG_ACPI_PRMT
efi_status_t
efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
u64 param_buffer_addr, void *context)
{
efi_status_t status;
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
status = efi_queue_work(ACPI_PRM_HANDLER, handler_addr,
param_buffer_addr, context);
up(&efi_runtime_lock);
return status;
}
#endif

View File

@ -726,7 +726,6 @@ static inline efi_status_t efi_query_variable_store(u32 attributes,
return EFI_SUCCESS;
}
#endif
extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
extern int __init __efi_memmap_init(struct efi_memory_map_data *data);
extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
@ -1130,7 +1129,7 @@ extern bool efi_runtime_disabled(void);
static inline bool efi_runtime_disabled(void) { return true; }
#endif
extern void efi_call_virt_check_flags(unsigned long flags, const char *call);
extern void efi_call_virt_check_flags(unsigned long flags, const void *caller);
extern unsigned long efi_call_virt_save_flags(void);
enum efi_secureboot_mode {
@ -1171,8 +1170,7 @@ static inline void efi_check_for_embedded_firmwares(void) { }
#define arch_efi_call_virt(p, f, args...) ((p)->f(args))
/*
* Arch code can implement the following three template macros, avoiding
* reptition for the void/non-void return cases of {__,}efi_call_virt():
* Arch code must implement the following three routines:
*
* * arch_efi_call_virt_setup()
*
@ -1181,9 +1179,8 @@ static inline void efi_check_for_embedded_firmwares(void) { }
*
* * arch_efi_call_virt()
*
* Performs the call. The last expression in the macro must be the call
* itself, allowing the logic to be shared by the void and non-void
* cases.
* Performs the call. This routine takes a variable number of arguments so
* it must be implemented as a variadic preprocessor macro.
*
* * arch_efi_call_virt_teardown()
*
@ -1192,33 +1189,20 @@ static inline void efi_check_for_embedded_firmwares(void) { }
#define efi_call_virt_pointer(p, f, args...) \
({ \
efi_status_t __s; \
typeof((p)->f(args)) __s; \
unsigned long __flags; \
\
arch_efi_call_virt_setup(); \
\
__flags = efi_call_virt_save_flags(); \
__s = arch_efi_call_virt(p, f, args); \
efi_call_virt_check_flags(__flags, __stringify(f)); \
efi_call_virt_check_flags(__flags, NULL); \
\
arch_efi_call_virt_teardown(); \
\
__s; \
})
#define __efi_call_virt_pointer(p, f, args...) \
({ \
unsigned long __flags; \
\
arch_efi_call_virt_setup(); \
\
__flags = efi_call_virt_save_flags(); \
arch_efi_call_virt(p, f, args); \
efi_call_virt_check_flags(__flags, __stringify(f)); \
\
arch_efi_call_virt_teardown(); \
})
#define EFI_RANDOM_SEED_SIZE 32U // BLAKE2S_HASH_SIZE
struct linux_efi_random_seed {
@ -1244,6 +1228,10 @@ extern int efi_tpm_final_log_size;
extern unsigned long rci2_table_phys;
efi_status_t
efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
u64 param_buffer_addr, void *context);
/*
* efi_runtime_service() function identifiers.
* "NONE" is used by efi_recover_from_page_fault() to check if the page
@ -1263,25 +1251,26 @@ enum efi_rts_ids {
EFI_RESET_SYSTEM,
EFI_UPDATE_CAPSULE,
EFI_QUERY_CAPSULE_CAPS,
EFI_ACPI_PRM_HANDLER,
};
union efi_rts_args;
/*
* efi_runtime_work: Details of EFI Runtime Service work
* @arg<1-5>: EFI Runtime Service function arguments
* @args: Pointer to union describing the arguments
* @status: Status of executing EFI Runtime Service
* @efi_rts_id: EFI Runtime Service function identifier
* @efi_rts_comp: Struct used for handling completions
* @caller: The caller of the runtime service
*/
struct efi_runtime_work {
void *arg1;
void *arg2;
void *arg3;
void *arg4;
void *arg5;
efi_status_t status;
struct work_struct work;
enum efi_rts_ids efi_rts_id;
struct completion efi_rts_comp;
union efi_rts_args *args;
efi_status_t status;
struct work_struct work;
enum efi_rts_ids efi_rts_id;
struct completion efi_rts_comp;
const void *caller;
};
extern struct efi_runtime_work efi_rts_work;