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); \ 703eb420e7SSai Praneeth INIT_WORK_ONSTACK(&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 /* 1503eb420e7SSai Praneeth * Calls the appropriate efi_runtime_service() with the appropriate 1513eb420e7SSai Praneeth * arguments. 1523eb420e7SSai Praneeth * 1533eb420e7SSai Praneeth * Semantics followed by efi_call_rts() to understand efi_runtime_work: 1543eb420e7SSai Praneeth * 1. If argument was a pointer, recast it from void pointer to original 1553eb420e7SSai Praneeth * pointer type. 1563eb420e7SSai Praneeth * 2. If argument was a value, recast it from void pointer to original 1573eb420e7SSai Praneeth * pointer type and dereference it. 1583eb420e7SSai Praneeth */ 1593eb420e7SSai Praneeth static void efi_call_rts(struct work_struct *work) 1603eb420e7SSai Praneeth { 1613eb420e7SSai Praneeth void *arg1, *arg2, *arg3, *arg4, *arg5; 1623eb420e7SSai Praneeth efi_status_t status = EFI_NOT_FOUND; 1633eb420e7SSai Praneeth 1649dbbedaaSSai Praneeth arg1 = efi_rts_work.arg1; 1659dbbedaaSSai Praneeth arg2 = efi_rts_work.arg2; 1669dbbedaaSSai Praneeth arg3 = efi_rts_work.arg3; 1679dbbedaaSSai Praneeth arg4 = efi_rts_work.arg4; 1689dbbedaaSSai Praneeth arg5 = efi_rts_work.arg5; 1693eb420e7SSai Praneeth 1709dbbedaaSSai Praneeth switch (efi_rts_work.efi_rts_id) { 1713eb420e7SSai Praneeth case GET_TIME: 1723eb420e7SSai Praneeth status = efi_call_virt(get_time, (efi_time_t *)arg1, 1733eb420e7SSai Praneeth (efi_time_cap_t *)arg2); 1743eb420e7SSai Praneeth break; 1753eb420e7SSai Praneeth case SET_TIME: 1763eb420e7SSai Praneeth status = efi_call_virt(set_time, (efi_time_t *)arg1); 1773eb420e7SSai Praneeth break; 1783eb420e7SSai Praneeth case GET_WAKEUP_TIME: 1793eb420e7SSai Praneeth status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1, 1803eb420e7SSai Praneeth (efi_bool_t *)arg2, (efi_time_t *)arg3); 1813eb420e7SSai Praneeth break; 1823eb420e7SSai Praneeth case SET_WAKEUP_TIME: 1833eb420e7SSai Praneeth status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1, 1843eb420e7SSai Praneeth (efi_time_t *)arg2); 1853eb420e7SSai Praneeth break; 1863eb420e7SSai Praneeth case GET_VARIABLE: 1873eb420e7SSai Praneeth status = efi_call_virt(get_variable, (efi_char16_t *)arg1, 1883eb420e7SSai Praneeth (efi_guid_t *)arg2, (u32 *)arg3, 1893eb420e7SSai Praneeth (unsigned long *)arg4, (void *)arg5); 1903eb420e7SSai Praneeth break; 1913eb420e7SSai Praneeth case GET_NEXT_VARIABLE: 1923eb420e7SSai Praneeth status = efi_call_virt(get_next_variable, (unsigned long *)arg1, 1933eb420e7SSai Praneeth (efi_char16_t *)arg2, 1943eb420e7SSai Praneeth (efi_guid_t *)arg3); 1953eb420e7SSai Praneeth break; 1963eb420e7SSai Praneeth case SET_VARIABLE: 1973eb420e7SSai Praneeth status = efi_call_virt(set_variable, (efi_char16_t *)arg1, 1983eb420e7SSai Praneeth (efi_guid_t *)arg2, *(u32 *)arg3, 1993eb420e7SSai Praneeth *(unsigned long *)arg4, (void *)arg5); 2003eb420e7SSai Praneeth break; 2013eb420e7SSai Praneeth case QUERY_VARIABLE_INFO: 2023eb420e7SSai Praneeth status = efi_call_virt(query_variable_info, *(u32 *)arg1, 2033eb420e7SSai Praneeth (u64 *)arg2, (u64 *)arg3, (u64 *)arg4); 2043eb420e7SSai Praneeth break; 2053eb420e7SSai Praneeth case GET_NEXT_HIGH_MONO_COUNT: 2063eb420e7SSai Praneeth status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1); 2073eb420e7SSai Praneeth break; 2083eb420e7SSai Praneeth case UPDATE_CAPSULE: 2093eb420e7SSai Praneeth status = efi_call_virt(update_capsule, 2103eb420e7SSai Praneeth (efi_capsule_header_t **)arg1, 2113eb420e7SSai Praneeth *(unsigned long *)arg2, 2123eb420e7SSai Praneeth *(unsigned long *)arg3); 2133eb420e7SSai Praneeth break; 2143eb420e7SSai Praneeth case QUERY_CAPSULE_CAPS: 2153eb420e7SSai Praneeth status = efi_call_virt(query_capsule_caps, 2163eb420e7SSai Praneeth (efi_capsule_header_t **)arg1, 2173eb420e7SSai Praneeth *(unsigned long *)arg2, (u64 *)arg3, 2183eb420e7SSai Praneeth (int *)arg4); 2193eb420e7SSai Praneeth break; 2203eb420e7SSai Praneeth default: 2213eb420e7SSai Praneeth /* 2223eb420e7SSai Praneeth * Ideally, we should never reach here because a caller of this 2233eb420e7SSai Praneeth * function should have put the right efi_runtime_service() 2243eb420e7SSai Praneeth * function identifier into efi_rts_work->efi_rts_id 2253eb420e7SSai Praneeth */ 2263eb420e7SSai Praneeth pr_err("Requested executing invalid EFI Runtime Service.\n"); 2273eb420e7SSai Praneeth } 2289dbbedaaSSai Praneeth efi_rts_work.status = status; 2299dbbedaaSSai Praneeth complete(&efi_rts_work.efi_rts_comp); 2303eb420e7SSai Praneeth } 2313eb420e7SSai Praneeth 232022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 233022ee6c5SArd Biesheuvel { 234022ee6c5SArd Biesheuvel efi_status_t status; 235022ee6c5SArd Biesheuvel 236dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 237dce48e35SArd Biesheuvel return EFI_ABORTED; 2383eb420e7SSai Praneeth status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL); 239dce48e35SArd Biesheuvel up(&efi_runtime_lock); 240022ee6c5SArd Biesheuvel return status; 241022ee6c5SArd Biesheuvel } 242022ee6c5SArd Biesheuvel 243022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_time(efi_time_t *tm) 244022ee6c5SArd Biesheuvel { 245022ee6c5SArd Biesheuvel efi_status_t status; 246022ee6c5SArd Biesheuvel 247dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 248dce48e35SArd Biesheuvel return EFI_ABORTED; 2493eb420e7SSai Praneeth status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL); 250dce48e35SArd Biesheuvel up(&efi_runtime_lock); 251022ee6c5SArd Biesheuvel return status; 252022ee6c5SArd Biesheuvel } 253022ee6c5SArd Biesheuvel 254022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 255022ee6c5SArd Biesheuvel efi_bool_t *pending, 256022ee6c5SArd Biesheuvel efi_time_t *tm) 257022ee6c5SArd Biesheuvel { 258022ee6c5SArd Biesheuvel efi_status_t status; 259022ee6c5SArd Biesheuvel 260dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 261dce48e35SArd Biesheuvel return EFI_ABORTED; 2623eb420e7SSai Praneeth status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL, 2633eb420e7SSai Praneeth NULL); 264dce48e35SArd Biesheuvel up(&efi_runtime_lock); 265022ee6c5SArd Biesheuvel return status; 266022ee6c5SArd Biesheuvel } 267022ee6c5SArd Biesheuvel 268022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 269022ee6c5SArd Biesheuvel { 270022ee6c5SArd Biesheuvel efi_status_t status; 271022ee6c5SArd Biesheuvel 272dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 273dce48e35SArd Biesheuvel return EFI_ABORTED; 2743eb420e7SSai Praneeth status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, NULL, 2753eb420e7SSai Praneeth NULL); 276dce48e35SArd Biesheuvel up(&efi_runtime_lock); 277022ee6c5SArd Biesheuvel return status; 278022ee6c5SArd Biesheuvel } 279022ee6c5SArd Biesheuvel 280022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_variable(efi_char16_t *name, 281022ee6c5SArd Biesheuvel efi_guid_t *vendor, 282022ee6c5SArd Biesheuvel u32 *attr, 283022ee6c5SArd Biesheuvel unsigned long *data_size, 284022ee6c5SArd Biesheuvel void *data) 285022ee6c5SArd Biesheuvel { 286161485e8SArd Biesheuvel efi_status_t status; 287161485e8SArd Biesheuvel 288dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 289dce48e35SArd Biesheuvel return EFI_ABORTED; 2903eb420e7SSai Praneeth status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size, 291161485e8SArd Biesheuvel data); 292dce48e35SArd Biesheuvel up(&efi_runtime_lock); 293161485e8SArd Biesheuvel return status; 294022ee6c5SArd Biesheuvel } 295022ee6c5SArd Biesheuvel 296022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 297022ee6c5SArd Biesheuvel efi_char16_t *name, 298022ee6c5SArd Biesheuvel efi_guid_t *vendor) 299022ee6c5SArd Biesheuvel { 300161485e8SArd Biesheuvel efi_status_t status; 301161485e8SArd Biesheuvel 302dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 303dce48e35SArd Biesheuvel return EFI_ABORTED; 3043eb420e7SSai Praneeth status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor, 3053eb420e7SSai Praneeth NULL, NULL); 306dce48e35SArd Biesheuvel up(&efi_runtime_lock); 307161485e8SArd Biesheuvel return status; 308022ee6c5SArd Biesheuvel } 309022ee6c5SArd Biesheuvel 310022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_variable(efi_char16_t *name, 311022ee6c5SArd Biesheuvel efi_guid_t *vendor, 312022ee6c5SArd Biesheuvel u32 attr, 313022ee6c5SArd Biesheuvel unsigned long data_size, 314022ee6c5SArd Biesheuvel void *data) 315022ee6c5SArd Biesheuvel { 316161485e8SArd Biesheuvel efi_status_t status; 317161485e8SArd Biesheuvel 318dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 319dce48e35SArd Biesheuvel return EFI_ABORTED; 3203eb420e7SSai Praneeth status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size, 321161485e8SArd Biesheuvel data); 322dce48e35SArd Biesheuvel up(&efi_runtime_lock); 323161485e8SArd Biesheuvel return status; 324022ee6c5SArd Biesheuvel } 325022ee6c5SArd Biesheuvel 3266d80dba1SMatt Fleming static efi_status_t 3276d80dba1SMatt Fleming virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, 3286d80dba1SMatt Fleming u32 attr, unsigned long data_size, 3296d80dba1SMatt Fleming void *data) 3306d80dba1SMatt Fleming { 3316d80dba1SMatt Fleming efi_status_t status; 3326d80dba1SMatt Fleming 333dce48e35SArd Biesheuvel if (down_trylock(&efi_runtime_lock)) 3346d80dba1SMatt Fleming return EFI_NOT_READY; 3356d80dba1SMatt Fleming 3366d80dba1SMatt Fleming status = efi_call_virt(set_variable, name, vendor, attr, data_size, 3376d80dba1SMatt Fleming data); 338dce48e35SArd Biesheuvel up(&efi_runtime_lock); 3396d80dba1SMatt Fleming return status; 3406d80dba1SMatt Fleming } 3416d80dba1SMatt Fleming 3426d80dba1SMatt Fleming 343022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_variable_info(u32 attr, 344022ee6c5SArd Biesheuvel u64 *storage_space, 345022ee6c5SArd Biesheuvel u64 *remaining_space, 346022ee6c5SArd Biesheuvel u64 *max_variable_size) 347022ee6c5SArd Biesheuvel { 348161485e8SArd Biesheuvel efi_status_t status; 349161485e8SArd Biesheuvel 350022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 351022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 352022ee6c5SArd Biesheuvel 353dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 354dce48e35SArd Biesheuvel return EFI_ABORTED; 3553eb420e7SSai Praneeth status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space, 3563eb420e7SSai Praneeth remaining_space, max_variable_size, NULL); 357dce48e35SArd Biesheuvel up(&efi_runtime_lock); 358161485e8SArd Biesheuvel return status; 359022ee6c5SArd Biesheuvel } 360022ee6c5SArd Biesheuvel 361d3cac1f8SArd Biesheuvel static efi_status_t 362d3cac1f8SArd Biesheuvel virt_efi_query_variable_info_nonblocking(u32 attr, 363d3cac1f8SArd Biesheuvel u64 *storage_space, 364d3cac1f8SArd Biesheuvel u64 *remaining_space, 365d3cac1f8SArd Biesheuvel u64 *max_variable_size) 366d3cac1f8SArd Biesheuvel { 367d3cac1f8SArd Biesheuvel efi_status_t status; 368d3cac1f8SArd Biesheuvel 369d3cac1f8SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 370d3cac1f8SArd Biesheuvel return EFI_UNSUPPORTED; 371d3cac1f8SArd Biesheuvel 372dce48e35SArd Biesheuvel if (down_trylock(&efi_runtime_lock)) 373d3cac1f8SArd Biesheuvel return EFI_NOT_READY; 374d3cac1f8SArd Biesheuvel 375d3cac1f8SArd Biesheuvel status = efi_call_virt(query_variable_info, attr, storage_space, 376d3cac1f8SArd Biesheuvel remaining_space, max_variable_size); 377dce48e35SArd Biesheuvel up(&efi_runtime_lock); 378d3cac1f8SArd Biesheuvel return status; 379d3cac1f8SArd Biesheuvel } 380d3cac1f8SArd Biesheuvel 381022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 382022ee6c5SArd Biesheuvel { 383161485e8SArd Biesheuvel efi_status_t status; 384161485e8SArd Biesheuvel 385dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 386dce48e35SArd Biesheuvel return EFI_ABORTED; 3873eb420e7SSai Praneeth status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL, 3883eb420e7SSai Praneeth NULL, NULL); 389dce48e35SArd Biesheuvel up(&efi_runtime_lock); 390161485e8SArd Biesheuvel return status; 391022ee6c5SArd Biesheuvel } 392022ee6c5SArd Biesheuvel 393022ee6c5SArd Biesheuvel static void virt_efi_reset_system(int reset_type, 394022ee6c5SArd Biesheuvel efi_status_t status, 395022ee6c5SArd Biesheuvel unsigned long data_size, 396022ee6c5SArd Biesheuvel efi_char16_t *data) 397022ee6c5SArd Biesheuvel { 398dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) { 399dce48e35SArd Biesheuvel pr_warn("failed to invoke the reset_system() runtime service:\n" 400dce48e35SArd Biesheuvel "could not get exclusive access to the firmware\n"); 401dce48e35SArd Biesheuvel return; 402dce48e35SArd Biesheuvel } 4033425d934SSai Praneeth efi_rts_work.efi_rts_id = RESET_SYSTEM; 404022ee6c5SArd Biesheuvel __efi_call_virt(reset_system, reset_type, status, data_size, data); 405dce48e35SArd Biesheuvel up(&efi_runtime_lock); 406022ee6c5SArd Biesheuvel } 407022ee6c5SArd Biesheuvel 408022ee6c5SArd Biesheuvel static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 409022ee6c5SArd Biesheuvel unsigned long count, 410022ee6c5SArd Biesheuvel unsigned long sg_list) 411022ee6c5SArd Biesheuvel { 412161485e8SArd Biesheuvel efi_status_t status; 413161485e8SArd Biesheuvel 414022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 415022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 416022ee6c5SArd Biesheuvel 417dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 418dce48e35SArd Biesheuvel return EFI_ABORTED; 4193eb420e7SSai Praneeth status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list, 4203eb420e7SSai Praneeth NULL, NULL); 421dce48e35SArd Biesheuvel up(&efi_runtime_lock); 422161485e8SArd Biesheuvel return status; 423022ee6c5SArd Biesheuvel } 424022ee6c5SArd Biesheuvel 425022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 426022ee6c5SArd Biesheuvel unsigned long count, 427022ee6c5SArd Biesheuvel u64 *max_size, 428022ee6c5SArd Biesheuvel int *reset_type) 429022ee6c5SArd Biesheuvel { 430161485e8SArd Biesheuvel efi_status_t status; 431161485e8SArd Biesheuvel 432022ee6c5SArd Biesheuvel if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 433022ee6c5SArd Biesheuvel return EFI_UNSUPPORTED; 434022ee6c5SArd Biesheuvel 435dce48e35SArd Biesheuvel if (down_interruptible(&efi_runtime_lock)) 436dce48e35SArd Biesheuvel return EFI_ABORTED; 4373eb420e7SSai Praneeth status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count, 4383eb420e7SSai Praneeth max_size, reset_type, NULL); 439dce48e35SArd Biesheuvel up(&efi_runtime_lock); 440161485e8SArd Biesheuvel return status; 441022ee6c5SArd Biesheuvel } 442022ee6c5SArd Biesheuvel 443022ee6c5SArd Biesheuvel void efi_native_runtime_setup(void) 444022ee6c5SArd Biesheuvel { 445022ee6c5SArd Biesheuvel efi.get_time = virt_efi_get_time; 446022ee6c5SArd Biesheuvel efi.set_time = virt_efi_set_time; 447022ee6c5SArd Biesheuvel efi.get_wakeup_time = virt_efi_get_wakeup_time; 448022ee6c5SArd Biesheuvel efi.set_wakeup_time = virt_efi_set_wakeup_time; 449022ee6c5SArd Biesheuvel efi.get_variable = virt_efi_get_variable; 450022ee6c5SArd Biesheuvel efi.get_next_variable = virt_efi_get_next_variable; 451022ee6c5SArd Biesheuvel efi.set_variable = virt_efi_set_variable; 4526d80dba1SMatt Fleming efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; 453022ee6c5SArd Biesheuvel efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 454022ee6c5SArd Biesheuvel efi.reset_system = virt_efi_reset_system; 455022ee6c5SArd Biesheuvel efi.query_variable_info = virt_efi_query_variable_info; 456d3cac1f8SArd Biesheuvel efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; 457022ee6c5SArd Biesheuvel efi.update_capsule = virt_efi_update_capsule; 458022ee6c5SArd Biesheuvel efi.query_capsule_caps = virt_efi_query_capsule_caps; 459022ee6c5SArd Biesheuvel } 460