18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * runtime-wrappers.c - Runtime Services function call wrappers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Implementation summary: 68c2ecf20Sopenharmony_ci * ----------------------- 78c2ecf20Sopenharmony_ci * 1. When user/kernel thread requests to execute efi_runtime_service(), 88c2ecf20Sopenharmony_ci * enqueue work to efi_rts_wq. 98c2ecf20Sopenharmony_ci * 2. Caller thread waits for completion until the work is finished 108c2ecf20Sopenharmony_ci * because it's dependent on the return status and execution of 118c2ecf20Sopenharmony_ci * efi_runtime_service(). 128c2ecf20Sopenharmony_ci * For instance, get_variable() and get_next_variable(). 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Split off from arch/x86/platform/efi/efi.c 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems 198c2ecf20Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 208c2ecf20Sopenharmony_ci * Copyright (C) 1999-2002 Hewlett-Packard Co. 218c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008 Intel Co. 228c2ecf20Sopenharmony_ci * Copyright (C) 2013 SuSE Labs 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "efi: " fmt 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/bug.h> 288c2ecf20Sopenharmony_ci#include <linux/efi.h> 298c2ecf20Sopenharmony_ci#include <linux/irqflags.h> 308c2ecf20Sopenharmony_ci#include <linux/mutex.h> 318c2ecf20Sopenharmony_ci#include <linux/semaphore.h> 328c2ecf20Sopenharmony_ci#include <linux/stringify.h> 338c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 348c2ecf20Sopenharmony_ci#include <linux/completion.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <asm/efi.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Wrap around the new efi_call_virt_generic() macros so that the 408c2ecf20Sopenharmony_ci * code doesn't get too cluttered: 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci#define efi_call_virt(f, args...) \ 438c2ecf20Sopenharmony_ci efi_call_virt_pointer(efi.runtime, f, args) 448c2ecf20Sopenharmony_ci#define __efi_call_virt(f, args...) \ 458c2ecf20Sopenharmony_ci __efi_call_virt_pointer(efi.runtime, f, args) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct efi_runtime_work efi_rts_work; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * efi_queue_work: Queue efi_runtime_service() and wait until it's done 518c2ecf20Sopenharmony_ci * @rts: efi_runtime_service() function identifier 528c2ecf20Sopenharmony_ci * @rts_arg<1-5>: efi_runtime_service() function arguments 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Accesses to efi_runtime_services() are serialized by a binary 558c2ecf20Sopenharmony_ci * semaphore (efi_runtime_lock) and caller waits until the work is 568c2ecf20Sopenharmony_ci * finished, hence _only_ one work is queued at a time and the caller 578c2ecf20Sopenharmony_ci * thread waits for completion. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \ 608c2ecf20Sopenharmony_ci({ \ 618c2ecf20Sopenharmony_ci efi_rts_work.status = EFI_ABORTED; \ 628c2ecf20Sopenharmony_ci \ 638c2ecf20Sopenharmony_ci if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \ 648c2ecf20Sopenharmony_ci pr_warn_once("EFI Runtime Services are disabled!\n"); \ 658c2ecf20Sopenharmony_ci efi_rts_work.status = EFI_DEVICE_ERROR; \ 668c2ecf20Sopenharmony_ci goto exit; \ 678c2ecf20Sopenharmony_ci } \ 688c2ecf20Sopenharmony_ci \ 698c2ecf20Sopenharmony_ci init_completion(&efi_rts_work.efi_rts_comp); \ 708c2ecf20Sopenharmony_ci INIT_WORK(&efi_rts_work.work, efi_call_rts); \ 718c2ecf20Sopenharmony_ci efi_rts_work.arg1 = _arg1; \ 728c2ecf20Sopenharmony_ci efi_rts_work.arg2 = _arg2; \ 738c2ecf20Sopenharmony_ci efi_rts_work.arg3 = _arg3; \ 748c2ecf20Sopenharmony_ci efi_rts_work.arg4 = _arg4; \ 758c2ecf20Sopenharmony_ci efi_rts_work.arg5 = _arg5; \ 768c2ecf20Sopenharmony_ci efi_rts_work.efi_rts_id = _rts; \ 778c2ecf20Sopenharmony_ci \ 788c2ecf20Sopenharmony_ci /* \ 798c2ecf20Sopenharmony_ci * queue_work() returns 0 if work was already on queue, \ 808c2ecf20Sopenharmony_ci * _ideally_ this should never happen. \ 818c2ecf20Sopenharmony_ci */ \ 828c2ecf20Sopenharmony_ci if (queue_work(efi_rts_wq, &efi_rts_work.work)) \ 838c2ecf20Sopenharmony_ci wait_for_completion(&efi_rts_work.efi_rts_comp); \ 848c2ecf20Sopenharmony_ci else \ 858c2ecf20Sopenharmony_ci pr_err("Failed to queue work to efi_rts_wq.\n"); \ 868c2ecf20Sopenharmony_ci \ 878c2ecf20Sopenharmony_ciexit: \ 888c2ecf20Sopenharmony_ci efi_rts_work.efi_rts_id = EFI_NONE; \ 898c2ecf20Sopenharmony_ci efi_rts_work.status; \ 908c2ecf20Sopenharmony_ci}) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#ifndef arch_efi_save_flags 938c2ecf20Sopenharmony_ci#define arch_efi_save_flags(state_flags) local_save_flags(state_flags) 948c2ecf20Sopenharmony_ci#define arch_efi_restore_flags(state_flags) local_irq_restore(state_flags) 958c2ecf20Sopenharmony_ci#endif 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciunsigned long efi_call_virt_save_flags(void) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci unsigned long flags; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci arch_efi_save_flags(flags); 1028c2ecf20Sopenharmony_ci return flags; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_civoid efi_call_virt_check_flags(unsigned long flags, const char *call) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci unsigned long cur_flags, mismatch; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci cur_flags = efi_call_virt_save_flags(); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci mismatch = flags ^ cur_flags; 1128c2ecf20Sopenharmony_ci if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK)) 1138c2ecf20Sopenharmony_ci return; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE); 1168c2ecf20Sopenharmony_ci pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n", 1178c2ecf20Sopenharmony_ci flags, cur_flags, call); 1188c2ecf20Sopenharmony_ci arch_efi_restore_flags(flags); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * According to section 7.1 of the UEFI spec, Runtime Services are not fully 1238c2ecf20Sopenharmony_ci * reentrant, and there are particular combinations of calls that need to be 1248c2ecf20Sopenharmony_ci * serialized. (source: UEFI Specification v2.4A) 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Table 31. Rules for Reentry Into Runtime Services 1278c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1288c2ecf20Sopenharmony_ci * | If previous call is busy in | Forbidden to call | 1298c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1308c2ecf20Sopenharmony_ci * | Any | SetVirtualAddressMap() | 1318c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1328c2ecf20Sopenharmony_ci * | ConvertPointer() | ConvertPointer() | 1338c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1348c2ecf20Sopenharmony_ci * | SetVariable() | ResetSystem() | 1358c2ecf20Sopenharmony_ci * | UpdateCapsule() | | 1368c2ecf20Sopenharmony_ci * | SetTime() | | 1378c2ecf20Sopenharmony_ci * | SetWakeupTime() | | 1388c2ecf20Sopenharmony_ci * | GetNextHighMonotonicCount() | | 1398c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1408c2ecf20Sopenharmony_ci * | GetVariable() | GetVariable() | 1418c2ecf20Sopenharmony_ci * | GetNextVariableName() | GetNextVariableName() | 1428c2ecf20Sopenharmony_ci * | SetVariable() | SetVariable() | 1438c2ecf20Sopenharmony_ci * | QueryVariableInfo() | QueryVariableInfo() | 1448c2ecf20Sopenharmony_ci * | UpdateCapsule() | UpdateCapsule() | 1458c2ecf20Sopenharmony_ci * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | 1468c2ecf20Sopenharmony_ci * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | 1478c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1488c2ecf20Sopenharmony_ci * | GetTime() | GetTime() | 1498c2ecf20Sopenharmony_ci * | SetTime() | SetTime() | 1508c2ecf20Sopenharmony_ci * | GetWakeupTime() | GetWakeupTime() | 1518c2ecf20Sopenharmony_ci * | SetWakeupTime() | SetWakeupTime() | 1528c2ecf20Sopenharmony_ci * +------------------------------------+-------------------------------+ 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * Due to the fact that the EFI pstore may write to the variable store in 1558c2ecf20Sopenharmony_ci * interrupt context, we need to use a lock for at least the groups that 1568c2ecf20Sopenharmony_ci * contain SetVariable() and QueryVariableInfo(). That leaves little else, as 1578c2ecf20Sopenharmony_ci * none of the remaining functions are actually ever called at runtime. 1588c2ecf20Sopenharmony_ci * So let's just use a single lock to serialize all Runtime Services calls. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic DEFINE_SEMAPHORE(efi_runtime_lock); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * Expose the EFI runtime lock to the UV platform 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_UV 1668c2ecf20Sopenharmony_ciextern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock); 1678c2ecf20Sopenharmony_ci#endif 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * Calls the appropriate efi_runtime_service() with the appropriate 1718c2ecf20Sopenharmony_ci * arguments. 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * Semantics followed by efi_call_rts() to understand efi_runtime_work: 1748c2ecf20Sopenharmony_ci * 1. If argument was a pointer, recast it from void pointer to original 1758c2ecf20Sopenharmony_ci * pointer type. 1768c2ecf20Sopenharmony_ci * 2. If argument was a value, recast it from void pointer to original 1778c2ecf20Sopenharmony_ci * pointer type and dereference it. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void efi_call_rts(struct work_struct *work) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci void *arg1, *arg2, *arg3, *arg4, *arg5; 1828c2ecf20Sopenharmony_ci efi_status_t status = EFI_NOT_FOUND; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci arg1 = efi_rts_work.arg1; 1858c2ecf20Sopenharmony_ci arg2 = efi_rts_work.arg2; 1868c2ecf20Sopenharmony_ci arg3 = efi_rts_work.arg3; 1878c2ecf20Sopenharmony_ci arg4 = efi_rts_work.arg4; 1888c2ecf20Sopenharmony_ci arg5 = efi_rts_work.arg5; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci switch (efi_rts_work.efi_rts_id) { 1918c2ecf20Sopenharmony_ci case EFI_GET_TIME: 1928c2ecf20Sopenharmony_ci status = efi_call_virt(get_time, (efi_time_t *)arg1, 1938c2ecf20Sopenharmony_ci (efi_time_cap_t *)arg2); 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci case EFI_SET_TIME: 1968c2ecf20Sopenharmony_ci status = efi_call_virt(set_time, (efi_time_t *)arg1); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case EFI_GET_WAKEUP_TIME: 1998c2ecf20Sopenharmony_ci status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1, 2008c2ecf20Sopenharmony_ci (efi_bool_t *)arg2, (efi_time_t *)arg3); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci case EFI_SET_WAKEUP_TIME: 2038c2ecf20Sopenharmony_ci status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1, 2048c2ecf20Sopenharmony_ci (efi_time_t *)arg2); 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case EFI_GET_VARIABLE: 2078c2ecf20Sopenharmony_ci status = efi_call_virt(get_variable, (efi_char16_t *)arg1, 2088c2ecf20Sopenharmony_ci (efi_guid_t *)arg2, (u32 *)arg3, 2098c2ecf20Sopenharmony_ci (unsigned long *)arg4, (void *)arg5); 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci case EFI_GET_NEXT_VARIABLE: 2128c2ecf20Sopenharmony_ci status = efi_call_virt(get_next_variable, (unsigned long *)arg1, 2138c2ecf20Sopenharmony_ci (efi_char16_t *)arg2, 2148c2ecf20Sopenharmony_ci (efi_guid_t *)arg3); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case EFI_SET_VARIABLE: 2178c2ecf20Sopenharmony_ci status = efi_call_virt(set_variable, (efi_char16_t *)arg1, 2188c2ecf20Sopenharmony_ci (efi_guid_t *)arg2, *(u32 *)arg3, 2198c2ecf20Sopenharmony_ci *(unsigned long *)arg4, (void *)arg5); 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case EFI_QUERY_VARIABLE_INFO: 2228c2ecf20Sopenharmony_ci status = efi_call_virt(query_variable_info, *(u32 *)arg1, 2238c2ecf20Sopenharmony_ci (u64 *)arg2, (u64 *)arg3, (u64 *)arg4); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case EFI_GET_NEXT_HIGH_MONO_COUNT: 2268c2ecf20Sopenharmony_ci status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case EFI_UPDATE_CAPSULE: 2298c2ecf20Sopenharmony_ci status = efi_call_virt(update_capsule, 2308c2ecf20Sopenharmony_ci (efi_capsule_header_t **)arg1, 2318c2ecf20Sopenharmony_ci *(unsigned long *)arg2, 2328c2ecf20Sopenharmony_ci *(unsigned long *)arg3); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci case EFI_QUERY_CAPSULE_CAPS: 2358c2ecf20Sopenharmony_ci status = efi_call_virt(query_capsule_caps, 2368c2ecf20Sopenharmony_ci (efi_capsule_header_t **)arg1, 2378c2ecf20Sopenharmony_ci *(unsigned long *)arg2, (u64 *)arg3, 2388c2ecf20Sopenharmony_ci (int *)arg4); 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci default: 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * Ideally, we should never reach here because a caller of this 2438c2ecf20Sopenharmony_ci * function should have put the right efi_runtime_service() 2448c2ecf20Sopenharmony_ci * function identifier into efi_rts_work->efi_rts_id 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci pr_err("Requested executing invalid EFI Runtime Service.\n"); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci efi_rts_work.status = status; 2498c2ecf20Sopenharmony_ci complete(&efi_rts_work.efi_rts_comp); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci efi_status_t status; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 2578c2ecf20Sopenharmony_ci return EFI_ABORTED; 2588c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_GET_TIME, tm, tc, NULL, NULL, NULL); 2598c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 2608c2ecf20Sopenharmony_ci return status; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_set_time(efi_time_t *tm) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci efi_status_t status; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 2688c2ecf20Sopenharmony_ci return EFI_ABORTED; 2698c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_SET_TIME, tm, NULL, NULL, NULL, NULL); 2708c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 2718c2ecf20Sopenharmony_ci return status; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 2758c2ecf20Sopenharmony_ci efi_bool_t *pending, 2768c2ecf20Sopenharmony_ci efi_time_t *tm) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci efi_status_t status; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 2818c2ecf20Sopenharmony_ci return EFI_ABORTED; 2828c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_GET_WAKEUP_TIME, enabled, pending, tm, NULL, 2838c2ecf20Sopenharmony_ci NULL); 2848c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 2858c2ecf20Sopenharmony_ci return status; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci efi_status_t status; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 2938c2ecf20Sopenharmony_ci return EFI_ABORTED; 2948c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_SET_WAKEUP_TIME, &enabled, tm, NULL, NULL, 2958c2ecf20Sopenharmony_ci NULL); 2968c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 2978c2ecf20Sopenharmony_ci return status; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_get_variable(efi_char16_t *name, 3018c2ecf20Sopenharmony_ci efi_guid_t *vendor, 3028c2ecf20Sopenharmony_ci u32 *attr, 3038c2ecf20Sopenharmony_ci unsigned long *data_size, 3048c2ecf20Sopenharmony_ci void *data) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci efi_status_t status; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 3098c2ecf20Sopenharmony_ci return EFI_ABORTED; 3108c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_GET_VARIABLE, name, vendor, attr, data_size, 3118c2ecf20Sopenharmony_ci data); 3128c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 3138c2ecf20Sopenharmony_ci return status; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 3178c2ecf20Sopenharmony_ci efi_char16_t *name, 3188c2ecf20Sopenharmony_ci efi_guid_t *vendor) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci efi_status_t status; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 3238c2ecf20Sopenharmony_ci return EFI_ABORTED; 3248c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_GET_NEXT_VARIABLE, name_size, name, vendor, 3258c2ecf20Sopenharmony_ci NULL, NULL); 3268c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 3278c2ecf20Sopenharmony_ci return status; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_set_variable(efi_char16_t *name, 3318c2ecf20Sopenharmony_ci efi_guid_t *vendor, 3328c2ecf20Sopenharmony_ci u32 attr, 3338c2ecf20Sopenharmony_ci unsigned long data_size, 3348c2ecf20Sopenharmony_ci void *data) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci efi_status_t status; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 3398c2ecf20Sopenharmony_ci return EFI_ABORTED; 3408c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_SET_VARIABLE, name, vendor, &attr, &data_size, 3418c2ecf20Sopenharmony_ci data); 3428c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 3438c2ecf20Sopenharmony_ci return status; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic efi_status_t 3478c2ecf20Sopenharmony_civirt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, 3488c2ecf20Sopenharmony_ci u32 attr, unsigned long data_size, 3498c2ecf20Sopenharmony_ci void *data) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci efi_status_t status; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (down_trylock(&efi_runtime_lock)) 3548c2ecf20Sopenharmony_ci return EFI_NOT_READY; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci status = efi_call_virt(set_variable, name, vendor, attr, data_size, 3578c2ecf20Sopenharmony_ci data); 3588c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 3598c2ecf20Sopenharmony_ci return status; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_query_variable_info(u32 attr, 3648c2ecf20Sopenharmony_ci u64 *storage_space, 3658c2ecf20Sopenharmony_ci u64 *remaining_space, 3668c2ecf20Sopenharmony_ci u64 *max_variable_size) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci efi_status_t status; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 3718c2ecf20Sopenharmony_ci return EFI_UNSUPPORTED; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 3748c2ecf20Sopenharmony_ci return EFI_ABORTED; 3758c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_QUERY_VARIABLE_INFO, &attr, storage_space, 3768c2ecf20Sopenharmony_ci remaining_space, max_variable_size, NULL); 3778c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 3788c2ecf20Sopenharmony_ci return status; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic efi_status_t 3828c2ecf20Sopenharmony_civirt_efi_query_variable_info_nonblocking(u32 attr, 3838c2ecf20Sopenharmony_ci u64 *storage_space, 3848c2ecf20Sopenharmony_ci u64 *remaining_space, 3858c2ecf20Sopenharmony_ci u64 *max_variable_size) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci efi_status_t status; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 3908c2ecf20Sopenharmony_ci return EFI_UNSUPPORTED; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (down_trylock(&efi_runtime_lock)) 3938c2ecf20Sopenharmony_ci return EFI_NOT_READY; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci status = efi_call_virt(query_variable_info, attr, storage_space, 3968c2ecf20Sopenharmony_ci remaining_space, max_variable_size); 3978c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 3988c2ecf20Sopenharmony_ci return status; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci efi_status_t status; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 4068c2ecf20Sopenharmony_ci return EFI_ABORTED; 4078c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL, 4088c2ecf20Sopenharmony_ci NULL, NULL); 4098c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 4108c2ecf20Sopenharmony_ci return status; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic void virt_efi_reset_system(int reset_type, 4148c2ecf20Sopenharmony_ci efi_status_t status, 4158c2ecf20Sopenharmony_ci unsigned long data_size, 4168c2ecf20Sopenharmony_ci efi_char16_t *data) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci if (down_trylock(&efi_runtime_lock)) { 4198c2ecf20Sopenharmony_ci pr_warn("failed to invoke the reset_system() runtime service:\n" 4208c2ecf20Sopenharmony_ci "could not get exclusive access to the firmware\n"); 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM; 4248c2ecf20Sopenharmony_ci __efi_call_virt(reset_system, reset_type, status, data_size, data); 4258c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 4298c2ecf20Sopenharmony_ci unsigned long count, 4308c2ecf20Sopenharmony_ci unsigned long sg_list) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci efi_status_t status; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 4358c2ecf20Sopenharmony_ci return EFI_UNSUPPORTED; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 4388c2ecf20Sopenharmony_ci return EFI_ABORTED; 4398c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_UPDATE_CAPSULE, capsules, &count, &sg_list, 4408c2ecf20Sopenharmony_ci NULL, NULL); 4418c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 4428c2ecf20Sopenharmony_ci return status; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 4468c2ecf20Sopenharmony_ci unsigned long count, 4478c2ecf20Sopenharmony_ci u64 *max_size, 4488c2ecf20Sopenharmony_ci int *reset_type) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci efi_status_t status; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 4538c2ecf20Sopenharmony_ci return EFI_UNSUPPORTED; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (down_interruptible(&efi_runtime_lock)) 4568c2ecf20Sopenharmony_ci return EFI_ABORTED; 4578c2ecf20Sopenharmony_ci status = efi_queue_work(EFI_QUERY_CAPSULE_CAPS, capsules, &count, 4588c2ecf20Sopenharmony_ci max_size, reset_type, NULL); 4598c2ecf20Sopenharmony_ci up(&efi_runtime_lock); 4608c2ecf20Sopenharmony_ci return status; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_civoid efi_native_runtime_setup(void) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci efi.get_time = virt_efi_get_time; 4668c2ecf20Sopenharmony_ci efi.set_time = virt_efi_set_time; 4678c2ecf20Sopenharmony_ci efi.get_wakeup_time = virt_efi_get_wakeup_time; 4688c2ecf20Sopenharmony_ci efi.set_wakeup_time = virt_efi_set_wakeup_time; 4698c2ecf20Sopenharmony_ci efi.get_variable = virt_efi_get_variable; 4708c2ecf20Sopenharmony_ci efi.get_next_variable = virt_efi_get_next_variable; 4718c2ecf20Sopenharmony_ci efi.set_variable = virt_efi_set_variable; 4728c2ecf20Sopenharmony_ci efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; 4738c2ecf20Sopenharmony_ci efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 4748c2ecf20Sopenharmony_ci efi.reset_system = virt_efi_reset_system; 4758c2ecf20Sopenharmony_ci efi.query_variable_info = virt_efi_query_variable_info; 4768c2ecf20Sopenharmony_ci efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; 4778c2ecf20Sopenharmony_ci efi.update_capsule = virt_efi_update_capsule; 4788c2ecf20Sopenharmony_ci efi.query_capsule_caps = virt_efi_query_capsule_caps; 4798c2ecf20Sopenharmony_ci} 480