155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2022ee6c5SArd Biesheuvel /* 3022ee6c5SArd Biesheuvel * runtime-wrappers.c - Runtime Services function call wrappers 4022ee6c5SArd Biesheuvel * 53eb420e7SSai Praneeth * Implementation summary: 63eb420e7SSai Praneeth * ----------------------- 73eb420e7SSai Praneeth * 1. When user/kernel thread requests to execute efi_runtime_service(), 83eb420e7SSai Praneeth * enqueue work to efi_rts_wq. 93eb420e7SSai Praneeth * 2. Caller thread waits for completion until the work is finished 103eb420e7SSai Praneeth * because it's dependent on the return status and execution of 113eb420e7SSai Praneeth * efi_runtime_service(). 123eb420e7SSai Praneeth * For instance, get_variable() and get_next_variable(). 133eb420e7SSai Praneeth * 14022ee6c5SArd Biesheuvel * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> 15022ee6c5SArd Biesheuvel * 16022ee6c5SArd Biesheuvel * Split off from arch/x86/platform/efi/efi.c 17022ee6c5SArd Biesheuvel * 18022ee6c5SArd Biesheuvel * Copyright (C) 1999 VA Linux Systems 19022ee6c5SArd Biesheuvel * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 20022ee6c5SArd Biesheuvel * Copyright (C) 1999-2002 Hewlett-Packard Co. 21022ee6c5SArd Biesheuvel * Copyright (C) 2005-2008 Intel Co. 22022ee6c5SArd Biesheuvel * Copyright (C) 2013 SuSE Labs 23022ee6c5SArd Biesheuvel */ 24022ee6c5SArd Biesheuvel 25dce48e35SArd Biesheuvel #define pr_fmt(fmt) "efi: " fmt 26dce48e35SArd Biesheuvel 27161485e8SArd Biesheuvel #include <linux/bug.h> 28022ee6c5SArd Biesheuvel #include <linux/efi.h> 291d04ba17SMark Rutland #include <linux/irqflags.h> 30161485e8SArd Biesheuvel #include <linux/mutex.h> 31dce48e35SArd Biesheuvel #include <linux/semaphore.h> 321d04ba17SMark Rutland #include <linux/stringify.h> 333eb420e7SSai Praneeth #include <linux/workqueue.h> 343eb420e7SSai Praneeth #include <linux/completion.h> 353eb420e7SSai Praneeth 36022ee6c5SArd Biesheuvel #include <asm/efi.h> 37022ee6c5SArd Biesheuvel 3880e75596SAlex Thorlton /* 3980e75596SAlex Thorlton * Wrap around the new efi_call_virt_generic() macros so that the 4080e75596SAlex Thorlton * code doesn't get too cluttered: 4180e75596SAlex Thorlton */ 4280e75596SAlex Thorlton #define efi_call_virt(f, args...) \ 4380e75596SAlex Thorlton efi_call_virt_pointer(efi.systab->runtime, f, args) 4480e75596SAlex Thorlton #define __efi_call_virt(f, args...) \ 4580e75596SAlex Thorlton __efi_call_virt_pointer(efi.systab->runtime, f, args) 4680e75596SAlex Thorlton 479dbbedaaSSai Praneeth struct efi_runtime_work efi_rts_work; 483eb420e7SSai Praneeth 493eb420e7SSai Praneeth /* 503eb420e7SSai Praneeth * efi_queue_work: Queue efi_runtime_service() and wait until it's done 513eb420e7SSai Praneeth * @rts: efi_runtime_service() function identifier 523eb420e7SSai Praneeth * @rts_arg<1-5>: efi_runtime_service() function arguments 533eb420e7SSai Praneeth * 543eb420e7SSai Praneeth * Accesses to efi_runtime_services() are serialized by a binary 553eb420e7SSai Praneeth * semaphore (efi_runtime_lock) and caller waits until the work is 563eb420e7SSai Praneeth * finished, hence _only_ one work is queued at a time and the caller 573eb420e7SSai Praneeth * thread waits for completion. 583eb420e7SSai Praneeth */ 593eb420e7SSai Praneeth #define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \ 603eb420e7SSai Praneeth ({ \ 613eb420e7SSai Praneeth efi_rts_work.status = EFI_ABORTED; \ 623eb420e7SSai Praneeth \ 633425d934SSai Praneeth if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \ 643425d934SSai Praneeth pr_warn_once("EFI Runtime Services are disabled!\n"); \ 653425d934SSai Praneeth goto exit; \ 663425d934SSai Praneeth } \ 673425d934SSai Praneeth \ 683eb420e7SSai Praneeth init_completion(&efi_rts_work.efi_rts_comp); \ 69ef1491e7SWaiman Long INIT_WORK(&efi_rts_work.work, efi_call_rts); \ 703eb420e7SSai Praneeth efi_rts_work.arg1 = _arg1; \ 713eb420e7SSai Praneeth efi_rts_work.arg2 = _arg2; \ 723eb420e7SSai Praneeth efi_rts_work.arg3 = _arg3; \ 733eb420e7SSai Praneeth efi_rts_work.arg4 = _arg4; \ 743eb420e7SSai Praneeth efi_rts_work.arg5 = _arg5; \ 753eb420e7SSai Praneeth efi_rts_work.efi_rts_id = _rts; \ 763eb420e7SSai Praneeth \ 773eb420e7SSai Praneeth /* \ 783eb420e7SSai Praneeth * queue_work() returns 0 if work was already on queue, \ 793eb420e7SSai Praneeth * _ideally_ this should never happen. \ 803eb420e7SSai Praneeth */ \ 813eb420e7SSai Praneeth if (queue_work(efi_rts_wq, &efi_rts_work.work)) \ 823eb420e7SSai Praneeth wait_for_completion(&efi_rts_work.efi_rts_comp); \ 833eb420e7SSai Praneeth else \ 843eb420e7SSai Praneeth pr_err("Failed to queue work to efi_rts_wq.\n"); \ 853eb420e7SSai Praneeth \ 863425d934SSai Praneeth exit: \ 875c418dc7SAnders Roxell efi_rts_work.efi_rts_id = EFI_NONE; \ 883eb420e7SSai Praneeth efi_rts_work.status; \ 893eb420e7SSai Praneeth }) 903eb420e7SSai Praneeth 9113b210ddSJulien Thierry #ifndef arch_efi_save_flags 9213b210ddSJulien Thierry #define arch_efi_save_flags(state_flags) local_save_flags(state_flags) 9313b210ddSJulien Thierry #define arch_efi_restore_flags(state_flags) local_irq_restore(state_flags) 9413b210ddSJulien Thierry #endif 9513b210ddSJulien Thierry 9613b210ddSJulien Thierry unsigned long efi_call_virt_save_flags(void) 9713b210ddSJulien Thierry { 9813b210ddSJulien Thierry unsigned long flags; 9913b210ddSJulien Thierry 10013b210ddSJulien Thierry arch_efi_save_flags(flags); 10113b210ddSJulien Thierry return flags; 10213b210ddSJulien Thierry } 10313b210ddSJulien Thierry 10480e75596SAlex Thorlton void efi_call_virt_check_flags(unsigned long flags, const char *call) 1051d04ba17SMark Rutland { 1061d04ba17SMark Rutland unsigned long cur_flags, mismatch; 1071d04ba17SMark Rutland 10813b210ddSJulien Thierry cur_flags = efi_call_virt_save_flags(); 1091d04ba17SMark Rutland 1101d04ba17SMark Rutland mismatch = flags ^ cur_flags; 1111d04ba17SMark Rutland if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK)) 1121d04ba17SMark Rutland return; 1131d04ba17SMark Rutland 1141d04ba17SMark Rutland add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE); 1151d04ba17SMark Rutland pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n", 1161d04ba17SMark Rutland flags, cur_flags, call); 11713b210ddSJulien Thierry arch_efi_restore_flags(flags); 1181d04ba17SMark Rutland } 1191d04ba17SMark Rutland 1201d04ba17SMark Rutland /* 121161485e8SArd Biesheuvel * According to section 7.1 of the UEFI spec, Runtime Services are not fully 122161485e8SArd Biesheuvel * reentrant, and there are particular combinations of calls that need to be 123161485e8SArd Biesheuvel * serialized. (source: UEFI Specification v2.4A) 124161485e8SArd Biesheuvel * 125161485e8SArd Biesheuvel * Table 31. Rules for Reentry Into Runtime Services 126161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 127161485e8SArd Biesheuvel * | If previous call is busy in | Forbidden to call | 128161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 129161485e8SArd Biesheuvel * | Any | SetVirtualAddressMap() | 130161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 131161485e8SArd Biesheuvel * | ConvertPointer() | ConvertPointer() | 132161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 133161485e8SArd Biesheuvel * | SetVariable() | ResetSystem() | 134161485e8SArd Biesheuvel * | UpdateCapsule() | | 135161485e8SArd Biesheuvel * | SetTime() | | 136161485e8SArd Biesheuvel * | SetWakeupTime() | | 137161485e8SArd Biesheuvel * | GetNextHighMonotonicCount() | | 138161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 139161485e8SArd Biesheuvel * | GetVariable() | GetVariable() | 140161485e8SArd Biesheuvel * | GetNextVariableName() | GetNextVariableName() | 141161485e8SArd Biesheuvel * | SetVariable() | SetVariable() | 142161485e8SArd Biesheuvel * | QueryVariableInfo() | QueryVariableInfo() | 143161485e8SArd Biesheuvel * | UpdateCapsule() | UpdateCapsule() | 144161485e8SArd Biesheuvel * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | 145161485e8SArd Biesheuvel * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | 146161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 147161485e8SArd Biesheuvel * | GetTime() | GetTime() | 148161485e8SArd Biesheuvel * | SetTime() | SetTime() | 149161485e8SArd Biesheuvel * | GetWakeupTime() | GetWakeupTime() | 150161485e8SArd Biesheuvel * | SetWakeupTime() | SetWakeupTime() | 151161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 152161485e8SArd Biesheuvel * 153161485e8SArd Biesheuvel * Due to the fact that the EFI pstore may write to the variable store in 154dce48e35SArd Biesheuvel * interrupt context, we need to use a lock for at least the groups that 155161485e8SArd Biesheuvel * contain SetVariable() and QueryVariableInfo(). That leaves little else, as 156161485e8SArd Biesheuvel * none of the remaining functions are actually ever called at runtime. 157dce48e35SArd Biesheuvel * So let's just use a single lock to serialize all Runtime Services calls. 158161485e8SArd Biesheuvel */ 159dce48e35SArd Biesheuvel static DEFINE_SEMAPHORE(efi_runtime_lock); 160161485e8SArd Biesheuvel 1613eb420e7SSai Praneeth /* 162f331e766SHedi Berriche * Expose the EFI runtime lock to the UV platform 163f331e766SHedi Berriche */ 164f331e766SHedi Berriche #ifdef CONFIG_X86_UV 165f331e766SHedi Berriche extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock); 166f331e766SHedi Berriche #endif 167f331e766SHedi Berriche 168f331e766SHedi Berriche /* 1693eb420e7SSai Praneeth * Calls the appropriate efi_runtime_service() with the appropriate 1703eb420e7SSai Praneeth * arguments. 1713eb420e7SSai Praneeth * 1723eb420e7SSai Praneeth * Semantics followed by efi_call_rts() to understand efi_runtime_work: 1733eb420e7SSai Praneeth * 1. If argument was a pointer, recast it from void pointer to original 1743eb420e7SSai Praneeth * pointer type. 1753eb420e7SSai Praneeth * 2. If argument was a value, recast it from void pointer to original 1763eb420e7SSai Praneeth * pointer type and dereference it. 1773eb420e7SSai Praneeth */ 1783eb420e7SSai Praneeth static void efi_call_rts(struct work_struct *work) 1793eb420e7SSai Praneeth { 1803eb420e7SSai Praneeth void *arg1, *arg2, *arg3, *arg4, *arg5; 1813eb420e7SSai Praneeth efi_status_t status = EFI_NOT_FOUND; 1823eb420e7SSai Praneeth 1839dbbedaaSSai Praneeth arg1 = efi_rts_work.arg1; 1849dbbedaaSSai Praneeth arg2 = efi_rts_work.arg2; 1859dbbedaaSSai Praneeth arg3 = efi_rts_work.arg3; 1869dbbedaaSSai Praneeth arg4 = efi_rts_work.arg4; 1879dbbedaaSSai Praneeth arg5 = efi_rts_work.arg5; 1883eb420e7SSai Praneeth 1899dbbedaaSSai Praneeth switch (efi_rts_work.efi_rts_id) { 1905c418dc7SAnders Roxell case EFI_GET_TIME: 1913eb420e7SSai Praneeth status = efi_call_virt(get_time, (efi_time_t *)arg1, 1923eb420e7SSai Praneeth (efi_time_cap_t *)arg2); 1933eb420e7SSai Praneeth break; 1945c418dc7SAnders Roxell case EFI_SET_TIME: 1953eb420e7SSai Praneeth status = efi_call_virt(set_time, (efi_time_t *)arg1); 1963eb420e7SSai Praneeth break; 1975c418dc7SAnders Roxell case EFI_GET_WAKEUP_TIME: 1983eb420e7SSai Praneeth status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1, 1993eb420e7SSai Praneeth (efi_bool_t *)arg2, (efi_time_t *)arg3); 2003eb420e7SSai Praneeth break; 2015c418dc7SAnders Roxell case EFI_SET_WAKEUP_TIME: 2023eb420e7SSai Praneeth status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1, 2033eb420e7SSai Praneeth (efi_time_t *)arg2); 2043eb420e7SSai Praneeth break; 2055c418dc7SAnders Roxell case EFI_GET_VARIABLE: 2063eb420e7SSai Praneeth status = efi_call_virt(get_variable, (efi_char16_t *)arg1, 2073eb420e7SSai Praneeth (efi_guid_t *)arg2, (u32 *)arg3, 2083eb420e7SSai Praneeth (unsigned long *)arg4, (void *)arg5); 2093eb420e7SSai Praneeth break; 2105c418dc7SAnders Roxell case EFI_GET_NEXT_VARIABLE: 2113eb420e7SSai Praneeth status = efi_call_virt(get_next_variable, (unsigned long *)arg1, 2123eb420e7SSai Praneeth (efi_char16_t *)arg2, 2133eb420e7SSai Praneeth (efi_guid_t *)arg3); 2143eb420e7SSai Praneeth break; 2155c418dc7SAnders Roxell case EFI_SET_VARIABLE: 2163eb420e7SSai Praneeth status = efi_call_virt(set_variable, (efi_char16_t *)arg1, 2173eb420e7SSai Praneeth (efi_guid_t *)arg2, *(u32 *)arg3, 2183eb420e7SSai Praneeth *(unsigned long *)arg4, (void *)arg5); 2193eb420e7SSai Praneeth break; 2205c418dc7SAnders Roxell case EFI_QUERY_VARIABLE_INFO: 2213eb420e7SSai Praneeth status = efi_call_virt(query_variable_info, *(u32 *)arg1, 2223eb420e7SSai Praneeth (u64 *)arg2, (u64 *)arg3, (u64 *)arg4); 2233eb420e7SSai Praneeth break; 2245c418dc7SAnders Roxell case EFI_GET_NEXT_HIGH_MONO_COUNT: 2253eb420e7SSai Praneeth status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1); 2263eb420e7SSai Praneeth break; 2275c418dc7SAnders Roxell case EFI_UPDATE_CAPSULE: 2283eb420e7SSai Praneeth status = efi_call_virt(update_capsule, 2293eb420e7SSai Praneeth (efi_capsule_header_t **)arg1, 2303eb420e7SSai Praneeth *(unsigned long *)arg2, 2313eb420e7SSai Praneeth *(unsigned long *)arg3); 2323eb420e7SSai Praneeth break; 2335c418dc7SAnders Roxell case EFI_QUERY_CAPSULE_CAPS: 2343eb420e7SSai Praneeth status = efi_call_virt(query_capsule_caps, 2353eb420e7SSai Praneeth (efi_capsule_header_t **)arg1, 2363eb420e7SSai Praneeth *(unsigned long *)arg2, (u64 *)arg3, 2373eb420e7SSai Praneeth (int *)arg4); 2383eb420e7SSai Praneeth break; 2393eb420e7SSai Praneeth default: 2403eb420e7SSai Praneeth /* 2413eb420e7SSai Praneeth * Ideally, we should never reach here because a caller of this 2423eb420e7SSai Praneeth * function should have put the right efi_runtime_service() 2433eb420e7SSai Praneeth * function identifier into efi_rts_work->efi_rts_id 2443eb420e7SSai Praneeth */ 2453eb420e7SSai Praneeth pr_err("Requested executing invalid EFI Runtime Service.\n"); 2463eb420e7SSai Praneeth } 2479dbbedaaSSai Praneeth efi_rts_work.status = status; 2489dbbedaaSSai Praneeth complete(&efi_rts_work.efi_rts_comp); 2493eb420e7SSai Praneeth } 2503eb420e7SSai Praneeth 251022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 252022ee6c5SArd Biesheuvel { 253022ee6c5SArd Biesheuvel efi_status_t status; 254022ee6c5SArd Biesheuvel 255dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 256dce48e35SArd Biesheuvel return EFI_ABORTED; 2575c418dc7SAnders Roxell status = efi_queue_work(EFI_GET_TIME, tm, tc, NULL, NULL, NULL); 258dce48e35SArd Biesheuvel up(&efi_runtime_lock); 259022ee6c5SArd Biesheuvel return status; 260022ee6c5SArd Biesheuvel } 261022ee6c5SArd Biesheuvel 262022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_time(efi_time_t *tm) 263022ee6c5SArd Biesheuvel { 264022ee6c5SArd Biesheuvel efi_status_t status; 265022ee6c5SArd Biesheuvel 266dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 267dce48e35SArd Biesheuvel return EFI_ABORTED; 2685c418dc7SAnders Roxell status = efi_queue_work(EFI_SET_TIME, tm, NULL, NULL, NULL, NULL); 269dce48e35SArd Biesheuvel up(&efi_runtime_lock); 270022ee6c5SArd Biesheuvel return status; 271022ee6c5SArd Biesheuvel } 272022ee6c5SArd Biesheuvel 273022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 274022ee6c5SArd Biesheuvel efi_bool_t *pending, 275022ee6c5SArd Biesheuvel efi_time_t *tm) 276022ee6c5SArd Biesheuvel { 277022ee6c5SArd Biesheuvel efi_status_t status; 278022ee6c5SArd Biesheuvel 279dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 280dce48e35SArd Biesheuvel return EFI_ABORTED; 2815c418dc7SAnders Roxell status = efi_queue_work(EFI_GET_WAKEUP_TIME, enabled, pending, tm, NULL, 2823eb420e7SSai Praneeth NULL); 283dce48e35SArd Biesheuvel up(&efi_runtime_lock); 284022ee6c5SArd Biesheuvel return status; 285022ee6c5SArd Biesheuvel } 286022ee6c5SArd Biesheuvel 287022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 288022ee6c5SArd Biesheuvel { 289022ee6c5SArd Biesheuvel efi_status_t status; 290022ee6c5SArd Biesheuvel 291dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 292dce48e35SArd Biesheuvel return EFI_ABORTED; 2935c418dc7SAnders Roxell status = efi_queue_work(EFI_SET_WAKEUP_TIME, &enabled, tm, NULL, NULL, 2943eb420e7SSai Praneeth NULL); 295dce48e35SArd Biesheuvel up(&efi_runtime_lock); 296022ee6c5SArd Biesheuvel return status; 297022ee6c5SArd Biesheuvel } 298022ee6c5SArd Biesheuvel 299022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_variable(efi_char16_t *name, 300022ee6c5SArd Biesheuvel efi_guid_t *vendor, 301022ee6c5SArd Biesheuvel u32 *attr, 302022ee6c5SArd Biesheuvel unsigned long *data_size, 303022ee6c5SArd Biesheuvel void *data) 304022ee6c5SArd Biesheuvel { 305161485e8SArd Biesheuvel efi_status_t status; 306161485e8SArd Biesheuvel 307dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 308dce48e35SArd Biesheuvel return EFI_ABORTED; 3095c418dc7SAnders Roxell status = efi_queue_work(EFI_GET_VARIABLE, name, vendor, attr, data_size, 310161485e8SArd Biesheuvel data); 311dce48e35SArd Biesheuvel up(&efi_runtime_lock); 312161485e8SArd Biesheuvel return status; 313022ee6c5SArd Biesheuvel } 314022ee6c5SArd Biesheuvel 315022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 316022ee6c5SArd Biesheuvel efi_char16_t *name, 317022ee6c5SArd Biesheuvel efi_guid_t *vendor) 318022ee6c5SArd Biesheuvel { 319161485e8SArd Biesheuvel efi_status_t status; 320161485e8SArd Biesheuvel 321dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 322dce48e35SArd Biesheuvel return EFI_ABORTED; 3235c418dc7SAnders Roxell status = efi_queue_work(EFI_GET_NEXT_VARIABLE, name_size, name, vendor, 3243eb420e7SSai Praneeth NULL, NULL); 325dce48e35SArd Biesheuvel up(&efi_runtime_lock); 326161485e8SArd Biesheuvel return status; 327022ee6c5SArd Biesheuvel } 328022ee6c5SArd Biesheuvel 329022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_variable(efi_char16_t *name, 330022ee6c5SArd Biesheuvel efi_guid_t *vendor, 331022ee6c5SArd Biesheuvel u32 attr, 332022ee6c5SArd Biesheuvel unsigned long data_size, 333022ee6c5SArd Biesheuvel void *data) 334022ee6c5SArd Biesheuvel { 335161485e8SArd Biesheuvel efi_status_t status; 336161485e8SArd Biesheuvel 337dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 338dce48e35SArd Biesheuvel return EFI_ABORTED; 3395c418dc7SAnders Roxell status = efi_queue_work(EFI_SET_VARIABLE, name, vendor, &attr, &data_size, 340161485e8SArd Biesheuvel data); 341dce48e35SArd Biesheuvel up(&efi_runtime_lock); 342161485e8SArd Biesheuvel return status; 343022ee6c5SArd Biesheuvel } 344022ee6c5SArd Biesheuvel 3456d80dba1SMatt Fleming static efi_status_t 3466d80dba1SMatt Fleming virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, 3476d80dba1SMatt Fleming u32 attr, unsigned long data_size, 3486d80dba1SMatt Fleming void *data) 3496d80dba1SMatt Fleming { 3506d80dba1SMatt Fleming efi_status_t status; 3516d80dba1SMatt Fleming 352dce48e35SArd Biesheuvel if (down_trylock(&efi_runtime_lock)) 3536d80dba1SMatt Fleming return EFI_NOT_READY; 3546d80dba1SMatt Fleming 3556d80dba1SMatt Fleming status = efi_call_virt(set_variable, name, vendor, attr, data_size, 3566d80dba1SMatt Fleming data); 357dce48e35SArd Biesheuvel up(&efi_runtime_lock); 3586d80dba1SMatt Fleming return status; 3596d80dba1SMatt Fleming } 3606d80dba1SMatt Fleming 3616d80dba1SMatt Fleming 362022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_variable_info(u32 attr, 363022ee6c5SArd Biesheuvel u64 *storage_space, 364022ee6c5SArd Biesheuvel u64 *remaining_space, 365022ee6c5SArd Biesheuvel u64 *max_variable_size) 366022ee6c5SArd Biesheuvel { 367161485e8SArd Biesheuvel efi_status_t status; 368161485e8SArd Biesheuvel 369022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 370022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 371022ee6c5SArd Biesheuvel 372dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 373dce48e35SArd Biesheuvel return EFI_ABORTED; 3745c418dc7SAnders Roxell status = efi_queue_work(EFI_QUERY_VARIABLE_INFO, &attr, storage_space, 3753eb420e7SSai Praneeth remaining_space, max_variable_size, NULL); 376dce48e35SArd Biesheuvel up(&efi_runtime_lock); 377161485e8SArd Biesheuvel return status; 378022ee6c5SArd Biesheuvel } 379022ee6c5SArd Biesheuvel 380d3cac1f8SArd Biesheuvel static efi_status_t 381d3cac1f8SArd Biesheuvel virt_efi_query_variable_info_nonblocking(u32 attr, 382d3cac1f8SArd Biesheuvel u64 *storage_space, 383d3cac1f8SArd Biesheuvel u64 *remaining_space, 384d3cac1f8SArd Biesheuvel u64 *max_variable_size) 385d3cac1f8SArd Biesheuvel { 386d3cac1f8SArd Biesheuvel efi_status_t status; 387d3cac1f8SArd Biesheuvel 388d3cac1f8SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 389d3cac1f8SArd Biesheuvel return EFI_UNSUPPORTED; 390d3cac1f8SArd Biesheuvel 391dce48e35SArd Biesheuvel if (down_trylock(&efi_runtime_lock)) 392d3cac1f8SArd Biesheuvel return EFI_NOT_READY; 393d3cac1f8SArd Biesheuvel 394d3cac1f8SArd Biesheuvel status = efi_call_virt(query_variable_info, attr, storage_space, 395d3cac1f8SArd Biesheuvel remaining_space, max_variable_size); 396dce48e35SArd Biesheuvel up(&efi_runtime_lock); 397d3cac1f8SArd Biesheuvel return status; 398d3cac1f8SArd Biesheuvel } 399d3cac1f8SArd Biesheuvel 400022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 401022ee6c5SArd Biesheuvel { 402161485e8SArd Biesheuvel efi_status_t status; 403161485e8SArd Biesheuvel 404dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 405dce48e35SArd Biesheuvel return EFI_ABORTED; 4065c418dc7SAnders Roxell status = efi_queue_work(EFI_GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL, 4073eb420e7SSai Praneeth NULL, NULL); 408dce48e35SArd Biesheuvel up(&efi_runtime_lock); 409161485e8SArd Biesheuvel return status; 410022ee6c5SArd Biesheuvel } 411022ee6c5SArd Biesheuvel 412022ee6c5SArd Biesheuvel static void virt_efi_reset_system(int reset_type, 413022ee6c5SArd Biesheuvel efi_status_t status, 414022ee6c5SArd Biesheuvel unsigned long data_size, 415022ee6c5SArd Biesheuvel efi_char16_t *data) 416022ee6c5SArd Biesheuvel { 417dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) { 418dce48e35SArd Biesheuvel pr_warn("failed to invoke the reset_system() runtime service:\n" 419dce48e35SArd Biesheuvel "could not get exclusive access to the firmware\n"); 420dce48e35SArd Biesheuvel return; 421dce48e35SArd Biesheuvel } 4225c418dc7SAnders Roxell efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM; 423022ee6c5SArd Biesheuvel __efi_call_virt(reset_system, reset_type, status, data_size, data); 424dce48e35SArd Biesheuvel up(&efi_runtime_lock); 425022ee6c5SArd Biesheuvel } 426022ee6c5SArd Biesheuvel 427022ee6c5SArd Biesheuvel static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 428022ee6c5SArd Biesheuvel unsigned long count, 429022ee6c5SArd Biesheuvel unsigned long sg_list) 430022ee6c5SArd Biesheuvel { 431161485e8SArd Biesheuvel efi_status_t status; 432161485e8SArd Biesheuvel 433022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 434022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 435022ee6c5SArd Biesheuvel 436dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 437dce48e35SArd Biesheuvel return EFI_ABORTED; 4385c418dc7SAnders Roxell status = efi_queue_work(EFI_UPDATE_CAPSULE, capsules, &count, &sg_list, 4393eb420e7SSai Praneeth NULL, NULL); 440dce48e35SArd Biesheuvel up(&efi_runtime_lock); 441161485e8SArd Biesheuvel return status; 442022ee6c5SArd Biesheuvel } 443022ee6c5SArd Biesheuvel 444022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 445022ee6c5SArd Biesheuvel unsigned long count, 446022ee6c5SArd Biesheuvel u64 *max_size, 447022ee6c5SArd Biesheuvel int *reset_type) 448022ee6c5SArd Biesheuvel { 449161485e8SArd Biesheuvel efi_status_t status; 450161485e8SArd Biesheuvel 451022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 452022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 453022ee6c5SArd Biesheuvel 454dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 455dce48e35SArd Biesheuvel return EFI_ABORTED; 4565c418dc7SAnders Roxell status = efi_queue_work(EFI_QUERY_CAPSULE_CAPS, capsules, &count, 4573eb420e7SSai Praneeth max_size, reset_type, NULL); 458dce48e35SArd Biesheuvel up(&efi_runtime_lock); 459161485e8SArd Biesheuvel return status; 460022ee6c5SArd Biesheuvel } 461022ee6c5SArd Biesheuvel 462022ee6c5SArd Biesheuvel void efi_native_runtime_setup(void) 463022ee6c5SArd Biesheuvel { 464022ee6c5SArd Biesheuvel efi.get_time = virt_efi_get_time; 465022ee6c5SArd Biesheuvel efi.set_time = virt_efi_set_time; 466022ee6c5SArd Biesheuvel efi.get_wakeup_time = virt_efi_get_wakeup_time; 467022ee6c5SArd Biesheuvel efi.set_wakeup_time = virt_efi_set_wakeup_time; 468022ee6c5SArd Biesheuvel efi.get_variable = virt_efi_get_variable; 469022ee6c5SArd Biesheuvel efi.get_next_variable = virt_efi_get_next_variable; 470022ee6c5SArd Biesheuvel efi.set_variable = virt_efi_set_variable; 4716d80dba1SMatt Fleming efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; 472022ee6c5SArd Biesheuvel efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 473022ee6c5SArd Biesheuvel efi.reset_system = virt_efi_reset_system; 474022ee6c5SArd Biesheuvel efi.query_variable_info = virt_efi_query_variable_info; 475d3cac1f8SArd Biesheuvel efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; 476022ee6c5SArd Biesheuvel efi.update_capsule = virt_efi_update_capsule; 477022ee6c5SArd Biesheuvel efi.query_capsule_caps = virt_efi_query_capsule_caps; 478022ee6c5SArd Biesheuvel } 479