On 3/17/20 3:12 AM, AKASHI Takahiro wrote:
There are platforms on which OS's won't be able to access UEFI variables
at runtime (i.e. after ExitBootServices).
With this patch, all the UEFI variables are exported as a configuration
table so as to enable retrieving variables' values from the table, and
later modifying them via capsule-on-disk if necessary.

I do not understand why we should expose our internal memory for holding
UEFI variables to the operating system. This might end up in users
trying to access the variables directly.

I do not understand why we should not keep the pointer in our private
memory.

Best regards

Heinrich


The idea is based on Peter's proposal[1] in boot-arch ML.

[1] 
https://lists.linaro.org/pipermail/boot-architecture/2018-October/000883.html

Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org>
---
  include/efi_loader.h          |   7 +++
  lib/efi_loader/Kconfig        |  10 ++++
  lib/efi_loader/efi_boottime.c |  10 ++++
  lib/efi_loader/efi_capsule.c  |   4 ++
  lib/efi_loader/efi_variable.c | 109 ++++++++++++++++++++++++++++++++++
  5 files changed, 140 insertions(+)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 79bdf9586d24..93ed5502821c 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -183,6 +183,8 @@ extern const efi_guid_t efi_guid_hii_string_protocol;
  extern const efi_guid_t efi_guid_capsule_report;
  /* GUID of firmware management protocol */
  extern const efi_guid_t efi_guid_firmware_management_protocol;
+/* GUID of runtime variable access */
+extern const efi_guid_t efi_guid_variable_storage;

  /* GUID of RNG protocol */
  extern const efi_guid_t efi_guid_rng_protocol;
@@ -659,6 +661,10 @@ efi_status_t EFIAPI efi_query_variable_info(
                        u64 *remaining_variable_storage_size,
                        u64 *maximum_variable_size);

