1022ee6c5SArd Biesheuvel /* 2022ee6c5SArd Biesheuvel * runtime-wrappers.c - Runtime Services function call wrappers 3022ee6c5SArd Biesheuvel * 43eb420e7SSai Praneeth * Implementation summary: 53eb420e7SSai Praneeth * ----------------------- 63eb420e7SSai Praneeth * 1. When user/kernel thread requests to execute efi_runtime_service(), 73eb420e7SSai Praneeth * enqueue work to efi_rts_wq. 83eb420e7SSai Praneeth * 2. Caller thread waits for completion until the work is finished 93eb420e7SSai Praneeth * because it's dependent on the return status and execution of 103eb420e7SSai Praneeth * efi_runtime_service(). 113eb420e7SSai Praneeth * For instance, get_variable() and get_next_variable(). 123eb420e7SSai Praneeth * 13022ee6c5SArd Biesheuvel * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> 14022ee6c5SArd Biesheuvel * 15022ee6c5SArd Biesheuvel * Split off from arch/x86/platform/efi/efi.c 16022ee6c5SArd Biesheuvel * 17022ee6c5SArd Biesheuvel * Copyright (C) 1999 VA Linux Systems 18022ee6c5SArd Biesheuvel * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 19022ee6c5SArd Biesheuvel * Copyright (C) 1999-2002 Hewlett-Packard Co. 20022ee6c5SArd Biesheuvel * Copyright (C) 2005-2008 Intel Co. 21022ee6c5SArd Biesheuvel * Copyright (C) 2013 SuSE Labs 22022ee6c5SArd Biesheuvel * 23022ee6c5SArd Biesheuvel * This file is released under the GPLv2. 24022ee6c5SArd Biesheuvel */ 25022ee6c5SArd Biesheuvel 26dce48e35SArd Biesheuvel #define pr_fmt(fmt) "efi: " fmt 27dce48e35SArd Biesheuvel 28161485e8SArd Biesheuvel #include <linux/bug.h> 29022ee6c5SArd Biesheuvel #include <linux/efi.h> 301d04ba17SMark Rutland #include <linux/irqflags.h> 31161485e8SArd Biesheuvel #include <linux/mutex.h> 32dce48e35SArd Biesheuvel #include <linux/semaphore.h> 331d04ba17SMark Rutland #include <linux/stringify.h> 343eb420e7SSai Praneeth #include <linux/workqueue.h> 353eb420e7SSai Praneeth #include <linux/completion.h> 363eb420e7SSai Praneeth 37022ee6c5SArd Biesheuvel #include <asm/efi.h> 38022ee6c5SArd Biesheuvel 3980e75596SAlex Thorlton /* 4080e75596SAlex Thorlton * Wrap around the new efi_call_virt_generic() macros so that the 4180e75596SAlex Thorlton * code doesn't get too cluttered: 4280e75596SAlex Thorlton */ 4380e75596SAlex Thorlton #define efi_call_virt(f, args...) \ 4480e75596SAlex Thorlton efi_call_virt_pointer(efi.systab->runtime, f, args) 4580e75596SAlex Thorlton #define __efi_call_virt(f, args...) \ 4680e75596SAlex Thorlton __efi_call_virt_pointer(efi.systab->runtime, f, args) 4780e75596SAlex Thorlton 489dbbedaaSSai Praneeth struct efi_runtime_work efi_rts_work; 493eb420e7SSai Praneeth 503eb420e7SSai Praneeth /* 513eb420e7SSai Praneeth * efi_queue_work: Queue efi_runtime_service() and wait until it's done 523eb420e7SSai Praneeth * @rts: efi_runtime_service() function identifier 533eb420e7SSai Praneeth * @rts_arg<1-5>: efi_runtime_service() function arguments 543eb420e7SSai Praneeth * 553eb420e7SSai Praneeth * Accesses to efi_runtime_services() are serialized by a binary 563eb420e7SSai Praneeth * semaphore (efi_runtime_lock) and caller waits until the work is 573eb420e7SSai Praneeth * finished, hence _only_ one work is queued at a time and the caller 583eb420e7SSai Praneeth * thread waits for completion. 593eb420e7SSai Praneeth */ 603eb420e7SSai Praneeth #define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \ 613eb420e7SSai Praneeth ({ \ 623eb420e7SSai Praneeth efi_rts_work.status = EFI_ABORTED; \ 633eb420e7SSai Praneeth \ 643425d934SSai Praneeth if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \ 653425d934SSai Praneeth pr_warn_once("EFI Runtime Services are disabled!\n"); \ 663425d934SSai Praneeth goto exit; \ 673425d934SSai Praneeth } \ 683425d934SSai Praneeth \ 693eb420e7SSai Praneeth init_completion(&efi_rts_work.efi_rts_comp); \ 70ef1491e7SWaiman Long INIT_WORK(&efi_rts_work.work, efi_call_rts); \ 713eb420e7SSai Praneeth efi_rts_work.arg1 = _arg1; \ 723eb420e7SSai Praneeth efi_rts_work.arg2 = _arg2; \ 733eb420e7SSai Praneeth efi_rts_work.arg3 = _arg3; \ 743eb420e7SSai Praneeth efi_rts_work.arg4 = _arg4; \ 753eb420e7SSai Praneeth efi_rts_work.arg5 = _arg5; \ 763eb420e7SSai Praneeth efi_rts_work.efi_rts_id = _rts; \ 773eb420e7SSai Praneeth \ 783eb420e7SSai Praneeth /* \ 793eb420e7SSai Praneeth * queue_work() returns 0 if work was already on queue, \ 803eb420e7SSai Praneeth * _ideally_ this should never happen. \ 813eb420e7SSai Praneeth */ \ 823eb420e7SSai Praneeth if (queue_work(efi_rts_wq, &efi_rts_work.work)) \ 833eb420e7SSai Praneeth wait_for_completion(&efi_rts_work.efi_rts_comp); \ 843eb420e7SSai Praneeth else \ 853eb420e7SSai Praneeth pr_err("Failed to queue work to efi_rts_wq.\n"); \ 863eb420e7SSai Praneeth \ 873425d934SSai Praneeth exit: \ 883425d934SSai Praneeth efi_rts_work.efi_rts_id = NONE; \ 893eb420e7SSai Praneeth efi_rts_work.status; \ 903eb420e7SSai Praneeth }) 913eb420e7SSai Praneeth 9280e75596SAlex Thorlton void efi_call_virt_check_flags(unsigned long flags, const char *call) 931d04ba17SMark Rutland { 941d04ba17SMark Rutland unsigned long cur_flags, mismatch; 951d04ba17SMark Rutland 961d04ba17SMark Rutland local_save_flags(cur_flags); 971d04ba17SMark Rutland 981d04ba17SMark Rutland mismatch = flags ^ cur_flags; 991d04ba17SMark Rutland if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK)) 1001d04ba17SMark Rutland return; 1011d04ba17SMark Rutland 1021d04ba17SMark Rutland add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE); 1031d04ba17SMark Rutland pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n", 1041d04ba17SMark Rutland flags, cur_flags, call); 1051d04ba17SMark Rutland local_irq_restore(flags); 1061d04ba17SMark Rutland } 1071d04ba17SMark Rutland 1081d04ba17SMark Rutland /* 109161485e8SArd Biesheuvel * According to section 7.1 of the UEFI spec, Runtime Services are not fully 110161485e8SArd Biesheuvel * reentrant, and there are particular combinations of calls that need to be 111161485e8SArd Biesheuvel * serialized. (source: UEFI Specification v2.4A) 112161485e8SArd Biesheuvel * 113161485e8SArd Biesheuvel * Table 31. Rules for Reentry Into Runtime Services 114161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 115161485e8SArd Biesheuvel * | If previous call is busy in | Forbidden to call | 116161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 117161485e8SArd Biesheuvel * | Any | SetVirtualAddressMap() | 118161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 119161485e8SArd Biesheuvel * | ConvertPointer() | ConvertPointer() | 120161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 121161485e8SArd Biesheuvel * | SetVariable() | ResetSystem() | 122161485e8SArd Biesheuvel * | UpdateCapsule() | | 123161485e8SArd Biesheuvel * | SetTime() | | 124161485e8SArd Biesheuvel * | SetWakeupTime() | | 125161485e8SArd Biesheuvel * | GetNextHighMonotonicCount() | | 126161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 127161485e8SArd Biesheuvel * | GetVariable() | GetVariable() | 128161485e8SArd Biesheuvel * | GetNextVariableName() | GetNextVariableName() | 129161485e8SArd Biesheuvel * | SetVariable() | SetVariable() | 130161485e8SArd Biesheuvel * | QueryVariableInfo() | QueryVariableInfo() | 131161485e8SArd Biesheuvel * | UpdateCapsule() | UpdateCapsule() | 132161485e8SArd Biesheuvel * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | 133161485e8SArd Biesheuvel * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | 134161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 135161485e8SArd Biesheuvel * | GetTime() | GetTime() | 136161485e8SArd Biesheuvel * | SetTime() | SetTime() | 137161485e8SArd Biesheuvel * | GetWakeupTime() | GetWakeupTime() | 138161485e8SArd Biesheuvel * | SetWakeupTime() | SetWakeupTime() | 139161485e8SArd Biesheuvel * +------------------------------------+-------------------------------+ 140161485e8SArd Biesheuvel * 141161485e8SArd Biesheuvel * Due to the fact that the EFI pstore may write to the variable store in 142dce48e35SArd Biesheuvel * interrupt context, we need to use a lock for at least the groups that 143161485e8SArd Biesheuvel * contain SetVariable() and QueryVariableInfo(). That leaves little else, as 144161485e8SArd Biesheuvel * none of the remaining functions are actually ever called at runtime. 145dce48e35SArd Biesheuvel * So let's just use a single lock to serialize all Runtime Services calls. 146161485e8SArd Biesheuvel */ 147dce48e35SArd Biesheuvel static DEFINE_SEMAPHORE(efi_runtime_lock); 148161485e8SArd Biesheuvel 1493eb420e7SSai Praneeth /* 150f331e766SHedi Berriche * Expose the EFI runtime lock to the UV platform 151f331e766SHedi Berriche */ 152f331e766SHedi Berriche #ifdef CONFIG_X86_UV 153f331e766SHedi Berriche extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock); 154f331e766SHedi Berriche #endif 155f331e766SHedi Berriche 156f331e766SHedi Berriche /* 1573eb420e7SSai Praneeth * Calls the appropriate efi_runtime_service() with the appropriate 1583eb420e7SSai Praneeth * arguments. 1593eb420e7SSai Praneeth * 1603eb420e7SSai Praneeth * Semantics followed by efi_call_rts() to understand efi_runtime_work: 1613eb420e7SSai Praneeth * 1. If argument was a pointer, recast it from void pointer to original 1623eb420e7SSai Praneeth * pointer type. 1633eb420e7SSai Praneeth * 2. If argument was a value, recast it from void pointer to original 1643eb420e7SSai Praneeth * pointer type and dereference it. 1653eb420e7SSai Praneeth */ 1663eb420e7SSai Praneeth static void efi_call_rts(struct work_struct *work) 1673eb420e7SSai Praneeth { 1683eb420e7SSai Praneeth void *arg1, *arg2, *arg3, *arg4, *arg5; 1693eb420e7SSai Praneeth efi_status_t status = EFI_NOT_FOUND; 1703eb420e7SSai Praneeth 1719dbbedaaSSai Praneeth arg1 = efi_rts_work.arg1; 1729dbbedaaSSai Praneeth arg2 = efi_rts_work.arg2; 1739dbbedaaSSai Praneeth arg3 = efi_rts_work.arg3; 1749dbbedaaSSai Praneeth arg4 = efi_rts_work.arg4; 1759dbbedaaSSai Praneeth arg5 = efi_rts_work.arg5; 1763eb420e7SSai Praneeth 1779dbbedaaSSai Praneeth switch (efi_rts_work.efi_rts_id) { 1783eb420e7SSai Praneeth case GET_TIME: 1793eb420e7SSai Praneeth status = efi_call_virt(get_time, (efi_time_t *)arg1, 1803eb420e7SSai Praneeth (efi_time_cap_t *)arg2); 1813eb420e7SSai Praneeth break; 1823eb420e7SSai Praneeth case SET_TIME: 1833eb420e7SSai Praneeth status = efi_call_virt(set_time, (efi_time_t *)arg1); 1843eb420e7SSai Praneeth break; 1853eb420e7SSai Praneeth case GET_WAKEUP_TIME: 1863eb420e7SSai Praneeth status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1, 1873eb420e7SSai Praneeth (efi_bool_t *)arg2, (efi_time_t *)arg3); 1883eb420e7SSai Praneeth break; 1893eb420e7SSai Praneeth case SET_WAKEUP_TIME: 1903eb420e7SSai Praneeth status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1, 1913eb420e7SSai Praneeth (efi_time_t *)arg2); 1923eb420e7SSai Praneeth break; 1933eb420e7SSai Praneeth case GET_VARIABLE: 1943eb420e7SSai Praneeth status = efi_call_virt(get_variable, (efi_char16_t *)arg1, 1953eb420e7SSai Praneeth (efi_guid_t *)arg2, (u32 *)arg3, 1963eb420e7SSai Praneeth (unsigned long *)arg4, (void *)arg5); 1973eb420e7SSai Praneeth break; 1983eb420e7SSai Praneeth case GET_NEXT_VARIABLE: 1993eb420e7SSai Praneeth status = efi_call_virt(get_next_variable, (unsigned long *)arg1, 2003eb420e7SSai Praneeth (efi_char16_t *)arg2, 2013eb420e7SSai Praneeth (efi_guid_t *)arg3); 2023eb420e7SSai Praneeth break; 2033eb420e7SSai Praneeth case SET_VARIABLE: 2043eb420e7SSai Praneeth status = efi_call_virt(set_variable, (efi_char16_t *)arg1, 2053eb420e7SSai Praneeth (efi_guid_t *)arg2, *(u32 *)arg3, 2063eb420e7SSai Praneeth *(unsigned long *)arg4, (void *)arg5); 2073eb420e7SSai Praneeth break; 2083eb420e7SSai Praneeth case QUERY_VARIABLE_INFO: 2093eb420e7SSai Praneeth status = efi_call_virt(query_variable_info, *(u32 *)arg1, 2103eb420e7SSai Praneeth (u64 *)arg2, (u64 *)arg3, (u64 *)arg4); 2113eb420e7SSai Praneeth break; 2123eb420e7SSai Praneeth case GET_NEXT_HIGH_MONO_COUNT: 2133eb420e7SSai Praneeth status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1); 2143eb420e7SSai Praneeth break; 2153eb420e7SSai Praneeth case UPDATE_CAPSULE: 2163eb420e7SSai Praneeth status = efi_call_virt(update_capsule, 2173eb420e7SSai Praneeth (efi_capsule_header_t **)arg1, 2183eb420e7SSai Praneeth *(unsigned long *)arg2, 2193eb420e7SSai Praneeth *(unsigned long *)arg3); 2203eb420e7SSai Praneeth break; 2213eb420e7SSai Praneeth case QUERY_CAPSULE_CAPS: 2223eb420e7SSai Praneeth status = efi_call_virt(query_capsule_caps, 2233eb420e7SSai Praneeth (efi_capsule_header_t **)arg1, 2243eb420e7SSai Praneeth *(unsigned long *)arg2, (u64 *)arg3, 2253eb420e7SSai Praneeth (int *)arg4); 2263eb420e7SSai Praneeth break; 2273eb420e7SSai Praneeth default: 2283eb420e7SSai Praneeth /* 2293eb420e7SSai Praneeth * Ideally, we should never reach here because a caller of this 2303eb420e7SSai Praneeth * function should have put the right efi_runtime_service() 2313eb420e7SSai Praneeth * function identifier into efi_rts_work->efi_rts_id 2323eb420e7SSai Praneeth */ 2333eb420e7SSai Praneeth pr_err("Requested executing invalid EFI Runtime Service.\n"); 2343eb420e7SSai Praneeth } 2359dbbedaaSSai Praneeth efi_rts_work.status = status; 2369dbbedaaSSai Praneeth complete(&efi_rts_work.efi_rts_comp); 2373eb420e7SSai Praneeth } 2383eb420e7SSai Praneeth 239022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 240022ee6c5SArd Biesheuvel { 241022ee6c5SArd Biesheuvel efi_status_t status; 242022ee6c5SArd Biesheuvel 243dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 244dce48e35SArd Biesheuvel return EFI_ABORTED; 2453eb420e7SSai Praneeth status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL); 246dce48e35SArd Biesheuvel up(&efi_runtime_lock); 247022ee6c5SArd Biesheuvel return status; 248022ee6c5SArd Biesheuvel } 249022ee6c5SArd Biesheuvel 250022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_time(efi_time_t *tm) 251022ee6c5SArd Biesheuvel { 252022ee6c5SArd Biesheuvel efi_status_t status; 253022ee6c5SArd Biesheuvel 254dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 255dce48e35SArd Biesheuvel return EFI_ABORTED; 2563eb420e7SSai Praneeth status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL); 257dce48e35SArd Biesheuvel up(&efi_runtime_lock); 258022ee6c5SArd Biesheuvel return status; 259022ee6c5SArd Biesheuvel } 260022ee6c5SArd Biesheuvel 261022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 262022ee6c5SArd Biesheuvel efi_bool_t *pending, 263022ee6c5SArd Biesheuvel efi_time_t *tm) 264022ee6c5SArd Biesheuvel { 265022ee6c5SArd Biesheuvel efi_status_t status; 266022ee6c5SArd Biesheuvel 267dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 268dce48e35SArd Biesheuvel return EFI_ABORTED; 2693eb420e7SSai Praneeth status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL, 2703eb420e7SSai Praneeth NULL); 271dce48e35SArd Biesheuvel up(&efi_runtime_lock); 272022ee6c5SArd Biesheuvel return status; 273022ee6c5SArd Biesheuvel } 274022ee6c5SArd Biesheuvel 275022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, 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; 2813eb420e7SSai Praneeth status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, 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_get_variable(efi_char16_t *name, 288022ee6c5SArd Biesheuvel efi_guid_t *vendor, 289022ee6c5SArd Biesheuvel u32 *attr, 290022ee6c5SArd Biesheuvel unsigned long *data_size, 291022ee6c5SArd Biesheuvel void *data) 292022ee6c5SArd Biesheuvel { 293161485e8SArd Biesheuvel efi_status_t status; 294161485e8SArd Biesheuvel 295dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 296dce48e35SArd Biesheuvel return EFI_ABORTED; 2973eb420e7SSai Praneeth status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size, 298161485e8SArd Biesheuvel data); 299dce48e35SArd Biesheuvel up(&efi_runtime_lock); 300161485e8SArd Biesheuvel return status; 301022ee6c5SArd Biesheuvel } 302022ee6c5SArd Biesheuvel 303022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 304022ee6c5SArd Biesheuvel efi_char16_t *name, 305022ee6c5SArd Biesheuvel efi_guid_t *vendor) 306022ee6c5SArd Biesheuvel { 307161485e8SArd Biesheuvel efi_status_t status; 308161485e8SArd Biesheuvel 309dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 310dce48e35SArd Biesheuvel return EFI_ABORTED; 3113eb420e7SSai Praneeth status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor, 3123eb420e7SSai Praneeth NULL, NULL); 313dce48e35SArd Biesheuvel up(&efi_runtime_lock); 314161485e8SArd Biesheuvel return status; 315022ee6c5SArd Biesheuvel } 316022ee6c5SArd Biesheuvel 317022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_variable(efi_char16_t *name, 318022ee6c5SArd Biesheuvel efi_guid_t *vendor, 319022ee6c5SArd Biesheuvel u32 attr, 320022ee6c5SArd Biesheuvel unsigned long data_size, 321022ee6c5SArd Biesheuvel void *data) 322022ee6c5SArd Biesheuvel { 323161485e8SArd Biesheuvel efi_status_t status; 324161485e8SArd Biesheuvel 325dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 326dce48e35SArd Biesheuvel return EFI_ABORTED; 3273eb420e7SSai Praneeth status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size, 328161485e8SArd Biesheuvel data); 329dce48e35SArd Biesheuvel up(&efi_runtime_lock); 330161485e8SArd Biesheuvel return status; 331022ee6c5SArd Biesheuvel } 332022ee6c5SArd Biesheuvel 3336d80dba1SMatt Fleming static efi_status_t 3346d80dba1SMatt Fleming virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, 3356d80dba1SMatt Fleming u32 attr, unsigned long data_size, 3366d80dba1SMatt Fleming void *data) 3376d80dba1SMatt Fleming { 3386d80dba1SMatt Fleming efi_status_t status; 3396d80dba1SMatt Fleming 340dce48e35SArd Biesheuvel if (down_trylock(&efi_runtime_lock)) 3416d80dba1SMatt Fleming return EFI_NOT_READY; 3426d80dba1SMatt Fleming 3436d80dba1SMatt Fleming status = efi_call_virt(set_variable, name, vendor, attr, data_size, 3446d80dba1SMatt Fleming data); 345dce48e35SArd Biesheuvel up(&efi_runtime_lock); 3466d80dba1SMatt Fleming return status; 3476d80dba1SMatt Fleming } 3486d80dba1SMatt Fleming 3496d80dba1SMatt Fleming 350022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_variable_info(u32 attr, 351022ee6c5SArd Biesheuvel u64 *storage_space, 352022ee6c5SArd Biesheuvel u64 *remaining_space, 353022ee6c5SArd Biesheuvel u64 *max_variable_size) 354022ee6c5SArd Biesheuvel { 355161485e8SArd Biesheuvel efi_status_t status; 356161485e8SArd Biesheuvel 357022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 358022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 359022ee6c5SArd Biesheuvel 360dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 361dce48e35SArd Biesheuvel return EFI_ABORTED; 3623eb420e7SSai Praneeth status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space, 3633eb420e7SSai Praneeth remaining_space, max_variable_size, NULL); 364dce48e35SArd Biesheuvel up(&efi_runtime_lock); 365161485e8SArd Biesheuvel return status; 366022ee6c5SArd Biesheuvel } 367022ee6c5SArd Biesheuvel 368d3cac1f8SArd Biesheuvel static efi_status_t 369d3cac1f8SArd Biesheuvel virt_efi_query_variable_info_nonblocking(u32 attr, 370d3cac1f8SArd Biesheuvel u64 *storage_space, 371d3cac1f8SArd Biesheuvel u64 *remaining_space, 372d3cac1f8SArd Biesheuvel u64 *max_variable_size) 373d3cac1f8SArd Biesheuvel { 374d3cac1f8SArd Biesheuvel efi_status_t status; 375d3cac1f8SArd Biesheuvel 376d3cac1f8SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 377d3cac1f8SArd Biesheuvel return EFI_UNSUPPORTED; 378d3cac1f8SArd Biesheuvel 379dce48e35SArd Biesheuvel if (down_trylock(&efi_runtime_lock)) 380d3cac1f8SArd Biesheuvel return EFI_NOT_READY; 381d3cac1f8SArd Biesheuvel 382d3cac1f8SArd Biesheuvel status = efi_call_virt(query_variable_info, attr, storage_space, 383d3cac1f8SArd Biesheuvel remaining_space, max_variable_size); 384dce48e35SArd Biesheuvel up(&efi_runtime_lock); 385d3cac1f8SArd Biesheuvel return status; 386d3cac1f8SArd Biesheuvel } 387d3cac1f8SArd Biesheuvel 388022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 389022ee6c5SArd Biesheuvel { 390161485e8SArd Biesheuvel efi_status_t status; 391161485e8SArd Biesheuvel 392dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 393dce48e35SArd Biesheuvel return EFI_ABORTED; 3943eb420e7SSai Praneeth status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL, 3953eb420e7SSai Praneeth NULL, NULL); 396dce48e35SArd Biesheuvel up(&efi_runtime_lock); 397161485e8SArd Biesheuvel return status; 398022ee6c5SArd Biesheuvel } 399022ee6c5SArd Biesheuvel 400022ee6c5SArd Biesheuvel static void virt_efi_reset_system(int reset_type, 401022ee6c5SArd Biesheuvel efi_status_t status, 402022ee6c5SArd Biesheuvel unsigned long data_size, 403022ee6c5SArd Biesheuvel efi_char16_t *data) 404022ee6c5SArd Biesheuvel { 405dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) { 406dce48e35SArd Biesheuvel pr_warn("failed to invoke the reset_system() runtime service:\n" 407dce48e35SArd Biesheuvel "could not get exclusive access to the firmware\n"); 408dce48e35SArd Biesheuvel return; 409dce48e35SArd Biesheuvel } 4103425d934SSai Praneeth efi_rts_work.efi_rts_id = RESET_SYSTEM; 411022ee6c5SArd Biesheuvel __efi_call_virt(reset_system, reset_type, status, data_size, data); 412dce48e35SArd Biesheuvel up(&efi_runtime_lock); 413022ee6c5SArd Biesheuvel } 414022ee6c5SArd Biesheuvel 415022ee6c5SArd Biesheuvel static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 416022ee6c5SArd Biesheuvel unsigned long count, 417022ee6c5SArd Biesheuvel unsigned long sg_list) 418022ee6c5SArd Biesheuvel { 419161485e8SArd Biesheuvel efi_status_t status; 420161485e8SArd Biesheuvel 421022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 422022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 423022ee6c5SArd Biesheuvel 424dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 425dce48e35SArd Biesheuvel return EFI_ABORTED; 4263eb420e7SSai Praneeth status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list, 4273eb420e7SSai Praneeth NULL, NULL); 428dce48e35SArd Biesheuvel up(&efi_runtime_lock); 429161485e8SArd Biesheuvel return status; 430022ee6c5SArd Biesheuvel } 431022ee6c5SArd Biesheuvel 432022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 433022ee6c5SArd Biesheuvel unsigned long count, 434022ee6c5SArd Biesheuvel u64 *max_size, 435022ee6c5SArd Biesheuvel int *reset_type) 436022ee6c5SArd Biesheuvel { 437161485e8SArd Biesheuvel efi_status_t status; 438161485e8SArd Biesheuvel 439022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 440022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 441022ee6c5SArd Biesheuvel 442dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 443dce48e35SArd Biesheuvel return EFI_ABORTED; 4443eb420e7SSai Praneeth status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count, 4453eb420e7SSai Praneeth max_size, reset_type, NULL); 446dce48e35SArd Biesheuvel up(&efi_runtime_lock); 447161485e8SArd Biesheuvel return status; 448022ee6c5SArd Biesheuvel } 449022ee6c5SArd Biesheuvel 450022ee6c5SArd Biesheuvel void efi_native_runtime_setup(void) 451022ee6c5SArd Biesheuvel { 452022ee6c5SArd Biesheuvel efi.get_time = virt_efi_get_time; 453022ee6c5SArd Biesheuvel efi.set_time = virt_efi_set_time; 454022ee6c5SArd Biesheuvel efi.get_wakeup_time = virt_efi_get_wakeup_time; 455022ee6c5SArd Biesheuvel efi.set_wakeup_time = virt_efi_set_wakeup_time; 456022ee6c5SArd Biesheuvel efi.get_variable = virt_efi_get_variable; 457022ee6c5SArd Biesheuvel efi.get_next_variable = virt_efi_get_next_variable; 458022ee6c5SArd Biesheuvel efi.set_variable = virt_efi_set_variable; 4596d80dba1SMatt Fleming efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; 460022ee6c5SArd Biesheuvel efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 461022ee6c5SArd Biesheuvel efi.reset_system = virt_efi_reset_system; 462022ee6c5SArd Biesheuvel efi.query_variable_info = virt_efi_query_variable_info; 463d3cac1f8SArd Biesheuvel efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; 464022ee6c5SArd Biesheuvel efi.update_capsule = virt_efi_update_capsule; 465022ee6c5SArd Biesheuvel efi.query_capsule_caps = virt_efi_query_capsule_caps; 466022ee6c5SArd Biesheuvel } 467