summaryrefslogtreecommitdiff
path: root/meta-arm/meta-arm-bsp/recipes-security/trusted-services/secure-partitions/corstone1000/0015-Add-UEFI-variable-support-for-QueryVariableInfo.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-arm/meta-arm-bsp/recipes-security/trusted-services/secure-partitions/corstone1000/0015-Add-UEFI-variable-support-for-QueryVariableInfo.patch')
-rw-r--r--meta-arm/meta-arm-bsp/recipes-security/trusted-services/secure-partitions/corstone1000/0015-Add-UEFI-variable-support-for-QueryVariableInfo.patch830
1 files changed, 830 insertions, 0 deletions
diff --git a/meta-arm/meta-arm-bsp/recipes-security/trusted-services/secure-partitions/corstone1000/0015-Add-UEFI-variable-support-for-QueryVariableInfo.patch b/meta-arm/meta-arm-bsp/recipes-security/trusted-services/secure-partitions/corstone1000/0015-Add-UEFI-variable-support-for-QueryVariableInfo.patch
new file mode 100644
index 0000000000..978600dd94
--- /dev/null
+++ b/meta-arm/meta-arm-bsp/recipes-security/trusted-services/secure-partitions/corstone1000/0015-Add-UEFI-variable-support-for-QueryVariableInfo.patch
@@ -0,0 +1,830 @@
+From c4eaf83548eed4ed6194ff9e1368d6ae65f4ebf9 Mon Sep 17 00:00:00 2001
+From: Julian Hall <julian.hall@arm.com>
+Date: Thu, 2 Dec 2021 17:27:55 +0000
+Subject: [PATCH] Add UEFI variable support for QueryVariableInfo
+
+Adds support for the UEFI QueryVariableInfo operation. The total
+store size currently relies on pre-configured values, set for a
+particular deployment. Ideally, this information would be read
+from the storage backend. This facility is not however yet
+supported by the storage backend interface or by any PSA
+storage backend storage providers.
+
+Signed-off-by: Julian Hall <julian.hall@arm.com>
+Change-Id: I971252831f7e478914d736c672d184a371e64502
+
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
+
+
+---
+ .../backend/test/variable_store_tests.cpp | 89 +++++++-
+ .../backend/uefi_variable_store.c | 213 ++++++++++++++----
+ .../backend/uefi_variable_store.h | 39 +++-
+ .../client/cpp/smm_variable_client.cpp | 66 ++++++
+ .../client/cpp/smm_variable_client.h | 7 +
+ .../provider/smm_variable_provider.c | 31 ++-
+ .../service/smm_variable_service_tests.cpp | 55 ++++-
+ 7 files changed, 445 insertions(+), 55 deletions(-)
+
+diff --git a/components/service/smm_variable/backend/test/variable_store_tests.cpp b/components/service/smm_variable/backend/test/variable_store_tests.cpp
+index 578f118f..e90c1067 100644
+--- a/components/service/smm_variable/backend/test/variable_store_tests.cpp
++++ b/components/service/smm_variable/backend/test/variable_store_tests.cpp
+@@ -27,6 +27,18 @@ TEST_GROUP(UefiVariableStoreTests)
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+
++ uefi_variable_store_set_storage_limits(
++ &m_uefi_variable_store,
++ EFI_VARIABLE_NON_VOLATILE,
++ STORE_CAPACITY,
++ MAX_VARIABLE_SIZE);
++
++ uefi_variable_store_set_storage_limits(
++ &m_uefi_variable_store,
++ 0,
++ STORE_CAPACITY,
++ MAX_VARIABLE_SIZE);
++
+ setup_common_guid();
+ }
+
+@@ -152,6 +164,33 @@ TEST_GROUP(UefiVariableStoreTests)
+ return status;
+ }
+
++ efi_status_t query_variable_info(
++ uint32_t attributes,
++ size_t *max_variable_storage_size,
++ size_t *remaining_variable_storage_size,
++ size_t *max_variable_size)
++ {
++ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO query;
++
++ query.MaximumVariableStorageSize = 0;
++ query.RemainingVariableStorageSize = 0;
++ query.MaximumVariableSize = 0;
++ query.Attributes = attributes;
++
++ efi_status_t status = uefi_variable_store_query_variable_info(
++ &m_uefi_variable_store,
++ &query);
++
++ if (status == EFI_SUCCESS) {
++
++ *max_variable_storage_size = query.MaximumVariableStorageSize;
++ *remaining_variable_storage_size = query.RemainingVariableStorageSize;
++ *max_variable_size = query.MaximumVariableSize;
++ }
++
++ return status;
++ }
++
+ efi_status_t set_check_var_property(
+ const std::wstring &name,
+ const VAR_CHECK_VARIABLE_PROPERTY &check_property)
+@@ -195,7 +234,8 @@ TEST_GROUP(UefiVariableStoreTests)
+
+ if (info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
+
+- struct storage_backend *storage_backend = m_uefi_variable_store.persistent_store;
++ struct storage_backend *storage_backend =
++ m_uefi_variable_store.persistent_store.storage_backend;
+
+ storage_backend->interface->remove(
+ storage_backend->context,
+@@ -220,9 +260,24 @@ TEST_GROUP(UefiVariableStoreTests)
+ m_volatile_backend);
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
++
++ uefi_variable_store_set_storage_limits(
++ &m_uefi_variable_store,
++ EFI_VARIABLE_NON_VOLATILE,
++ STORE_CAPACITY,
++ MAX_VARIABLE_SIZE);
++
++ uefi_variable_store_set_storage_limits(
++ &m_uefi_variable_store,
++ 0,
++ STORE_CAPACITY,
++ MAX_VARIABLE_SIZE);
+ }
+
+ static const size_t MAX_VARIABLES = 10;
++ static const size_t MAX_VARIABLE_SIZE = 100;
++ static const size_t STORE_CAPACITY = 1000;
++
+ static const uint32_t OWNER_ID = 100;
+ static const size_t VARIABLE_BUFFER_SIZE = 1024;
+
+@@ -265,6 +320,22 @@ TEST(UefiVariableStoreTests, setGetRoundtrip)
+ /* Expect the append write operation to have extended the variable */
+ UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
+ LONGS_EQUAL(0, expected_output.compare(output_data));
++
++ /* Expect query_variable_info to return consistent values */
++ size_t max_variable_storage_size = 0;
++ size_t remaining_variable_storage_size = 0;
++ size_t max_variable_size = 0;
++
++ status = query_variable_info(
++ 0,
++ &max_variable_storage_size,
++ &remaining_variable_storage_size,
++ &max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
++
++ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY, max_variable_storage_size);
++ UNSIGNED_LONGLONGS_EQUAL(MAX_VARIABLE_SIZE, max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY - expected_output.size(), remaining_variable_storage_size);
+ }
+
+ TEST(UefiVariableStoreTests, persistentSetGet)
+@@ -311,6 +382,22 @@ TEST(UefiVariableStoreTests, persistentSetGet)
+ /* Still expect got variable data to be the same as the set value */
+ UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
+ LONGS_EQUAL(0, expected_output.compare(output_data));
++
++ /* Expect query_variable_info to return consistent values */
++ size_t max_variable_storage_size = 0;
++ size_t remaining_variable_storage_size = 0;
++ size_t max_variable_size = 0;
++
++ status = query_variable_info(
++ EFI_VARIABLE_NON_VOLATILE,
++ &max_variable_storage_size,
++ &remaining_variable_storage_size,
++ &max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
++
++ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY, max_variable_storage_size);
++ UNSIGNED_LONGLONGS_EQUAL(MAX_VARIABLE_SIZE, max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY - expected_output.size(), remaining_variable_storage_size);
+ }
+
+ TEST(UefiVariableStoreTests, removeVolatile)
+diff --git a/components/service/smm_variable/backend/uefi_variable_store.c b/components/service/smm_variable/backend/uefi_variable_store.c
+index bcb85995..ed50eaf9 100644
+--- a/components/service/smm_variable/backend/uefi_variable_store.c
++++ b/components/service/smm_variable/backend/uefi_variable_store.c
+@@ -46,8 +46,15 @@ static efi_status_t load_variable_data(
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
+ size_t max_data_len);
+
+-static psa_status_t append_write(
+- struct storage_backend *storage_backend,
++static psa_status_t store_overwrite(
++ struct delegate_variable_store *delegate_store,
++ uint32_t client_id,
++ uint64_t uid,
++ size_t data_length,
++ const void *data);
++
++static psa_status_t store_append_write(
++ struct delegate_variable_store *delegate_store,
+ uint32_t client_id,
+ uint64_t uid,
+ size_t data_length,
+@@ -56,6 +63,15 @@ static psa_status_t append_write(
+ static void purge_orphan_index_entries(
+ struct uefi_variable_store *context);
+
++static struct delegate_variable_store *select_delegate_store(
++ struct uefi_variable_store *context,
++ uint32_t attributes);
++
++static size_t space_used(
++ struct uefi_variable_store *context,
++ uint32_t attributes,
++ struct storage_backend *storage_backend);
++
+ static efi_status_t psa_to_efi_storage_status(
+ psa_status_t psa_status);
+
+@@ -66,6 +82,10 @@ static efi_status_t check_name_terminator(
+ /* Private UID for storing the variable index */
+ #define VARIABLE_INDEX_STORAGE_UID (1)
+
++/* Default maximum variable size -
++ * may be overridden using uefi_variable_store_set_storage_limits()
++ */
++#define DEFAULT_MAX_VARIABLE_SIZE (2048)
+
+ efi_status_t uefi_variable_store_init(
+ struct uefi_variable_store *context,
+@@ -76,8 +96,17 @@ efi_status_t uefi_variable_store_init(
+ {
+ efi_status_t status = EFI_SUCCESS;
+
+- context->persistent_store = persistent_store;
+- context->volatile_store = volatile_store;
++ /* Initialise persistent store defaults */
++ context->persistent_store.is_nv = true;
++ context->persistent_store.max_variable_size = DEFAULT_MAX_VARIABLE_SIZE;
++ context->persistent_store.total_capacity = DEFAULT_MAX_VARIABLE_SIZE * max_variables;
++ context->persistent_store.storage_backend = persistent_store;
++
++ /* Initialise volatile store defaults */
++ context->volatile_store.is_nv = false;
++ context->volatile_store.max_variable_size = DEFAULT_MAX_VARIABLE_SIZE;
++ context->volatile_store.total_capacity = DEFAULT_MAX_VARIABLE_SIZE * max_variables;
++ context->volatile_store.storage_backend = volatile_store;
+
+ context->owner_id = owner_id;
+ context->is_boot_service = true;
+@@ -116,6 +145,20 @@ void uefi_variable_store_deinit(
+ context->index_sync_buffer = NULL;
+ }
+
++void uefi_variable_store_set_storage_limits(
++ struct uefi_variable_store *context,
++ uint32_t attributes,
++ size_t total_capacity,
++ size_t max_variable_size)
++{
++ struct delegate_variable_store *delegate_store = select_delegate_store(
++ context,
++ attributes);
++
++ delegate_store->total_capacity = total_capacity;
++ delegate_store->max_variable_size = max_variable_size;
++}
++
+ efi_status_t uefi_variable_store_set_variable(
+ struct uefi_variable_store *context,
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
+@@ -284,12 +327,24 @@ efi_status_t uefi_variable_store_get_next_variable_name(
+
+ efi_status_t uefi_variable_store_query_variable_info(
+ struct uefi_variable_store *context,
+- SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *cur)
++ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *var_info)
+ {
+- efi_status_t status = EFI_UNSUPPORTED;
++ struct delegate_variable_store *delegate_store = select_delegate_store(
++ context,
++ var_info->Attributes);
+
++ size_t total_used = space_used(
++ context,
++ var_info->Attributes,
++ delegate_store->storage_backend);
+
+- return status;
++ var_info->MaximumVariableSize = delegate_store->max_variable_size;
++ var_info->MaximumVariableStorageSize = delegate_store->total_capacity;
++ var_info->RemainingVariableStorageSize = (total_used < delegate_store->total_capacity) ?
++ delegate_store->total_capacity - total_used :
++ 0;
++
++ return EFI_SUCCESS;
+ }
+
+ efi_status_t uefi_variable_store_exit_boot_service(
+@@ -375,7 +430,7 @@ efi_status_t uefi_variable_store_get_var_check_property(
+ static void load_variable_index(
+ struct uefi_variable_store *context)
+ {
+- struct storage_backend *persistent_store = context->persistent_store;
++ struct storage_backend *persistent_store = context->persistent_store.storage_backend;
+
+ if (persistent_store) {
+
+@@ -413,7 +468,7 @@ static efi_status_t sync_variable_index(
+
+ if (is_dirty) {
+
+- struct storage_backend *persistent_store = context->persistent_store;
++ struct storage_backend *persistent_store = context->persistent_store.storage_backend;
+
+ if (persistent_store) {
+
+@@ -501,30 +556,27 @@ static efi_status_t store_variable_data(
+ const uint8_t *data = (const uint8_t*)var +
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+
+- bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
+-
+- struct storage_backend *storage_backend = (is_nv) ?
+- context->persistent_store :
+- context->volatile_store;
++ struct delegate_variable_store *delegate_store = select_delegate_store(
++ context,
++ info->metadata.attributes);
+
+- if (storage_backend) {
++ if (delegate_store->storage_backend) {
+
+ if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) {
+
+ /* Create or overwrite variable data */
+- psa_status = storage_backend->interface->set(
+- storage_backend->context,
++ psa_status = store_overwrite(
++ delegate_store,
+ context->owner_id,
+ info->metadata.uid,
+ data_len,
+- data,
+- PSA_STORAGE_FLAG_NONE);
++ data);
+ }
+ else {
+
+ /* Append new data to existing variable data */
+- psa_status = append_write(
+- storage_backend,
++ psa_status = store_append_write(
++ delegate_store,
+ context->owner_id,
+ info->metadata.uid,
+ data_len,
+@@ -532,7 +584,7 @@ static efi_status_t store_variable_data(
+ }
+ }
+
+- if ((psa_status != PSA_SUCCESS) && is_nv) {
++ if ((psa_status != PSA_SUCCESS) && delegate_store->is_nv) {
+
+ /* A storage failure has occurred so attempt to fix any
+ * mismatch between the variable index and stored NV variables.
+@@ -551,16 +603,14 @@ static efi_status_t remove_variable_data(
+
+ if (info->is_variable_set) {
+
+- bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
++ struct delegate_variable_store *delegate_store = select_delegate_store(
++ context,
++ info->metadata.attributes);
+
+- struct storage_backend *storage_backend = (is_nv) ?
+- context->persistent_store :
+- context->volatile_store;
++ if (delegate_store->storage_backend) {
+
+- if (storage_backend) {
+-
+- psa_status = storage_backend->interface->remove(
+- storage_backend->context,
++ psa_status = delegate_store->storage_backend->interface->remove(
++ delegate_store->storage_backend->context,
+ context->owner_id,
+ info->metadata.uid);
+ }
+@@ -580,16 +630,14 @@ static efi_status_t load_variable_data(
+ uint8_t *data = (uint8_t*)var +
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
+
+- bool is_nv = (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
++ struct delegate_variable_store *delegate_store = select_delegate_store(
++ context,
++ info->metadata.attributes);
+
+- struct storage_backend *storage_backend = (is_nv) ?
+- context->persistent_store :
+- context->volatile_store;
++ if (delegate_store->storage_backend) {
+
+- if (storage_backend) {
+-
+- psa_status = storage_backend->interface->get(
+- storage_backend->context,
++ psa_status = delegate_store->storage_backend->interface->get(
++ delegate_store->storage_backend->context,
+ context->owner_id,
+ info->metadata.uid,
+ 0,
+@@ -603,8 +651,29 @@ static efi_status_t load_variable_data(
+ return psa_to_efi_storage_status(psa_status);
+ }
+
+-static psa_status_t append_write(
+- struct storage_backend *storage_backend,
++static psa_status_t store_overwrite(
++ struct delegate_variable_store *delegate_store,
++ uint32_t client_id,
++ uint64_t uid,
++ size_t data_length,
++ const void *data)
++{
++ /* Police maximum variable size limit */
++ if (data_length > delegate_store->max_variable_size) return PSA_ERROR_INVALID_ARGUMENT;
++
++ psa_status_t psa_status = delegate_store->storage_backend->interface->set(
++ delegate_store->storage_backend->context,
++ client_id,
++ uid,
++ data_length,
++ data,
++ PSA_STORAGE_FLAG_NONE);
++
++ return psa_status;
++}
++
++static psa_status_t store_append_write(
++ struct delegate_variable_store *delegate_store,
+ uint32_t client_id,
+ uint64_t uid,
+ size_t data_length,
+@@ -614,8 +683,8 @@ static psa_status_t append_write(
+
+ if (data_length == 0) return PSA_SUCCESS;
+
+- psa_status_t psa_status = storage_backend->interface->get_info(
+- storage_backend->context,
++ psa_status_t psa_status = delegate_store->storage_backend->interface->get_info(
++ delegate_store->storage_backend->context,
+ client_id,
+ uid,
+ &storage_info);
+@@ -628,6 +697,9 @@ static psa_status_t append_write(
+ /* Defend against integer overflow */
+ if (new_size < storage_info.size) return PSA_ERROR_INVALID_ARGUMENT;
+
++ /* Police maximum variable size limit */
++ if (new_size > delegate_store->max_variable_size) return PSA_ERROR_INVALID_ARGUMENT;
++
+ /* Storage backend doesn't support an append operation so we need
+ * need to read the current variable data, extend it and write it back.
+ */
+@@ -635,8 +707,8 @@ static psa_status_t append_write(
+ if (!rw_buf) return PSA_ERROR_INSUFFICIENT_MEMORY;
+
+ size_t old_size = 0;
+- psa_status = storage_backend->interface->get(
+- storage_backend->context,
++ psa_status = delegate_store->storage_backend->interface->get(
++ delegate_store->storage_backend->context,
+ client_id,
+ uid,
+ 0,
+@@ -651,8 +723,8 @@ static psa_status_t append_write(
+ /* Extend the variable data */
+ memcpy(&rw_buf[old_size], data, data_length);
+
+- psa_status = storage_backend->interface->set(
+- storage_backend->context,
++ psa_status = delegate_store->storage_backend->interface->set(
++ delegate_store->storage_backend->context,
+ client_id,
+ uid,
+ old_size + data_length,
+@@ -692,7 +764,7 @@ static void purge_orphan_index_entries(
+ if (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
+
+ struct psa_storage_info_t storage_info;
+- struct storage_backend *storage_backend = context->persistent_store;
++ struct storage_backend *storage_backend = context->persistent_store.storage_backend;
+
+ psa_status_t psa_status = storage_backend->interface->get_info(
+ storage_backend->context,
+@@ -714,6 +786,53 @@ static void purge_orphan_index_entries(
+ if (any_orphans) sync_variable_index(context);
+ }
+
++static struct delegate_variable_store *select_delegate_store(
++ struct uefi_variable_store *context,
++ uint32_t attributes)
++{
++ bool is_nv = (attributes & EFI_VARIABLE_NON_VOLATILE);
++
++ return (is_nv) ?
++ &context->persistent_store :
++ &context->volatile_store;
++}
++
++static size_t space_used(
++ struct uefi_variable_store *context,
++ uint32_t attributes,
++ struct storage_backend *storage_backend)
++{
++ if (!storage_backend) return 0;
++
++ size_t total_used = 0;
++ struct variable_index_iterator iter;
++ variable_index_iterator_first(&iter, &context->variable_index);
++
++ while (!variable_index_iterator_is_done(&iter)) {
++
++ struct variable_info *info = variable_index_iterator_current(&iter);
++
++ if (info->is_variable_set &&
++ ((info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE) ==
++ (attributes & EFI_VARIABLE_NON_VOLATILE))) {
++
++ struct psa_storage_info_t storage_info;
++
++ psa_status_t psa_status = storage_backend->interface->get_info(
++ storage_backend->context,
++ context->owner_id,
++ info->metadata.uid,
++ &storage_info);
++
++ if (psa_status == PSA_SUCCESS) total_used += storage_info.size;
++ }
++
++ variable_index_iterator_next(&iter);
++ }
++
++ return total_used;
++}
++
+ static efi_status_t psa_to_efi_storage_status(
+ psa_status_t psa_status)
+ {
+diff --git a/components/service/smm_variable/backend/uefi_variable_store.h b/components/service/smm_variable/backend/uefi_variable_store.h
+index fe0f24af..cc992067 100644
+--- a/components/service/smm_variable/backend/uefi_variable_store.h
++++ b/components/service/smm_variable/backend/uefi_variable_store.h
+@@ -20,6 +20,20 @@
+ extern "C" {
+ #endif
+
++/**
++ * \brief delegate_variable_store structure definition
++ *
++ * A delegate_variable_store combines an association with a concrete
++ * storage backend and a set of limits parameters.
++ */
++struct delegate_variable_store
++{
++ bool is_nv;
++ size_t total_capacity;
++ size_t max_variable_size;
++ struct storage_backend *storage_backend;
++};
++
+ /**
+ * \brief uefi_variable_store structure definition
+ *
+@@ -35,8 +49,8 @@ struct uefi_variable_store
+ uint8_t *index_sync_buffer;
+ size_t index_sync_buffer_size;
+ struct variable_index variable_index;
+- struct storage_backend *persistent_store;
+- struct storage_backend *volatile_store;
++ struct delegate_variable_store persistent_store;
++ struct delegate_variable_store volatile_store;
+ };
+
+ /**
+@@ -69,6 +83,23 @@ efi_status_t uefi_variable_store_init(
+ void uefi_variable_store_deinit(
+ struct uefi_variable_store *context);
+
++/**
++ * @brief Set storage limits
++ *
++ * Overrides the default limits for the specified storage space. These
++ * values are reflected in the values returned by QueryVariableInfo.
++ *
++ * @param[in] context uefi_variable_store instance
++ * @param[in] attributes EFI_VARIABLE_NON_VOLATILE or 0
++ * @param[in] total_capacity The total storage capacity in bytes
++ * @param[in] max_variable_size Variable size limit
++ */
++void uefi_variable_store_set_storage_limits(
++ struct uefi_variable_store *context,
++ uint32_t attributes,
++ size_t total_capacity,
++ size_t max_variable_size);
++
+ /**
+ * @brief Set variable
+ *
+@@ -123,13 +154,13 @@ efi_status_t uefi_variable_store_get_next_variable_name(
+ * @brief Query for variable info
+ *
+ * @param[in] context uefi_variable_store instance
+- * @param[out] info Returns info
++ * @param[inout] var_info Returns info
+ *
+ * @return EFI_SUCCESS if succesful
+ */
+ efi_status_t uefi_variable_store_query_variable_info(
+ struct uefi_variable_store *context,
+- SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *cur);
++ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *var_info);
+
+ /**
+ * @brief Exit boot service
+diff --git a/components/service/smm_variable/client/cpp/smm_variable_client.cpp b/components/service/smm_variable/client/cpp/smm_variable_client.cpp
+index a68b7ace..8438285b 100644
+--- a/components/service/smm_variable/client/cpp/smm_variable_client.cpp
++++ b/components/service/smm_variable/client/cpp/smm_variable_client.cpp
+@@ -219,6 +219,72 @@ efi_status_t smm_variable_client::get_next_variable_name(
+ 0);
+ }
+
++efi_status_t smm_variable_client::query_variable_info(
++ uint32_t attributes,
++ size_t *max_variable_storage_size,
++ size_t *remaining_variable_storage_size,
++ size_t *max_variable_size)
++{
++ efi_status_t efi_status = EFI_NOT_READY;
++
++ size_t req_len = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
++ rpc_call_handle call_handle;
++ uint8_t *req_buf;
++
++ call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
++
++ if (call_handle) {
++
++ uint8_t *resp_buf;
++ size_t resp_len;
++ rpc_opstatus_t opstatus;
++
++ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *query =
++ (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO*)req_buf;
++
++ query->Attributes = attributes;
++ query->MaximumVariableSize = 0;
++ query->MaximumVariableStorageSize = 0;
++ query->RemainingVariableStorageSize = 0;
++
++ m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
++ SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, &opstatus, &resp_buf, &resp_len);
++
++ if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
++
++ efi_status = opstatus;
++
++ if (efi_status == EFI_SUCCESS) {
++
++ if (resp_len >= sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
++
++ query = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO*)resp_buf;
++
++ *max_variable_storage_size = query->MaximumVariableStorageSize;
++ *remaining_variable_storage_size = query->RemainingVariableStorageSize;
++ *max_variable_size = query->MaximumVariableSize;
++ }
++ else {
++
++ efi_status = EFI_PROTOCOL_ERROR;
++ }
++ }
++ else {
++
++ efi_status = EFI_PROTOCOL_ERROR;
++ }
++ }
++ else {
++
++ efi_status = rpc_to_efi_status();
++ }
++
++ rpc_caller_end(m_caller, call_handle);
++ }
++
++ return efi_status;
++}
++
+ efi_status_t smm_variable_client::get_next_variable_name(
+ EFI_GUID &guid,
+ std::wstring &name,
+diff --git a/components/service/smm_variable/client/cpp/smm_variable_client.h b/components/service/smm_variable/client/cpp/smm_variable_client.h
+index 9c36c4eb..c7973916 100644
+--- a/components/service/smm_variable/client/cpp/smm_variable_client.h
++++ b/components/service/smm_variable/client/cpp/smm_variable_client.h
+@@ -63,6 +63,13 @@ public:
+ const EFI_GUID &guid,
+ const std::wstring &name);
+
++ /* Query variable info */
++ efi_status_t query_variable_info(
++ uint32_t attributes,
++ size_t *max_variable_storage_size,
++ size_t *remaining_variable_storage_size,
++ size_t *max_variable_size);
++
+ /* Get the next variable name - for enumerating store contents */
+ efi_status_t get_next_variable_name(
+ EFI_GUID &guid,
+diff --git a/components/service/smm_variable/provider/smm_variable_provider.c b/components/service/smm_variable/provider/smm_variable_provider.c
+index d239a428..52e68d09 100644
+--- a/components/service/smm_variable/provider/smm_variable_provider.c
++++ b/components/service/smm_variable/provider/smm_variable_provider.c
+@@ -252,11 +252,38 @@ static rpc_status_t set_variable_handler(void *context, struct call_req* req)
+
+ static rpc_status_t query_variable_info_handler(void *context, struct call_req* req)
+ {
++ efi_status_t efi_status = EFI_INVALID_PARAMETER;
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
+
+- /* todo */
++ const struct call_param_buf *req_buf = call_req_get_req_buf(req);
++
++ if (req_buf->data_len >= sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
++
++ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
++
++ if (resp_buf->size >= req_buf->data_len) {
+
+- return TS_RPC_ERROR_NOT_READY;
++ memmove(resp_buf->data, req_buf->data, req_buf->data_len);
++
++ efi_status = uefi_variable_store_query_variable_info(
++ &this_instance->variable_store,
++ (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO*)resp_buf->data);
++
++ if (efi_status == EFI_SUCCESS) {
++
++ resp_buf->data_len = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
++ }
++ }
++ else {
++
++ /* Reponse buffer not big enough */
++ efi_status = EFI_BAD_BUFFER_SIZE;
++ }
++ }
++
++ call_req_set_opstatus(req, efi_status);
++
++ return TS_RPC_CALL_ACCEPTED;
+ }
+
+ static rpc_status_t exit_boot_service_handler(void *context, struct call_req* req)
+diff --git a/components/service/smm_variable/test/service/smm_variable_service_tests.cpp b/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
+index 088940a8..15556e9d 100644
+--- a/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
++++ b/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
+@@ -335,12 +335,38 @@ TEST(SmmVariableServiceTests, setAndGetNv)
+ TEST(SmmVariableServiceTests, enumerateStoreContents)
+ {
+ efi_status_t efi_status = EFI_SUCCESS;
++
++ /* Query information about the empty variable store */
++ size_t nv_max_variable_storage_size = 0;
++ size_t nv_max_variable_size = 0;
++ size_t nv_remaining_variable_storage_size = 0;
++
++ efi_status = m_client->query_variable_info(
++ EFI_VARIABLE_NON_VOLATILE,
++ &nv_max_variable_storage_size,
++ &nv_remaining_variable_storage_size,
++ &nv_max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
++ UNSIGNED_LONGLONGS_EQUAL(nv_max_variable_storage_size, nv_remaining_variable_storage_size);
++
++ size_t v_max_variable_storage_size = 0;
++ size_t v_max_variable_size = 0;
++ size_t v_remaining_variable_storage_size = 0;
++
++ efi_status = m_client->query_variable_info(
++ 0,
++ &v_max_variable_storage_size,
++ &v_remaining_variable_storage_size,
++ &v_max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
++ UNSIGNED_LONGLONGS_EQUAL(v_max_variable_storage_size, v_remaining_variable_storage_size);
++
++ /* Add some variables to the store */
+ std::wstring var_name_1 = L"varibale_1";
+ std::wstring var_name_2 = L"varibale_2";
+ std::wstring var_name_3 = L"varibale_3";
+ std::string set_data = "Some variable data";
+
+- /* Add some variables to the store */
+ efi_status = m_client->set_variable(
+ m_common_guid,
+ var_name_1,
+@@ -365,6 +391,33 @@ TEST(SmmVariableServiceTests, enumerateStoreContents)
+
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
+
++ /* Query variable info again and check it's as expected */
++ size_t max_variable_storage_size = 0;
++ size_t max_variable_size = 0;
++ size_t remaining_variable_storage_size = 0;
++
++ /* Check non-volatile - two variables have been added */
++ efi_status = m_client->query_variable_info(
++ EFI_VARIABLE_NON_VOLATILE,
++ &max_variable_storage_size,
++ &remaining_variable_storage_size,
++ &max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
++ UNSIGNED_LONGLONGS_EQUAL(
++ (nv_remaining_variable_storage_size - set_data.size() * 2),
++ remaining_variable_storage_size);
++
++ /* Check volatile - one variables have been added */
++ efi_status = m_client->query_variable_info(
++ 0,
++ &max_variable_storage_size,
++ &remaining_variable_storage_size,
++ &max_variable_size);
++ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
++ UNSIGNED_LONGLONGS_EQUAL(
++ (v_remaining_variable_storage_size - set_data.size() * 1),
++ remaining_variable_storage_size);
++
+ /* Enumerate store contents - expect the values we added */
+ std::wstring var_name;
+ EFI_GUID guid = {0};