+#ifdef CONFIG_EFI_VARIABLE_EXPORT
+efi_status_t efi_install_variables_table(void);
+#endif
+
  /*
   * See section 3.1.3 in the v2.7 UEFI spec for more details on
   * the layout of EFI_LOAD_OPTION.  In short it is:
@@ -683,6 +689,7 @@ struct efi_load_option {
  void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
  unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 
**data);
  efi_status_t efi_bootmgr_load(efi_handle_t *handle);
+efi_status_t efi_install_variables_table(void);

  /* Capsule update */
  efi_status_t EFIAPI efi_update_capsule(
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 616e2acbe102..edb8d19059ea 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -41,6 +41,16 @@ config EFI_SET_TIME
          Provide the SetTime() runtime service at boottime. This service
          can be used by an EFI application to adjust the real time clock.

+config EFI_VARIABLE_EXPORT
+       bool "Export variables table as configuration table"
+       depends on !EFI_VARIABLE_RUNTIME_ACCESS
+       depends on  EFI_CAPSULE_UPDATE_VARIABLE
+       default y
+       help
+         Select this option if you want to export UEFI variables as
+         configuration table so that OS can still get UEFI variable's
+         value.
+
  config EFI_DEVICE_PATH_TO_TEXT
        bool "Device path to text protocol"
        default y
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index c2a789b4f910..406644e4da67 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2898,6 +2898,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t 
image_handle,
        if (ret != EFI_SUCCESS)
                return EFI_EXIT(EFI_INVALID_PARAMETER);

+#ifdef CONFIG_EFI_VARIABLE_EXPORT
+       /* Install variables database as a configuration table */
+       ret = efi_install_variables_table();
+       if (ret != EFI_SUCCESS)
+               return EFI_EXIT(ret);
+#endif
+       /*
+        * TODO: remove a table after image is terminated.
+        */
+
        image_obj->exit_data_size = exit_data_size;
        image_obj->exit_data = exit_data;

diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 1293270aea95..6b737aec1b28 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -18,7 +18,11 @@ static const efi_guid_t 
efi_guid_firmware_management_capsule_id =
                EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
  const efi_guid_t efi_guid_firmware_management_protocol =
                EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
+#ifdef CONFIG_EFI_VARIABLE_EXPORT
+const efi_guid_t efi_guid_variable_storage = EFI_VARIABLE_STORAGE_GUID;
+#else
  static const efi_guid_t efi_guid_variable_storage = EFI_VARIABLE_STORAGE_GUID;
+#endif

  /* for file system access */
  static struct efi_file_handle *bootdev_root;
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index c316bdfec0e4..270e5211f633 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -641,3 +641,112 @@ efi_status_t efi_init_variables(void)
  {
        return EFI_SUCCESS;
  }
+
+#ifdef CONFIG_EFI_VARIABLE_EXPORT
+/**
+ * efi_install_variables_table() - install variables table
+ *
+ * This function adds a configuration table that contains all the cache
+ * data of UEFI variables for runtime access.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_install_variables_table(void)
+{
+       u16 var_name16[64];
+       efi_uintn_t var_name16_len;
+       efi_guid_t guid;
+       u32 attributes;
+       struct efi_capsule_header capsule;
+       u8 *data = NULL, *p;
+       efi_uintn_t capsule_size;
+       struct efi_ebbr_variable variable;
+       u8 *var_buf;
+       efi_uintn_t var_size, var_max_size;
+       efi_status_t ret;
+
+       capsule.capsule_guid = efi_guid_variable_storage;
+       capsule.header_size = sizeof(capsule);
+       capsule.flags = CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;
+       capsule_size = sizeof(capsule);
+
+       /* Determine size of capsule */
+       var_name16[0] = 0;
+       var_name16_len = 64;
+       var_buf = NULL;
+       var_max_size = 0;
+       for (;;) {
+               ret = EFI_CALL(efi_get_next_variable_name(&var_name16_len,
+                                                         var_name16,
+                                                         &guid));
+               if (ret == EFI_NOT_FOUND)
+                       break;
+               else if (ret != EFI_SUCCESS)
+                       goto out;
+
+               var_size = 0;
+               ret = EFI_CALL(efi_get_variable(var_name16, &guid, &attributes,
+                                               &var_size, var_buf));
+               if (ret != EFI_BUFFER_TOO_SMALL)
+                       goto out;
+
+               capsule_size += sizeof(variable) + var_size;
+               if (var_size > var_max_size)
+                       var_max_size = var_size;
+       }
+       capsule.capsule_image_size = capsule_size;
+
+       ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA,
+                               capsule_size, (void **)&data);
+       if (ret != EFI_SUCCESS)
+               return EFI_OUT_OF_RESOURCES;
+
+       var_buf = malloc(var_max_size);
+       if (!var_buf) {
+               ret = EFI_OUT_OF_RESOURCES;
+               goto out;
+       }
+
+       /* Copy data */
+       p = data;
+       memcpy(p, &capsule, sizeof(capsule));
+       p += sizeof(capsule);
+
+       var_name16[0] = 0;
+       for (;;) {
+               ret = EFI_CALL(efi_get_next_variable_name(&var_name16_len,
+                                                         var_name16, &guid));
+               if (ret == EFI_NOT_FOUND)
+                       break;
+               else if (ret != EFI_SUCCESS)
+                       goto out;
+
+               var_size = var_max_size;
+               ret = EFI_CALL(efi_get_variable(var_name16, &guid, &attributes,
+                                               &var_size, var_buf));
+               if (ret != EFI_SUCCESS)
+                       /* should not happen */
+                       goto out;
+
+               u16_strcpy(variable.variable_name, var_name16);
+               variable.vendor_guid = guid;
+               variable.attributes = attributes;
+               variable.data_size = var_size;
+
+               memcpy(p, &variable, sizeof(variable));
+               p += sizeof(variable);
+               memcpy(p, var_buf, var_size);
+               p += var_size;
+       }
+
+       ret = EFI_CALL(efi_install_configuration_table(
+                               &efi_guid_variable_storage, data));
+
+out:
+       free(var_buf);
+       if (ret != EFI_SUCCESS && data)
+               efi_free_pool(data);
+
+       return ret;
+}
+#endif /* CONFIG_EFI_VARIABLE_EXPORT */


Reply via email to