From patchwork Thu Jan 25 10:31:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 10183867 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4F70E60388 for ; Thu, 25 Jan 2018 10:35:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B23C285DE for ; Thu, 25 Jan 2018 10:35:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1BEFC2872F; Thu, 25 Jan 2018 10:35:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 06043285DE for ; Thu, 25 Jan 2018 10:35:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=t9FZS6714JZC/TWyzOIm9RwN6XatDMqaEFIV4jBERzM=; b=hwO3sg9i8BSFv1B0UfqEOYilo8 SzSxUHYXyo+fDQ2goQMgqlCyMPPDNECi5ecne9d1j7jpVbEz2PNmjd/LwcEDkHtBNTX/nKlOPCeOH c2D2lPZJHxZyUG83wbjTMgSjbqsSZZq9JKwod8r77O8qWVmbk+qIEDP/yC1mUXiDIyoBi9fhmRUme tScMKVMiOwJgpkaB9raDp1RbABPX4B9dDA55U6Aa5l8YDM7VSHHWZUigEfuXJgNeK2HhEB0fVYFYp Mr1WJe5YMBxTcUWGuOMVAhK50/zSr1L8X2VQXYwp4W+gcIMyg70rE1c5qNYjzyXtCvuhMlyEuR6lS FPsDV8qg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1eeesU-0003zw-G7; Thu, 25 Jan 2018 10:35:30 +0000 Received: from mail-wr0-x244.google.com ([2a00:1450:400c:c0c::244]) by bombadil.infradead.org with esmtps (Exim 4.89 #1 (Red Hat Linux)) id 1eeep7-00085b-Sa for linux-arm-kernel@lists.infradead.org; Thu, 25 Jan 2018 10:32:10 +0000 Received: by mail-wr0-x244.google.com with SMTP id a1so2404567wri.5 for ; Thu, 25 Jan 2018 02:31:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=WyBXwDXEDstE0keE/ai7u7i2exQLm/n5/KN2TdM/BEY=; b=YLyTMV5+VOu7CrvnMq+OjoK/FLp5j5wmuafCnwXcSb/YD88Hny8x9pYb3Zd7L840IG 8qXR/0hSgUq9EHfG1VHKhGH2Zy7psWrhBJhnjV3f+kHWIhCQaCKb3i3+XuQQP4Kx/qZK hmCqXEFNVhmc2Hw6oZP1+8c5/OgVZ/rWL06N0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=WyBXwDXEDstE0keE/ai7u7i2exQLm/n5/KN2TdM/BEY=; b=j9VvgXTyahV0FOFuip3Fm5X5tCTzr530EPD62C4lZTsInVLWAQF41cUIlLWjsrFIna ubuOwkCHO39eBE9h/M+mbQaPOdag/OpZtEgN8bvylR64KtfJTq7OrNZwEU9DIjQD3OzK v3SAsktJdZXPp2joN1x2653XzrdB3N1NrkjulxsVumKygGtStAtubVeEiL2zYpv6BAGY c5tVHvMzO/46F+oBs2KIZb3J9O0iqp6U+sPwV/D9V/rPfSEkW7rbg1LxkvJyunjW9QcE Kjpv6yOCIQQKKz8lUs4/EaOOVYhVQsdd2fVJcaReAK7NAzTDPWwus2tMYYetuGpbqJd+ 2BDw== X-Gm-Message-State: AKwxytc5pam5kdV9cNI5IWRFXO3EcawLe/DUDlOX1A8Mrao3OmyKuBQ/ Nv372bpJenys47Sv2kESjepblw== X-Google-Smtp-Source: AH8x227CC257yUEciqhSl9vQjtoX5BPIVJSiGyfXbwmwfPNNiT5BOtPsJKRXfbcxR7dUdjDBXYyGLw== X-Received: by 10.223.163.134 with SMTP id l6mr8105844wrb.220.1516876309098; Thu, 25 Jan 2018 02:31:49 -0800 (PST) Received: from localhost.localdomain ([160.167.127.168]) by smtp.gmail.com with ESMTPSA id j77sm1199964wmf.37.2018.01.25.02.31.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Jan 2018 02:31:48 -0800 (PST) From: Ard Biesheuvel To: linux-efi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, will.deacon@arm.com, catalin.marinas@arm.com, mark.rutland@arm.com, marc.zyngier@arm.com Subject: [PATCH 3/4] efi/arm64: marshall runtime services arguments via buffer in TTBR0 Date: Thu, 25 Jan 2018 10:31:30 +0000 Message-Id: <20180125103131.19168-4-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180125103131.19168-1-ard.biesheuvel@linaro.org> References: <20180125103131.19168-1-ard.biesheuvel@linaro.org> X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: joakim.bech@linaro.org, graeme.gregory@linaro.org, leif.lindholm@linaro.org, Ard Biesheuvel MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP If we want to unmap the kernel while executing UEFI runtime services, we need to ensure that all arguments passed to those services are valid during that time, and this includes pointer arguments to string buffers and other data. So we have to do the rather tedious job of replacing each generic runtime wrapper with one that takes the above into account. Fortunately, UEFI runtime services are not reentrant, so we can create a static buffer with fields for each runtime service, and a separate buffer for get/set_variable. This does limit variable names to 1024 characters and the variables themselves to 64 KB, but this should not be a limitation in practice. Note that capsule update is omitted for now - this will be addressed in a subsequent patch. Signed-off-by: Ard Biesheuvel --- arch/arm64/Kconfig | 1 - arch/arm64/include/asm/efi.h | 5 + arch/arm64/kernel/efi.c | 475 +++++++++++++++++++- 3 files changed, 479 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index de83b53c7e19..f2224566cc75 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1196,7 +1196,6 @@ config EFI select LIBFDT select UCS2_STRING select EFI_PARAMS_FROM_FDT - select EFI_RUNTIME_WRAPPERS select EFI_STUB select EFI_ARMSTUB default y diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index b9b09a734719..b96bc4836c37 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -165,4 +165,9 @@ int __init efi_allocate_runtime_regions(struct mm_struct *mm); #define EFI_CODE_BASE 0x200000 #define EFI_CODE_SIZE PAGE_SIZE +#define EFI_VARBUFFER_BASE 0x210000 +#define EFI_VARBUFFER_SIZE SZ_64K + +#define EFI_DATA_BASE 0x220000 + #endif /* _ASM_EFI_H */ diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 68c920b2f4f0..cd23c20fba39 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -11,9 +11,15 @@ * */ +#define pr_fmt(fmt) "efi: " fmt + +#include #include #include - +#include +#include +#include +#include #include /* @@ -136,6 +142,63 @@ bool on_efi_stack(unsigned long sp) return sp >= EFI_STACK_BASE && sp < (EFI_STACK_BASE + EFI_STACK_SIZE); } +#define MAX_CAPSULES 16 +#define MAX_VARNAME_LEN 1024 + +#define EFI_ADDR(arg) (&((typeof(__efi_rt_marshall_data)*)EFI_DATA_BASE)->arg) +#define EFI_DATA(arg) (__efi_rt_marshall_data.arg) + +static union { + struct { + efi_time_t tm; + efi_time_cap_t tc; + } get_time; + + struct { + efi_time_t tm; + } set_time; + + struct { + efi_bool_t enabled; + efi_bool_t pending; + efi_time_t tm; + } get_wakeup_time; + + struct { + efi_char16_t name[MAX_VARNAME_LEN]; + efi_guid_t vendor; + u32 attr; + unsigned long data_size; + void *data; + } get_variable; + + struct { + unsigned long name_size; + efi_char16_t name[MAX_VARNAME_LEN]; + efi_guid_t vendor; + } get_next_variable; + + struct { + u64 storage_space; + u64 remaining_space; + u64 max_variable_size; + } query_variable_info; + + struct { + u32 count; + } get_next_high_mono_count; + + struct { + efi_capsule_header_t capsules[MAX_CAPSULES]; + efi_capsule_header_t *capsule_headers[MAX_CAPSULES]; + u64 max_size; + int reset_type; + } query_capsule_caps; + +} __efi_rt_marshall_data __page_aligned_bss; + +static u8 __efi_rt_varbuffer[EFI_VARBUFFER_SIZE] __page_aligned_bss; + int __init efi_allocate_runtime_regions(struct mm_struct *mm) { static u8 stack[EFI_STACK_SIZE] __page_aligned_bss; @@ -152,5 +215,415 @@ int __init efi_allocate_runtime_regions(struct mm_struct *mm) __pgprot(pgprot_val(PAGE_KERNEL_ROX) | PTE_NG), false); + /* map the marshall data struct */ + create_pgd_mapping(mm, __pa_symbol(&__efi_rt_marshall_data), + EFI_DATA_BASE, sizeof(__efi_rt_marshall_data), + __pgprot(pgprot_val(PAGE_KERNEL) | PTE_NG), + false); + + /* map the varbuffer */ + create_pgd_mapping(mm, __pa_symbol(__efi_rt_varbuffer), + EFI_VARBUFFER_BASE, EFI_VARBUFFER_SIZE, + __pgprot(pgprot_val(PAGE_KERNEL) | PTE_NG), + false); + return 0; } + +/* + * Wrap around the new efi_call_virt_generic() macros so that the + * code doesn't get too cluttered: + */ +#define efi_call_virt(f, args...) \ + efi_call_virt_pointer(efi.systab->runtime, f, args) +#define __efi_call_virt(f, args...) \ + __efi_call_virt_pointer(efi.systab->runtime, f, args) + +void efi_call_virt_check_flags(unsigned long flags, const char *call) +{ + unsigned long cur_flags, mismatch; + + local_save_flags(cur_flags); + + mismatch = flags ^ cur_flags; + if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK)) + return; + + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE); + pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n", + flags, cur_flags, call); + local_irq_restore(flags); +} + +static int strlen16(efi_char16_t const *name) +{ + int ret = 0; + + while (*name++) + ret++; + + return ret; +} + +static DEFINE_SEMAPHORE(efi_runtime_lock); + +static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) +{ + efi_status_t status; + + if (!tm) + return EFI_INVALID_PARAMETER; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + status = efi_call_virt(get_time, + EFI_ADDR(get_time.tm), + tc ? EFI_ADDR(get_time.tc): NULL); + + *tm = EFI_DATA(get_time.tm); + if (tc) + *tc = EFI_DATA(get_time.tc); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_set_time(efi_time_t *tm) +{ + efi_status_t status; + + if (!tm) + return EFI_INVALID_PARAMETER; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + EFI_DATA(set_time.tm) = *tm; + + status = efi_call_virt(set_time, + EFI_ADDR(set_time.tm)); + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, + efi_bool_t *pending, + efi_time_t *tm) +{ + efi_status_t status; + + if (!enabled || !pending || !tm) + return EFI_INVALID_PARAMETER; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + status = efi_call_virt(get_wakeup_time, + EFI_ADDR(get_wakeup_time.enabled), + EFI_ADDR(get_wakeup_time.pending), + EFI_ADDR(get_wakeup_time.tm)); + + *enabled = EFI_DATA(get_wakeup_time.enabled); + *pending = EFI_DATA(get_wakeup_time.pending); + *tm = EFI_DATA(get_wakeup_time.tm); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) +{ + efi_status_t status; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + EFI_DATA(set_time.tm) = *tm; + + status = efi_call_virt(set_wakeup_time, enabled, + EFI_ADDR(set_time.tm)); + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_get_variable(efi_char16_t *name, + efi_guid_t *vendor, + u32 *attr, + unsigned long *data_size, + void *data) +{ + efi_status_t status; + int l = strlen16(name) + 1; + + if (!name || !vendor || !data_size) + return EFI_INVALID_PARAMETER; + + if (*data_size > EFI_VARBUFFER_SIZE || l > MAX_VARNAME_LEN) + return EFI_NOT_READY; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + memcpy(EFI_DATA(get_variable.name), name, l * sizeof(efi_char16_t)); + EFI_DATA(get_variable.vendor) = *vendor; + EFI_DATA(get_variable.data_size) = *data_size; + + status = efi_call_virt(get_variable, + EFI_ADDR(get_variable.name), + EFI_ADDR(get_variable.vendor), + attr ? EFI_ADDR(get_variable.attr) : NULL, + EFI_ADDR(get_variable.data_size), + data ? (void *)EFI_VARBUFFER_BASE : NULL); + + if (attr) + *attr = EFI_DATA(get_variable.attr); + *data_size = EFI_DATA(get_variable.data_size); + if (data) + memcpy(data, __efi_rt_varbuffer, *data_size); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, + efi_char16_t *name, + efi_guid_t *vendor) +{ + efi_status_t status; + + if (*name_size > MAX_VARNAME_LEN) + return EFI_NOT_READY; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + EFI_DATA(get_next_variable.name_size) = *name_size; + memcpy(EFI_DATA(get_next_variable.name), name, *name_size); + EFI_DATA(get_next_variable.vendor) = *vendor; + + status = efi_call_virt(get_next_variable, + EFI_ADDR(get_next_variable.name_size), + EFI_ADDR(get_next_variable.name), + EFI_ADDR(get_next_variable.vendor)); + + *name_size = EFI_DATA(get_next_variable.name_size); + memcpy(name, EFI_DATA(get_next_variable.name), *name_size); + *vendor = EFI_DATA(get_next_variable.vendor); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_set_variable(efi_char16_t *name, + efi_guid_t *vendor, + u32 attr, + unsigned long data_size, + void *data) +{ + efi_status_t status; + int l = strlen16(name) + 1; + + if (!name || !vendor) + return EFI_INVALID_PARAMETER; + + if (data_size > EFI_VARBUFFER_SIZE || l > MAX_VARNAME_LEN) + return EFI_NOT_READY; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + memcpy(EFI_DATA(get_variable.name), name, l * sizeof(efi_char16_t)); + EFI_DATA(get_variable.vendor) = *vendor; + if (data) + memcpy(__efi_rt_varbuffer, data, data_size); + + status = efi_call_virt(set_variable, + EFI_ADDR(get_variable.name), + EFI_ADDR(get_variable.vendor), + attr, + data_size, + data ? (void *)EFI_VARBUFFER_BASE : NULL); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t +virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, + u32 attr, unsigned long data_size, + void *data) +{ + efi_status_t status; + int l = strlen16(name) + 1; + + if (!name || !vendor) + return EFI_INVALID_PARAMETER; + + if (data_size > EFI_VARBUFFER_SIZE || l > MAX_VARNAME_LEN) + return EFI_NOT_READY; + + if (down_trylock(&efi_runtime_lock)) + return EFI_NOT_READY; + + memcpy(EFI_DATA(get_variable.name), name, l * sizeof(efi_char16_t)); + EFI_DATA(get_variable.vendor) = *vendor; + if (data) + memcpy(__efi_rt_varbuffer, data, data_size); + + status = efi_call_virt(set_variable, + EFI_ADDR(get_variable.name), + EFI_ADDR(get_variable.vendor), + attr, + data_size, + data ? (void *)EFI_VARBUFFER_BASE : NULL); + + up(&efi_runtime_lock); + return status; +} + + +static efi_status_t virt_efi_query_variable_info(u32 attr, + u64 *storage_space, + u64 *remaining_space, + u64 *max_variable_size) +{ + efi_status_t status; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + status = efi_call_virt(query_variable_info, + attr, + EFI_ADDR(query_variable_info.storage_space), + EFI_ADDR(query_variable_info.remaining_space), + EFI_ADDR(query_variable_info.max_variable_size)); + + *storage_space = EFI_DATA(query_variable_info.storage_space); + *remaining_space = EFI_DATA(query_variable_info.remaining_space); + *max_variable_size = EFI_DATA(query_variable_info.max_variable_size); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t +virt_efi_query_variable_info_nonblocking(u32 attr, + u64 *storage_space, + u64 *remaining_space, + u64 *max_variable_size) +{ + efi_status_t status; + + if (down_trylock(&efi_runtime_lock)) + return EFI_NOT_READY; + + status = efi_call_virt(query_variable_info, + attr, + EFI_ADDR(query_variable_info.storage_space), + EFI_ADDR(query_variable_info.remaining_space), + EFI_ADDR(query_variable_info.max_variable_size)); + + *storage_space = EFI_DATA(query_variable_info.storage_space); + *remaining_space = EFI_DATA(query_variable_info.remaining_space); + *max_variable_size = EFI_DATA(query_variable_info.max_variable_size); + + up(&efi_runtime_lock); + return status; +} + +static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) +{ + efi_status_t status; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + status = efi_call_virt(get_next_high_mono_count, + EFI_ADDR(get_next_high_mono_count.count)); + + *count = EFI_DATA(get_next_high_mono_count.count); + + up(&efi_runtime_lock); + return status; +} + +static void virt_efi_reset_system(int reset_type, + efi_status_t status, + unsigned long data_size, + efi_char16_t *data) +{ + /* we don't use 'data' in the kernel */ + pr_warn("efi_reset_system: ignoring 'data' argument\n"); + + if (down_interruptible(&efi_runtime_lock)) { + pr_warn("failed to invoke the reset_system() runtime service:\n" + "could not get exclusive access to the firmware\n"); + return; + } + __efi_call_virt(reset_system, reset_type, status, 0, NULL); + up(&efi_runtime_lock); +} + +static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, + unsigned long count, + unsigned long sg_list) +{ +// efi_status_t status; + + return EFI_NOT_READY; + +// if (down_interruptible(&efi_runtime_lock)) +// return EFI_ABORTED; +// status = efi_call_virt(update_capsule, capsules, count, sg_list); +// up(&efi_runtime_lock); +// return status; +} + +static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, + unsigned long count, + u64 *max_size, + int *reset_type) +{ + efi_status_t status; + int i; + + if (count > MAX_CAPSULES) + return EFI_NOT_READY; + + if (down_interruptible(&efi_runtime_lock)) + return EFI_ABORTED; + + for (i = 0; i < count; i++) { + EFI_DATA(query_capsule_caps.capsules[i]) = *capsules[i]; + EFI_DATA(query_capsule_caps.capsule_headers[i]) = + EFI_ADDR(query_capsule_caps.capsules[i]); + } + + status = efi_call_virt(query_capsule_caps, + EFI_ADDR(query_capsule_caps.capsule_headers), + count, + EFI_ADDR(query_capsule_caps.max_size), + EFI_ADDR(query_capsule_caps.reset_type)); + + *max_size = EFI_DATA(query_capsule_caps.max_size); + *reset_type = EFI_DATA(query_capsule_caps.reset_type); + + up(&efi_runtime_lock); + return status; +} + +void efi_native_runtime_setup(void) +{ + efi.get_time = virt_efi_get_time; + efi.set_time = virt_efi_set_time; + efi.get_wakeup_time = virt_efi_get_wakeup_time; + efi.set_wakeup_time = virt_efi_set_wakeup_time; + efi.get_variable = virt_efi_get_variable; + efi.get_next_variable = virt_efi_get_next_variable; + efi.set_variable = virt_efi_set_variable; + efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; + efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; + efi.reset_system = virt_efi_reset_system; + efi.query_variable_info = virt_efi_query_variable_info; + efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; + efi.update_capsule = virt_efi_update_capsule; + efi.query_capsule_caps = virt_efi_query_capsule_caps; +}