diff options
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.patch | 830 |
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}; |