References: FATE#314499, FATE#314509

# Commit 9be8a4447103d92843fcfeaad8be42408c90e9a9
# Date 2013-04-22 13:58:01 +0200
# Author Jan Beulich <jbeulich@suse.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86/EFI: pass boot services variable info to runtime code

EFI variables can be flagged as being accessible only within boot services.
This makes it awkward for us to figure out how much space they use at
runtime. In theory we could figure this out by simply comparing the results
from QueryVariableInfo() to the space used by all of our variables, but
that fails if the platform doesn't garbage collect on every boot. Thankfully,
calling QueryVariableInfo() while still inside boot services gives a more
reliable answer. This patch passes that information from the EFI boot stub
up to the efi platform code.

Based on a similarly named Linux patch by Matthew Garrett <matthew.garrett@nebula.com>.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
Acked-by: George Dunlap <george.dunlap@eu.citrix.com>

# Commit 47f71a8ccb0c881cf3d9e0b917ef5f0dc084b062
# Date 2013-05-23 13:08:51 +0200
# Author Eric Shelton <eshelton@pobox.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86/EFI: fix boot for pre-UEFI systems

efi/boot.c makes a call to QueryVariableInfo on all systems.  However,
as it is only promised for UEFI 2.0+ systems, pre-UEFI systems can
hang or crash on this call.  The below patch adds a version check, a
technique used in other parts of the Xen EFI codebase.

Signed-off-by: Eric Shelton <eshelton@pobox.com>

Check runtime services version instead of EFI version (while generally
they would be in sync, nothing requires them to be).

Signed-off-by: Jan Beulich <jbeulich@suse.com>

--- a/xen/arch/x86/efi/boot.c
+++ b/xen/arch/x86/efi/boot.c
@@ -1128,6 +1128,25 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
     if (efi.smbios != EFI_INVALID_TABLE_ADDR)
         dmi_efi_get_table((void *)(long)efi.smbios);
 
+    /* Get snapshot of variable store parameters. */
+    status = (efi_rs->Hdr.Revision >> 16) >= 2 ?
+             efi_rs->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE |
+                                       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                       EFI_VARIABLE_RUNTIME_ACCESS,
+                                       &efi_boot_max_var_store_size,
+                                       &efi_boot_remain_var_store_size,
+                                       &efi_boot_max_var_size) :
+             EFI_INCOMPATIBLE_VERSION;
+    if ( EFI_ERROR(status) )
+    {
+        efi_boot_max_var_store_size = 0;
+        efi_boot_remain_var_store_size = 0;
+        efi_boot_max_var_size = status;
+        PrintStr(L"Warning: Could not query variable store: ");
+        DisplayUint(status, 0);
+        PrintStr(newline);
+    }
+
     /* Allocate space for trampoline (in first Mb). */
     cfg.addr = 0x100000;
     cfg.size = trampoline_end - trampoline_start;
--- a/xen/arch/x86/efi/efi.h
+++ b/xen/arch/x86/efi/efi.h
@@ -22,5 +22,8 @@ extern void *efi_memmap;
 
 extern l4_pgentry_t *efi_l4_pgtable;
 
+extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size,
+              efi_boot_max_var_size;
+
 unsigned long efi_rs_enter(void);
 void efi_rs_leave(unsigned long);
--- a/xen/arch/x86/efi/runtime.c
+++ b/xen/arch/x86/efi/runtime.c
@@ -28,6 +28,10 @@ UINTN __read_mostly efi_memmap_size;
 UINTN __read_mostly efi_mdesc_size;
 void *__read_mostly efi_memmap;
 
+UINT64 __read_mostly efi_boot_max_var_store_size;
+UINT64 __read_mostly efi_boot_remain_var_store_size;
+UINT64 __read_mostly efi_boot_max_var_size;
+
 struct efi __read_mostly efi = {
 	.acpi   = EFI_INVALID_TABLE_ADDR,
 	.acpi20 = EFI_INVALID_TABLE_ADDR,
@@ -446,6 +450,35 @@ int efi_runtime_call(struct xenpf_efi_ru
     break;
 
     case XEN_EFI_query_variable_info:
+        if ( op->misc & ~XEN_EFI_VARINFO_BOOT_SNAPSHOT )
+            return -EINVAL;
+
+        if ( op->misc & XEN_EFI_VARINFO_BOOT_SNAPSHOT )
+        {
+            if ( (op->u.query_variable_info.attr
+                  & ~EFI_VARIABLE_APPEND_WRITE) !=
+                 (EFI_VARIABLE_NON_VOLATILE |
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                  EFI_VARIABLE_RUNTIME_ACCESS) )
+                return -EINVAL;
+
+            op->u.query_variable_info.max_store_size =
+                efi_boot_max_var_store_size;
+            op->u.query_variable_info.remain_store_size =
+                efi_boot_remain_var_store_size;
+            if ( efi_boot_max_var_store_size )
+            {
+                op->u.query_variable_info.max_size = efi_boot_max_var_size;
+                status = EFI_SUCCESS;
+            }
+            else
+            {
+                op->u.query_variable_info.max_size = 0;
+                status = efi_boot_max_var_size;
+            }
+            break;
+        }
+
         cr3 = efi_rs_enter();
         if ( (efi_rs->Hdr.Revision >> 16) < 2 )
         {
@@ -462,6 +495,9 @@ int efi_runtime_call(struct xenpf_efi_ru
 
     case XEN_EFI_query_capsule_capabilities:
     case XEN_EFI_update_capsule:
+        if ( op->misc )
+            return -EINVAL;
+
         cr3 = efi_rs_enter();
         if ( (efi_rs->Hdr.Revision >> 16) < 2 )
         {
--- a/xen/include/efi/efiapi.h
+++ b/xen/include/efi/efiapi.h
@@ -213,6 +213,10 @@ VOID
 #define EFI_VARIABLE_NON_VOLATILE           0x00000001
 #define EFI_VARIABLE_BOOTSERVICE_ACCESS     0x00000002
 #define EFI_VARIABLE_RUNTIME_ACCESS         0x00000004
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD  0x00000008
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
+#define EFI_VARIABLE_APPEND_WRITE           0x00000040
 
 // Variable size limitation
 #define EFI_MAXIMUM_VARIABLE_SIZE           1024
--- a/xen/include/efi/efierr.h
+++ b/xen/include/efi/efierr.h
@@ -50,6 +50,7 @@ Revision History
 #define EFI_ICMP_ERROR                  EFIERR(22)
 #define EFI_TFTP_ERROR                  EFIERR(23)
 #define EFI_PROTOCOL_ERROR              EFIERR(24)
+#define EFI_INCOMPATIBLE_VERSION        EFIERR(25)
 
 #define EFI_WARN_UNKOWN_GLYPH           EFIWARN(1)
 #define EFI_WARN_DELETE_FAILURE         EFIWARN(2)
--- a/xen/include/public/platform.h
+++ b/xen/include/public/platform.h
@@ -184,6 +184,7 @@ struct xenpf_efi_runtime_call {
             struct xenpf_efi_guid vendor_guid;
         } get_next_variable_name;
 
+#define XEN_EFI_VARINFO_BOOT_SNAPSHOT       0x00000001
         struct {
             uint32_t attr;
             uint64_t max_store_size;
