aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Hall <julian.hall@arm.com>2021-12-02 17:27:55 +0000
committerGyorgy Szing <Gyorgy.Szing@arm.com>2021-12-07 09:49:46 +0100
commit7fe88cbe8d5c3b6104f79f23126af5f46ad1633f (patch)
tree7bd1724c064462c0a25de32964c9526f7d86696e
parent4b8dd0a55eb32cb77576157bfec03a0a8261208f (diff)
downloadtrusted-services-7fe88cbe8d5c3b6104f79f23126af5f46ad1633f.tar.gz
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
-rw-r--r--components/service/smm_variable/backend/test/variable_store_tests.cpp89
-rw-r--r--components/service/smm_variable/backend/uefi_variable_store.c213
-rw-r--r--components/service/smm_variable/backend/uefi_variable_store.h39
-rw-r--r--components/service/smm_variable/client/cpp/smm_variable_client.cpp66
-rw-r--r--components/service/smm_variable/client/cpp/smm_variable_client.h7
-rw-r--r--components/service/smm_variable/provider/smm_variable_provider.c31
-rw-r--r--components/service/smm_variable/test/service/smm_variable_service_tests.cpp55
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 578f118f9..e90c10674 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 bcb859952..ed50eaf95 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 fe0f24af4..cc9920673 100644
--- a/components/service/smm_variable/backend/uefi_variable_store.h
+++ b/components/service/smm_variable/backend/uefi_variable_store.h
@@ -21,6 +21,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
*
* A uefi_variable_store provides a variable store using a persistent and a
@@ -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;
};
/**
@@ -70,6 +84,23 @@ 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
*
* Corresponds to the SetVariable UEFI operation
@@ -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 a68b7acec..8438285b0 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 9c36c4eb2..c79739161 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 d239a4283..52e68d097 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 088940a83..15556e9d8 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};