162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * runtime-wrappers.c - Runtime Services function call wrappers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Implementation summary: 662306a36Sopenharmony_ci * ----------------------- 762306a36Sopenharmony_ci * 1. When user/kernel thread requests to execute efi_runtime_service(), 862306a36Sopenharmony_ci * enqueue work to efi_rts_wq. 962306a36Sopenharmony_ci * 2. Caller thread waits for completion until the work is finished 1062306a36Sopenharmony_ci * because it's dependent on the return status and execution of 1162306a36Sopenharmony_ci * efi_runtime_service(). 1262306a36Sopenharmony_ci * For instance, get_variable() and get_next_variable(). 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Split off from arch/x86/platform/efi/efi.c 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems 1962306a36Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 2062306a36Sopenharmony_ci * Copyright (C) 1999-2002 Hewlett-Packard Co. 2162306a36Sopenharmony_ci * Copyright (C) 2005-2008 Intel Co. 2262306a36Sopenharmony_ci * Copyright (C) 2013 SuSE Labs 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define pr_fmt(fmt) "efi: " fmt 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/bug.h> 2862306a36Sopenharmony_ci#include <linux/efi.h> 2962306a36Sopenharmony_ci#include <linux/irqflags.h> 3062306a36Sopenharmony_ci#include <linux/mutex.h> 3162306a36Sopenharmony_ci#include <linux/semaphore.h> 3262306a36Sopenharmony_ci#include <linux/stringify.h> 3362306a36Sopenharmony_ci#include <linux/workqueue.h> 3462306a36Sopenharmony_ci#include <linux/completion.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <asm/efi.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Wrap around the new efi_call_virt_generic() macros so that the 4062306a36Sopenharmony_ci * code doesn't get too cluttered: 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci#define efi_call_virt(f, args...) \ 4362306a36Sopenharmony_ci arch_efi_call_virt(efi.runtime, f, args) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciunion efi_rts_args { 4662306a36Sopenharmony_ci struct { 4762306a36Sopenharmony_ci efi_time_t *time; 4862306a36Sopenharmony_ci efi_time_cap_t *capabilities; 4962306a36Sopenharmony_ci } GET_TIME; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci struct { 5262306a36Sopenharmony_ci efi_time_t *time; 5362306a36Sopenharmony_ci } SET_TIME; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci struct { 5662306a36Sopenharmony_ci efi_bool_t *enabled; 5762306a36Sopenharmony_ci efi_bool_t *pending; 5862306a36Sopenharmony_ci efi_time_t *time; 5962306a36Sopenharmony_ci } GET_WAKEUP_TIME; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci struct { 6262306a36Sopenharmony_ci efi_bool_t enable; 6362306a36Sopenharmony_ci efi_time_t *time; 6462306a36Sopenharmony_ci } SET_WAKEUP_TIME; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci struct { 6762306a36Sopenharmony_ci efi_char16_t *name; 6862306a36Sopenharmony_ci efi_guid_t *vendor; 6962306a36Sopenharmony_ci u32 *attr; 7062306a36Sopenharmony_ci unsigned long *data_size; 7162306a36Sopenharmony_ci void *data; 7262306a36Sopenharmony_ci } GET_VARIABLE; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci struct { 7562306a36Sopenharmony_ci unsigned long *name_size; 7662306a36Sopenharmony_ci efi_char16_t *name; 7762306a36Sopenharmony_ci efi_guid_t *vendor; 7862306a36Sopenharmony_ci } GET_NEXT_VARIABLE; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci struct { 8162306a36Sopenharmony_ci efi_char16_t *name; 8262306a36Sopenharmony_ci efi_guid_t *vendor; 8362306a36Sopenharmony_ci u32 attr; 8462306a36Sopenharmony_ci unsigned long data_size; 8562306a36Sopenharmony_ci void *data; 8662306a36Sopenharmony_ci } SET_VARIABLE; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci struct { 8962306a36Sopenharmony_ci u32 attr; 9062306a36Sopenharmony_ci u64 *storage_space; 9162306a36Sopenharmony_ci u64 *remaining_space; 9262306a36Sopenharmony_ci u64 *max_variable_size; 9362306a36Sopenharmony_ci } QUERY_VARIABLE_INFO; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci struct { 9662306a36Sopenharmony_ci u32 *high_count; 9762306a36Sopenharmony_ci } GET_NEXT_HIGH_MONO_COUNT; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci struct { 10062306a36Sopenharmony_ci efi_capsule_header_t **capsules; 10162306a36Sopenharmony_ci unsigned long count; 10262306a36Sopenharmony_ci unsigned long sg_list; 10362306a36Sopenharmony_ci } UPDATE_CAPSULE; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci struct { 10662306a36Sopenharmony_ci efi_capsule_header_t **capsules; 10762306a36Sopenharmony_ci unsigned long count; 10862306a36Sopenharmony_ci u64 *max_size; 10962306a36Sopenharmony_ci int *reset_type; 11062306a36Sopenharmony_ci } QUERY_CAPSULE_CAPS; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci struct { 11362306a36Sopenharmony_ci efi_status_t (__efiapi *acpi_prm_handler)(u64, void *); 11462306a36Sopenharmony_ci u64 param_buffer_addr; 11562306a36Sopenharmony_ci void *context; 11662306a36Sopenharmony_ci } ACPI_PRM_HANDLER; 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistruct efi_runtime_work efi_rts_work; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * efi_queue_work: Queue EFI runtime service call and wait for completion 12362306a36Sopenharmony_ci * @_rts: EFI runtime service function identifier 12462306a36Sopenharmony_ci * @_args: Arguments to pass to the EFI runtime service 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * Accesses to efi_runtime_services() are serialized by a binary 12762306a36Sopenharmony_ci * semaphore (efi_runtime_lock) and caller waits until the work is 12862306a36Sopenharmony_ci * finished, hence _only_ one work is queued at a time and the caller 12962306a36Sopenharmony_ci * thread waits for completion. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci#define efi_queue_work(_rts, _args...) \ 13262306a36Sopenharmony_ci __efi_queue_work(EFI_ ## _rts, \ 13362306a36Sopenharmony_ci &(union efi_rts_args){ ._rts = { _args }}) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#ifndef arch_efi_save_flags 13662306a36Sopenharmony_ci#define arch_efi_save_flags(state_flags) local_save_flags(state_flags) 13762306a36Sopenharmony_ci#define arch_efi_restore_flags(state_flags) local_irq_restore(state_flags) 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciunsigned long efi_call_virt_save_flags(void) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci unsigned long flags; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci arch_efi_save_flags(flags); 14562306a36Sopenharmony_ci return flags; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_civoid efi_call_virt_check_flags(unsigned long flags, const void *caller) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci unsigned long cur_flags, mismatch; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci cur_flags = efi_call_virt_save_flags(); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mismatch = flags ^ cur_flags; 15562306a36Sopenharmony_ci if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK)) 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE); 15962306a36Sopenharmony_ci pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI call from %pS\n", 16062306a36Sopenharmony_ci flags, cur_flags, caller ?: __builtin_return_address(0)); 16162306a36Sopenharmony_ci arch_efi_restore_flags(flags); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * According to section 7.1 of the UEFI spec, Runtime Services are not fully 16662306a36Sopenharmony_ci * reentrant, and there are particular combinations of calls that need to be 16762306a36Sopenharmony_ci * serialized. (source: UEFI Specification v2.4A) 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Table 31. Rules for Reentry Into Runtime Services 17062306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 17162306a36Sopenharmony_ci * | If previous call is busy in | Forbidden to call | 17262306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 17362306a36Sopenharmony_ci * | Any | SetVirtualAddressMap() | 17462306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 17562306a36Sopenharmony_ci * | ConvertPointer() | ConvertPointer() | 17662306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 17762306a36Sopenharmony_ci * | SetVariable() | ResetSystem() | 17862306a36Sopenharmony_ci * | UpdateCapsule() | | 17962306a36Sopenharmony_ci * | SetTime() | | 18062306a36Sopenharmony_ci * | SetWakeupTime() | | 18162306a36Sopenharmony_ci * | GetNextHighMonotonicCount() | | 18262306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 18362306a36Sopenharmony_ci * | GetVariable() | GetVariable() | 18462306a36Sopenharmony_ci * | GetNextVariableName() | GetNextVariableName() | 18562306a36Sopenharmony_ci * | SetVariable() | SetVariable() | 18662306a36Sopenharmony_ci * | QueryVariableInfo() | QueryVariableInfo() | 18762306a36Sopenharmony_ci * | UpdateCapsule() | UpdateCapsule() | 18862306a36Sopenharmony_ci * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | 18962306a36Sopenharmony_ci * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | 19062306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 19162306a36Sopenharmony_ci * | GetTime() | GetTime() | 19262306a36Sopenharmony_ci * | SetTime() | SetTime() | 19362306a36Sopenharmony_ci * | GetWakeupTime() | GetWakeupTime() | 19462306a36Sopenharmony_ci * | SetWakeupTime() | SetWakeupTime() | 19562306a36Sopenharmony_ci * +------------------------------------+-------------------------------+ 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Due to the fact that the EFI pstore may write to the variable store in 19862306a36Sopenharmony_ci * interrupt context, we need to use a lock for at least the groups that 19962306a36Sopenharmony_ci * contain SetVariable() and QueryVariableInfo(). That leaves little else, as 20062306a36Sopenharmony_ci * none of the remaining functions are actually ever called at runtime. 20162306a36Sopenharmony_ci * So let's just use a single lock to serialize all Runtime Services calls. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistatic DEFINE_SEMAPHORE(efi_runtime_lock, 1); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * Expose the EFI runtime lock to the UV platform 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci#ifdef CONFIG_X86_UV 20962306a36Sopenharmony_ciextern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock); 21062306a36Sopenharmony_ci#endif 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * Calls the appropriate efi_runtime_service() with the appropriate 21462306a36Sopenharmony_ci * arguments. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_cistatic void efi_call_rts(struct work_struct *work) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci const union efi_rts_args *args = efi_rts_work.args; 21962306a36Sopenharmony_ci efi_status_t status = EFI_NOT_FOUND; 22062306a36Sopenharmony_ci unsigned long flags; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci arch_efi_call_virt_setup(); 22362306a36Sopenharmony_ci flags = efi_call_virt_save_flags(); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci switch (efi_rts_work.efi_rts_id) { 22662306a36Sopenharmony_ci case EFI_GET_TIME: 22762306a36Sopenharmony_ci status = efi_call_virt(get_time, 22862306a36Sopenharmony_ci args->GET_TIME.time, 22962306a36Sopenharmony_ci args->GET_TIME.capabilities); 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci case EFI_SET_TIME: 23262306a36Sopenharmony_ci status = efi_call_virt(set_time, 23362306a36Sopenharmony_ci args->SET_TIME.time); 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci case EFI_GET_WAKEUP_TIME: 23662306a36Sopenharmony_ci status = efi_call_virt(get_wakeup_time, 23762306a36Sopenharmony_ci args->GET_WAKEUP_TIME.enabled, 23862306a36Sopenharmony_ci args->GET_WAKEUP_TIME.pending, 23962306a36Sopenharmony_ci args->GET_WAKEUP_TIME.time); 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case EFI_SET_WAKEUP_TIME: 24262306a36Sopenharmony_ci status = efi_call_virt(set_wakeup_time, 24362306a36Sopenharmony_ci args->SET_WAKEUP_TIME.enable, 24462306a36Sopenharmony_ci args->SET_WAKEUP_TIME.time); 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case EFI_GET_VARIABLE: 24762306a36Sopenharmony_ci status = efi_call_virt(get_variable, 24862306a36Sopenharmony_ci args->GET_VARIABLE.name, 24962306a36Sopenharmony_ci args->GET_VARIABLE.vendor, 25062306a36Sopenharmony_ci args->GET_VARIABLE.attr, 25162306a36Sopenharmony_ci args->GET_VARIABLE.data_size, 25262306a36Sopenharmony_ci args->GET_VARIABLE.data); 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case EFI_GET_NEXT_VARIABLE: 25562306a36Sopenharmony_ci status = efi_call_virt(get_next_variable, 25662306a36Sopenharmony_ci args->GET_NEXT_VARIABLE.name_size, 25762306a36Sopenharmony_ci args->GET_NEXT_VARIABLE.name, 25862306a36Sopenharmony_ci args->GET_NEXT_VARIABLE.vendor); 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci case EFI_SET_VARIABLE: 26162306a36Sopenharmony_ci status = efi_call_virt(set_variable, 26262306a36Sopenharmony_ci args->SET_VARIABLE.name, 26362306a36Sopenharmony_ci args->SET_VARIABLE.vendor, 26462306a36Sopenharmony_ci args->SET_VARIABLE.attr, 26562306a36Sopenharmony_ci args->SET_VARIABLE.data_size, 26662306a36Sopenharmony_ci args->SET_VARIABLE.data); 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci case EFI_QUERY_VARIABLE_INFO: 26962306a36Sopenharmony_ci status = efi_call_virt(query_variable_info, 27062306a36Sopenharmony_ci args->QUERY_VARIABLE_INFO.attr, 27162306a36Sopenharmony_ci args->QUERY_VARIABLE_INFO.storage_space, 27262306a36Sopenharmony_ci args->QUERY_VARIABLE_INFO.remaining_space, 27362306a36Sopenharmony_ci args->QUERY_VARIABLE_INFO.max_variable_size); 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci case EFI_GET_NEXT_HIGH_MONO_COUNT: 27662306a36Sopenharmony_ci status = efi_call_virt(get_next_high_mono_count, 27762306a36Sopenharmony_ci args->GET_NEXT_HIGH_MONO_COUNT.high_count); 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case EFI_UPDATE_CAPSULE: 28062306a36Sopenharmony_ci status = efi_call_virt(update_capsule, 28162306a36Sopenharmony_ci args->UPDATE_CAPSULE.capsules, 28262306a36Sopenharmony_ci args->UPDATE_CAPSULE.count, 28362306a36Sopenharmony_ci args->UPDATE_CAPSULE.sg_list); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case EFI_QUERY_CAPSULE_CAPS: 28662306a36Sopenharmony_ci status = efi_call_virt(query_capsule_caps, 28762306a36Sopenharmony_ci args->QUERY_CAPSULE_CAPS.capsules, 28862306a36Sopenharmony_ci args->QUERY_CAPSULE_CAPS.count, 28962306a36Sopenharmony_ci args->QUERY_CAPSULE_CAPS.max_size, 29062306a36Sopenharmony_ci args->QUERY_CAPSULE_CAPS.reset_type); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case EFI_ACPI_PRM_HANDLER: 29362306a36Sopenharmony_ci#ifdef CONFIG_ACPI_PRMT 29462306a36Sopenharmony_ci status = arch_efi_call_virt(args, ACPI_PRM_HANDLER.acpi_prm_handler, 29562306a36Sopenharmony_ci args->ACPI_PRM_HANDLER.param_buffer_addr, 29662306a36Sopenharmony_ci args->ACPI_PRM_HANDLER.context); 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci#endif 29962306a36Sopenharmony_ci default: 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * Ideally, we should never reach here because a caller of this 30262306a36Sopenharmony_ci * function should have put the right efi_runtime_service() 30362306a36Sopenharmony_ci * function identifier into efi_rts_work->efi_rts_id 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci pr_err("Requested executing invalid EFI Runtime Service.\n"); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci efi_call_virt_check_flags(flags, efi_rts_work.caller); 30962306a36Sopenharmony_ci arch_efi_call_virt_teardown(); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci efi_rts_work.status = status; 31262306a36Sopenharmony_ci complete(&efi_rts_work.efi_rts_comp); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic efi_status_t __efi_queue_work(enum efi_rts_ids id, 31662306a36Sopenharmony_ci union efi_rts_args *args) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci efi_rts_work.efi_rts_id = id; 31962306a36Sopenharmony_ci efi_rts_work.args = args; 32062306a36Sopenharmony_ci efi_rts_work.caller = __builtin_return_address(0); 32162306a36Sopenharmony_ci efi_rts_work.status = EFI_ABORTED; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (!efi_enabled(EFI_RUNTIME_SERVICES)) { 32462306a36Sopenharmony_ci pr_warn_once("EFI Runtime Services are disabled!\n"); 32562306a36Sopenharmony_ci efi_rts_work.status = EFI_DEVICE_ERROR; 32662306a36Sopenharmony_ci goto exit; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci init_completion(&efi_rts_work.efi_rts_comp); 33062306a36Sopenharmony_ci INIT_WORK(&efi_rts_work.work, efi_call_rts); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * queue_work() returns 0 if work was already on queue, 33462306a36Sopenharmony_ci * _ideally_ this should never happen. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (queue_work(efi_rts_wq, &efi_rts_work.work)) 33762306a36Sopenharmony_ci wait_for_completion(&efi_rts_work.efi_rts_comp); 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci pr_err("Failed to queue work to efi_rts_wq.\n"); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED); 34262306a36Sopenharmony_ciexit: 34362306a36Sopenharmony_ci efi_rts_work.efi_rts_id = EFI_NONE; 34462306a36Sopenharmony_ci return efi_rts_work.status; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci efi_status_t status; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 35262306a36Sopenharmony_ci return EFI_ABORTED; 35362306a36Sopenharmony_ci status = efi_queue_work(GET_TIME, tm, tc); 35462306a36Sopenharmony_ci up(&efi_runtime_lock); 35562306a36Sopenharmony_ci return status; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic efi_status_t virt_efi_set_time(efi_time_t *tm) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci efi_status_t status; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 36362306a36Sopenharmony_ci return EFI_ABORTED; 36462306a36Sopenharmony_ci status = efi_queue_work(SET_TIME, tm); 36562306a36Sopenharmony_ci up(&efi_runtime_lock); 36662306a36Sopenharmony_ci return status; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 37062306a36Sopenharmony_ci efi_bool_t *pending, 37162306a36Sopenharmony_ci efi_time_t *tm) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci efi_status_t status; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 37662306a36Sopenharmony_ci return EFI_ABORTED; 37762306a36Sopenharmony_ci status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm); 37862306a36Sopenharmony_ci up(&efi_runtime_lock); 37962306a36Sopenharmony_ci return status; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci efi_status_t status; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 38762306a36Sopenharmony_ci return EFI_ABORTED; 38862306a36Sopenharmony_ci status = efi_queue_work(SET_WAKEUP_TIME, enabled, tm); 38962306a36Sopenharmony_ci up(&efi_runtime_lock); 39062306a36Sopenharmony_ci return status; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic efi_status_t virt_efi_get_variable(efi_char16_t *name, 39462306a36Sopenharmony_ci efi_guid_t *vendor, 39562306a36Sopenharmony_ci u32 *attr, 39662306a36Sopenharmony_ci unsigned long *data_size, 39762306a36Sopenharmony_ci void *data) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci efi_status_t status; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 40262306a36Sopenharmony_ci return EFI_ABORTED; 40362306a36Sopenharmony_ci status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size, 40462306a36Sopenharmony_ci data); 40562306a36Sopenharmony_ci up(&efi_runtime_lock); 40662306a36Sopenharmony_ci return status; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 41062306a36Sopenharmony_ci efi_char16_t *name, 41162306a36Sopenharmony_ci efi_guid_t *vendor) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci efi_status_t status; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 41662306a36Sopenharmony_ci return EFI_ABORTED; 41762306a36Sopenharmony_ci status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor); 41862306a36Sopenharmony_ci up(&efi_runtime_lock); 41962306a36Sopenharmony_ci return status; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic efi_status_t virt_efi_set_variable(efi_char16_t *name, 42362306a36Sopenharmony_ci efi_guid_t *vendor, 42462306a36Sopenharmony_ci u32 attr, 42562306a36Sopenharmony_ci unsigned long data_size, 42662306a36Sopenharmony_ci void *data) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci efi_status_t status; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 43162306a36Sopenharmony_ci return EFI_ABORTED; 43262306a36Sopenharmony_ci status = efi_queue_work(SET_VARIABLE, name, vendor, attr, data_size, 43362306a36Sopenharmony_ci data); 43462306a36Sopenharmony_ci up(&efi_runtime_lock); 43562306a36Sopenharmony_ci return status; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic efi_status_t 43962306a36Sopenharmony_civirt_efi_set_variable_nb(efi_char16_t *name, efi_guid_t *vendor, u32 attr, 44062306a36Sopenharmony_ci unsigned long data_size, void *data) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci efi_status_t status; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (down_trylock(&efi_runtime_lock)) 44562306a36Sopenharmony_ci return EFI_NOT_READY; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci status = efi_call_virt_pointer(efi.runtime, set_variable, name, vendor, 44862306a36Sopenharmony_ci attr, data_size, data); 44962306a36Sopenharmony_ci up(&efi_runtime_lock); 45062306a36Sopenharmony_ci return status; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic efi_status_t virt_efi_query_variable_info(u32 attr, 45562306a36Sopenharmony_ci u64 *storage_space, 45662306a36Sopenharmony_ci u64 *remaining_space, 45762306a36Sopenharmony_ci u64 *max_variable_size) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci efi_status_t status; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 46262306a36Sopenharmony_ci return EFI_UNSUPPORTED; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 46562306a36Sopenharmony_ci return EFI_ABORTED; 46662306a36Sopenharmony_ci status = efi_queue_work(QUERY_VARIABLE_INFO, attr, storage_space, 46762306a36Sopenharmony_ci remaining_space, max_variable_size); 46862306a36Sopenharmony_ci up(&efi_runtime_lock); 46962306a36Sopenharmony_ci return status; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic efi_status_t 47362306a36Sopenharmony_civirt_efi_query_variable_info_nb(u32 attr, u64 *storage_space, 47462306a36Sopenharmony_ci u64 *remaining_space, u64 *max_variable_size) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci efi_status_t status; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 47962306a36Sopenharmony_ci return EFI_UNSUPPORTED; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (down_trylock(&efi_runtime_lock)) 48262306a36Sopenharmony_ci return EFI_NOT_READY; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci status = efi_call_virt_pointer(efi.runtime, query_variable_info, attr, 48562306a36Sopenharmony_ci storage_space, remaining_space, 48662306a36Sopenharmony_ci max_variable_size); 48762306a36Sopenharmony_ci up(&efi_runtime_lock); 48862306a36Sopenharmony_ci return status; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci efi_status_t status; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 49662306a36Sopenharmony_ci return EFI_ABORTED; 49762306a36Sopenharmony_ci status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count); 49862306a36Sopenharmony_ci up(&efi_runtime_lock); 49962306a36Sopenharmony_ci return status; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void virt_efi_reset_system(int reset_type, 50362306a36Sopenharmony_ci efi_status_t status, 50462306a36Sopenharmony_ci unsigned long data_size, 50562306a36Sopenharmony_ci efi_char16_t *data) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci if (down_trylock(&efi_runtime_lock)) { 50862306a36Sopenharmony_ci pr_warn("failed to invoke the reset_system() runtime service:\n" 50962306a36Sopenharmony_ci "could not get exclusive access to the firmware\n"); 51062306a36Sopenharmony_ci return; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci arch_efi_call_virt_setup(); 51462306a36Sopenharmony_ci efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM; 51562306a36Sopenharmony_ci arch_efi_call_virt(efi.runtime, reset_system, reset_type, status, 51662306a36Sopenharmony_ci data_size, data); 51762306a36Sopenharmony_ci arch_efi_call_virt_teardown(); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci up(&efi_runtime_lock); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 52362306a36Sopenharmony_ci unsigned long count, 52462306a36Sopenharmony_ci unsigned long sg_list) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci efi_status_t status; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 52962306a36Sopenharmony_ci return EFI_UNSUPPORTED; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 53262306a36Sopenharmony_ci return EFI_ABORTED; 53362306a36Sopenharmony_ci status = efi_queue_work(UPDATE_CAPSULE, capsules, count, sg_list); 53462306a36Sopenharmony_ci up(&efi_runtime_lock); 53562306a36Sopenharmony_ci return status; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 53962306a36Sopenharmony_ci unsigned long count, 54062306a36Sopenharmony_ci u64 *max_size, 54162306a36Sopenharmony_ci int *reset_type) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci efi_status_t status; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 54662306a36Sopenharmony_ci return EFI_UNSUPPORTED; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 54962306a36Sopenharmony_ci return EFI_ABORTED; 55062306a36Sopenharmony_ci status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, count, 55162306a36Sopenharmony_ci max_size, reset_type); 55262306a36Sopenharmony_ci up(&efi_runtime_lock); 55362306a36Sopenharmony_ci return status; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_civoid __init efi_native_runtime_setup(void) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci efi.get_time = virt_efi_get_time; 55962306a36Sopenharmony_ci efi.set_time = virt_efi_set_time; 56062306a36Sopenharmony_ci efi.get_wakeup_time = virt_efi_get_wakeup_time; 56162306a36Sopenharmony_ci efi.set_wakeup_time = virt_efi_set_wakeup_time; 56262306a36Sopenharmony_ci efi.get_variable = virt_efi_get_variable; 56362306a36Sopenharmony_ci efi.get_next_variable = virt_efi_get_next_variable; 56462306a36Sopenharmony_ci efi.set_variable = virt_efi_set_variable; 56562306a36Sopenharmony_ci efi.set_variable_nonblocking = virt_efi_set_variable_nb; 56662306a36Sopenharmony_ci efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 56762306a36Sopenharmony_ci efi.reset_system = virt_efi_reset_system; 56862306a36Sopenharmony_ci efi.query_variable_info = virt_efi_query_variable_info; 56962306a36Sopenharmony_ci efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nb; 57062306a36Sopenharmony_ci efi.update_capsule = virt_efi_update_capsule; 57162306a36Sopenharmony_ci efi.query_capsule_caps = virt_efi_query_capsule_caps; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci#ifdef CONFIG_ACPI_PRMT 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ciefi_status_t 57762306a36Sopenharmony_ciefi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *), 57862306a36Sopenharmony_ci u64 param_buffer_addr, void *context) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci efi_status_t status; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 58362306a36Sopenharmony_ci return EFI_ABORTED; 58462306a36Sopenharmony_ci status = efi_queue_work(ACPI_PRM_HANDLER, handler_addr, 58562306a36Sopenharmony_ci param_buffer_addr, context); 58662306a36Sopenharmony_ci up(&efi_runtime_lock); 58762306a36Sopenharmony_ci return status; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci#endif 591