aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Hall <julian.hall@arm.com>2021-11-18 09:24:55 +0000
committerGyorgy Szing <Gyorgy.Szing@arm.com>2021-11-26 05:05:42 +0100
commit919b558abde8b042e6301a334874058d24c1d230 (patch)
treeae2e967c9d1f87fc086fe1db55aee68f6237d1c2
parent65f7eb400f3f4b02a631d48af9dce153b419412b (diff)
downloadtrusted-services-919b558abde8b042e6301a334874058d24c1d230.tar.gz
Add uefi variable store tests
Component tests for the uefi variable store are added and bugs fixed such that all added tests pass. Tests are added to the component-test deployment. Signed-off-by: Julian Hall <julian.hall@arm.com> Change-Id: Idde768a9fac1f18b370069d104f823fac6456ae5
-rw-r--r--components/service/smm_variable/backend/test/component.cmake14
-rw-r--r--components/service/smm_variable/backend/test/variable_index_tests.cpp391
-rw-r--r--components/service/smm_variable/backend/test/variable_store_tests.cpp393
-rw-r--r--deployments/component-test/component-test.cmake3
4 files changed, 801 insertions, 0 deletions
diff --git a/components/service/smm_variable/backend/test/component.cmake b/components/service/smm_variable/backend/test/component.cmake
new file mode 100644
index 000000000..8464e6e2d
--- /dev/null
+++ b/components/service/smm_variable/backend/test/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/variable_index_tests.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/variable_store_tests.cpp"
+ )
diff --git a/components/service/smm_variable/backend/test/variable_index_tests.cpp b/components/service/smm_variable/backend/test/variable_index_tests.cpp
new file mode 100644
index 000000000..0c9cafe97
--- /dev/null
+++ b/components/service/smm_variable/backend/test/variable_index_tests.cpp
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <wchar.h>
+#include <string>
+#include <vector>
+#include <CppUTest/TestHarness.h>
+#include <service/smm_variable/backend/variable_index.h>
+
+
+TEST_GROUP(UefiVariableIndexTests)
+{
+ void setup()
+ {
+ efi_status_t status = variable_index_init(&m_variable_index, MAX_VARIABLES);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ guid_1.Data1 = 0x12341234;
+ guid_1.Data2 = 0x1234;
+ guid_1.Data3 = 0x1234;
+ guid_1.Data4[0] = 0x00;
+ guid_1.Data4[1] = 0x01;
+ guid_1.Data4[2] = 0x02;
+ guid_1.Data4[3] = 0x03;
+ guid_1.Data4[4] = 0x04;
+ guid_1.Data4[5] = 0x05;
+ guid_1.Data4[6] = 0x06;
+ guid_1.Data4[7] = 0x07;
+
+ guid_2.Data1 = 0x55443322;
+ guid_2.Data2 = 0x2345;
+ guid_2.Data3 = 0x2345;
+ guid_2.Data4[0] = 0x10;
+ guid_2.Data4[1] = 0x11;
+ guid_2.Data4[2] = 0x12;
+ guid_2.Data4[3] = 0x13;
+ guid_2.Data4[4] = 0x14;
+ guid_2.Data4[5] = 0x15;
+ guid_2.Data4[6] = 0x16;
+ guid_2.Data4[7] = 0x17;
+
+ name_1 = to_variable_name(L"var1");
+ name_2 = to_variable_name(L"var2_nv");
+ name_3 = to_variable_name(L"var3_nv");
+ }
+
+ void teardown()
+ {
+ variable_index_deinit(&m_variable_index);
+ }
+
+ std::vector<int16_t> to_variable_name(const std::wstring &string)
+ {
+ std::vector<int16_t> var_name;
+
+ for (size_t i = 0; i < string.size(); i++) {
+
+ var_name.push_back((int16_t)string[i]);
+ }
+
+ var_name.push_back(0);
+
+ return var_name;
+ }
+
+ void create_variables()
+ {
+ const struct variable_info *info = NULL;
+
+ info = variable_index_add(
+ &m_variable_index,
+ &guid_1,
+ name_1.size() * sizeof(int16_t),
+ name_1.data(),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+
+ CHECK_TRUE(info);
+
+ info = variable_index_add(
+ &m_variable_index,
+ &guid_2,
+ name_2.size() * sizeof(int16_t),
+ name_2.data(),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
+
+ CHECK_TRUE(info);
+
+ info = variable_index_add(
+ &m_variable_index,
+ &guid_1,
+ name_3.size() * sizeof(int16_t),
+ name_3.data(),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
+
+ CHECK_TRUE(info);
+ }
+
+ static const size_t MAX_VARIABLES = 10;
+
+ struct variable_index m_variable_index;
+ EFI_GUID guid_1;
+ EFI_GUID guid_2;
+ std::vector<int16_t> name_1;
+ std::vector<int16_t> name_2;
+ std::vector<int16_t> name_3;
+};
+
+TEST(UefiVariableIndexTests, emptyIndexOperations)
+{
+ const struct variable_info *info = NULL;
+
+ /* Expect not to find a variable */
+ info = variable_index_find(
+ &m_variable_index,
+ &guid_1,
+ name_1.size() * sizeof(int16_t),
+ name_1.data());
+ POINTERS_EQUAL(NULL, info);
+
+ /* Expect also not to find the next variable */
+ info = variable_index_find_next(
+ &m_variable_index,
+ &guid_1,
+ name_1.size() * sizeof(int16_t),
+ name_1.data());
+ POINTERS_EQUAL(NULL, info);
+
+ /* Remove should silently return */
+ variable_index_remove(
+ &m_variable_index,
+ &guid_1,
+ name_1.size() * sizeof(int16_t),
+ name_1.data());
+}
+
+TEST(UefiVariableIndexTests, addWithOversizedName)
+{
+ const struct variable_info *info = NULL;
+ std::vector<int16_t> name;
+
+ name = to_variable_name(L"a long variable name that exceeds the length limit");
+
+ info = variable_index_add(
+ &m_variable_index,
+ &guid_1,
+ name.size() * sizeof(int16_t),
+ name.data(),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+
+ /* Expect the add to fail because of an oversized name */
+ POINTERS_EQUAL(NULL, info);
+
+ name = to_variable_name(L"a long variable name that fits!");
+
+ info = variable_index_add(
+ &m_variable_index,
+ &guid_1,
+ name.size() * sizeof(int16_t),
+ name.data(),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+
+ /* Expect the add succeed */
+ CHECK_TRUE(info);
+}
+
+TEST(UefiVariableIndexTests, variableIndexFull)
+{
+ const struct variable_info *info = NULL;
+ EFI_GUID guid = guid_1;
+
+ /* Expect to be able to fill the index */
+ for (size_t i = 0; i < MAX_VARIABLES; ++i) {
+
+ info = variable_index_add(
+ &m_variable_index,
+ &guid,
+ name_1.size() * sizeof(int16_t),
+ name_1.data(),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+
+ CHECK_TRUE(info);
+
+ /* Modify the guid for the next add */
+ guid.Data1 += 1;
+ }
+
+ /* Variable index should now be full */
+ info = variable_index_add(
+ &m_variable_index,
+ &guid,
+ name_1.size() * sizeof(int16_t),
+ name_1.data(),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
+
+ POINTERS_EQUAL(NULL, info);
+}
+
+
+TEST(UefiVariableIndexTests, enumerateStore)
+{
+ const struct variable_info *info = NULL;
+ const std::vector<int16_t> null_name = to_variable_name(L"");
+
+ create_variables();
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &guid_1,
+ null_name.size() * sizeof(int16_t),
+ null_name.data());
+ CHECK_TRUE(info);
+ LONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->attributes);
+ MEMCMP_EQUAL(&guid_1, &info->guid, sizeof(EFI_GUID));
+ MEMCMP_EQUAL(name_1.data(), info->name, name_1.size());
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->guid,
+ info->name_size,
+ info->name);
+ CHECK_TRUE(info);
+ LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, info->attributes);
+ MEMCMP_EQUAL(&guid_2, &info->guid, sizeof(EFI_GUID));
+ MEMCMP_EQUAL(name_2.data(), info->name, name_2.size());
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->guid,
+ info->name_size,
+ info->name);
+ CHECK_TRUE(info);
+ LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS, info->attributes);
+ MEMCMP_EQUAL(&guid_1, &info->guid, sizeof(EFI_GUID));
+ MEMCMP_EQUAL(name_3.data(), info->name, name_3.size());
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->guid,
+ info->name_size,
+ info->name);
+ POINTERS_EQUAL(NULL, info);
+}
+
+TEST(UefiVariableIndexTests, dumpLoadRoadtrip)
+{
+ uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_info)];
+
+ create_variables();
+
+ /* Expect the info for two NV variables to have been dumped */
+ size_t dump_len = 0;
+ bool is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
+
+ CHECK_TRUE(is_dirty);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 2), dump_len);
+
+ /* Expect no records to be dirty when the dump is repeated */
+ dump_len = 0;
+ is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
+
+ CHECK_FALSE(is_dirty);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 2), dump_len);
+
+ /* Tear down and reinitialize to simulate a reboot */
+ variable_index_deinit(&m_variable_index);
+ efi_status_t status = variable_index_init(&m_variable_index, MAX_VARIABLES);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Load the dumped contents */
+ size_t load_len = variable_index_restore(&m_variable_index, dump_len, buffer);
+ UNSIGNED_LONGS_EQUAL(dump_len, load_len);
+
+ /* Enumerate and now expect only NV variables to be present */
+ const struct variable_info *info = NULL;
+ std::vector<int16_t> null_name = to_variable_name(L"");
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &guid_1,
+ null_name.size() * sizeof(int16_t),
+ null_name.data());
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ info->attributes);
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->guid,
+ info->name_size,
+ info->name);
+ CHECK_TRUE(info);
+ UNSIGNED_LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS,
+ info->attributes);
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &info->guid,
+ info->name_size,
+ info->name);
+ POINTERS_EQUAL(NULL, info);
+}
+
+TEST(UefiVariableIndexTests, dumpBufferTooSmall)
+{
+ uint8_t buffer[1 * sizeof(struct variable_info) + 1];
+
+ create_variables();
+
+ /* There should be two NV variables whose info needs saving. The buffer provided
+ * however is only big enough for one. Expect the dumped data length to not
+ * exceed the length of the buffer.
+ */
+ size_t dump_len = 0;
+ bool is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
+
+ CHECK_TRUE(is_dirty);
+ UNSIGNED_LONGS_EQUAL(sizeof(struct variable_info) * 1, dump_len);
+}
+
+
+TEST(UefiVariableIndexTests, removeVariable)
+{
+ uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_info)];
+
+ create_variables();
+
+ /* Remove one of the NV variables */
+ variable_index_remove(
+ &m_variable_index,
+ &guid_2,
+ name_2.size() * sizeof(int16_t),
+ name_2.data());
+
+ /* Expect index to be dirty and for only one NV variable to be left */
+ size_t dump_len = 0;
+ bool is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
+
+ CHECK_TRUE(is_dirty);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 1), dump_len);
+
+ /* Remove the volatile variable */
+ variable_index_remove(
+ &m_variable_index,
+ &guid_1,
+ name_1.size() * sizeof(int16_t),
+ name_1.data());
+
+ /* Expect index not to be dirty because there was no change to any NV variable */
+ dump_len = 0;
+ is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
+
+ CHECK_FALSE(is_dirty);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 1), dump_len);
+
+ /* Remove the remaining NV variable */
+ variable_index_remove(
+ &m_variable_index,
+ &guid_1,
+ name_3.size() * sizeof(int16_t),
+ name_3.data());
+
+ /* Expect index to be dirty and dump to now be empty */
+ dump_len = 0;
+ is_dirty = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len);
+
+ CHECK_TRUE(is_dirty);
+ UNSIGNED_LONGS_EQUAL((sizeof(struct variable_info) * 0), dump_len);
+
+ /* Repeat the remove on an empty index. This should have no effect on the empty state
+ * of the index.
+ */
+ variable_index_remove(
+ &m_variable_index,
+ &guid_1,
+ name_3.size(),
+ name_3.data());
+
+ /* Enumerate and now expect an empty index */
+ const struct variable_info *info = NULL;
+ std::vector<int16_t> null_name = to_variable_name(L"");
+
+ info = variable_index_find_next(
+ &m_variable_index,
+ &guid_1,
+ null_name.size() * sizeof(int16_t),
+ null_name.data());
+ POINTERS_EQUAL(NULL, info);
+}
diff --git a/components/service/smm_variable/backend/test/variable_store_tests.cpp b/components/service/smm_variable/backend/test/variable_store_tests.cpp
new file mode 100644
index 000000000..66def8f8a
--- /dev/null
+++ b/components/service/smm_variable/backend/test/variable_store_tests.cpp
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string>
+#include <vector>
+#include <string.h>
+#include <CppUTest/TestHarness.h>
+#include <service/smm_variable/backend/uefi_variable_store.h>
+#include <service/secure_storage/backend/mock_store/mock_store.h>
+
+TEST_GROUP(UefiVariableStoreTests)
+{
+ void setup()
+ {
+ m_persistent_backend = mock_store_init(&m_persistent_store);
+ m_volatile_backend = mock_store_init(&m_volatile_store);
+
+ efi_status_t status = uefi_variable_store_init(
+ &m_uefi_variable_store,
+ OWNER_ID,
+ MAX_VARIABLES,
+ m_persistent_backend,
+ m_volatile_backend);
+
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ setup_common_guid();
+ }
+
+ void teardown()
+ {
+ uefi_variable_store_deinit(&m_uefi_variable_store);
+ }
+
+ void setup_common_guid()
+ {
+ m_common_guid.Data1 = 0x12341234;
+ m_common_guid.Data2 = 0x1234;
+ m_common_guid.Data3 = 0x1234;
+ m_common_guid.Data4[0] = 0x00;
+ m_common_guid.Data4[1] = 0x01;
+ m_common_guid.Data4[2] = 0x02;
+ m_common_guid.Data4[3] = 0x03;
+ m_common_guid.Data4[4] = 0x04;
+ m_common_guid.Data4[5] = 0x05;
+ m_common_guid.Data4[6] = 0x06;
+ m_common_guid.Data4[7] = 0x07;
+ }
+
+ std::vector<int16_t> to_variable_name(const std::wstring &string)
+ {
+ std::vector<int16_t> var_name;
+
+ for (size_t i = 0; i < string.size(); i++) {
+
+ var_name.push_back((int16_t)string[i]);
+ }
+
+ /* Add mandatory null terminator */
+ var_name.push_back(0);
+
+ return var_name;
+ }
+
+ bool compare_variable_name(
+ const std::wstring &expected,
+ const int16_t *name,
+ size_t name_size) {
+
+ bool is_equal = (expected.size() + 1 <= name_size / sizeof(int16_t));
+
+ for (size_t i = 0; is_equal && i < expected.size(); i++) {
+
+ if (name[i] != (int16_t)expected[i]) {
+
+ is_equal = false;
+ break;
+ }
+ }
+
+ return is_equal;
+ }
+
+ efi_status_t set_variable(
+ const std::wstring &name,
+ const std::string &data,
+ uint32_t attributes)
+ {
+ std::vector<int16_t> var_name = to_variable_name(name);
+ size_t name_size = var_name.size() * sizeof(int16_t);
+ size_t data_size = data.size();
+ uint8_t msg_buffer[SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_SIZE(name_size, data_size)];
+
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_variable =
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)msg_buffer;
+
+ access_variable->Guid = m_common_guid;
+ access_variable->Attributes = attributes;
+
+ access_variable->NameSize = name_size;
+ memcpy(access_variable->Name, var_name.data(), name_size);
+
+ access_variable->DataSize = data_size;
+ memcpy(&msg_buffer[SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable)],
+ data.c_str(), data_size);
+
+ efi_status_t status = uefi_variable_store_set_variable(
+ &m_uefi_variable_store,
+ access_variable);
+
+ return status;
+ }
+
+ efi_status_t get_variable(
+ const std::wstring &name,
+ std::string &data)
+ {
+ std::vector<int16_t> var_name = to_variable_name(name);
+ size_t name_size = var_name.size() * sizeof(int16_t);
+ size_t total_size = 0;
+ uint8_t msg_buffer[VARIABLE_BUFFER_SIZE];
+
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_variable =
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)msg_buffer;
+
+ access_variable->Guid = m_common_guid;
+ access_variable->Attributes = 0;
+
+ access_variable->NameSize = name_size;
+ memcpy(access_variable->Name, var_name.data(), name_size);
+
+ access_variable->DataSize = 0;
+
+ efi_status_t status = uefi_variable_store_get_variable(
+ &m_uefi_variable_store,
+ access_variable,
+ VARIABLE_BUFFER_SIZE -
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable),
+ &total_size);
+
+ if (status == EFI_SUCCESS) {
+
+ const char *data_start = (const char*)(msg_buffer +
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(access_variable));
+
+ data = std::string(data_start, access_variable->DataSize);
+ }
+
+ return status;
+ }
+
+ void power_cycle()
+ {
+ /* Simulate a power-cycle */
+ uefi_variable_store_deinit(&m_uefi_variable_store);
+
+ /* Lose volatile store contents */
+ mock_store_reset(&m_volatile_store);
+
+ efi_status_t status = uefi_variable_store_init(
+ &m_uefi_variable_store,
+ OWNER_ID,
+ MAX_VARIABLES,
+ m_persistent_backend,
+ m_volatile_backend);
+
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ }
+
+ static const size_t MAX_VARIABLES = 10;
+ static const uint32_t OWNER_ID = 100;
+ static const size_t VARIABLE_BUFFER_SIZE = 1024;
+
+ struct uefi_variable_store m_uefi_variable_store;
+ struct mock_store m_persistent_store;
+ struct mock_store m_volatile_store;
+ struct storage_backend *m_persistent_backend;
+ struct storage_backend *m_volatile_backend;
+ EFI_GUID m_common_guid;
+};
+
+TEST(UefiVariableStoreTests, setGetRoundtrip)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name = L"test_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ status = set_variable(var_name, input_data, 0);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect got variable data to be the same as the set value */
+ UNSIGNED_LONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+}
+
+TEST(UefiVariableStoreTests, persistentSetGet)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name = L"test_variable";
+ std::string input_data = "quick brown fox";
+ std::string output_data;
+
+ status = set_variable(var_name, input_data, EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect got variable data to be the same as the set value */
+ UNSIGNED_LONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+
+ /* Expect the variable to survive a power cycle */
+ power_cycle();
+
+ output_data = std::string();
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Still expect got variable data to be the same as the set value */
+ UNSIGNED_LONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+}
+
+TEST(UefiVariableStoreTests, bootServiceAccess)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name = L"test_variable";
+ std::string input_data = "a variable with access restricted to boot";
+ std::string output_data;
+
+ status = set_variable(
+ var_name,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* 'Reboot' */
+ power_cycle();
+
+ /* Expect access to be permitted */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+
+ /* End of boot phase */
+ status = uefi_variable_store_exit_boot_service(&m_uefi_variable_store);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect access to be blocked */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGS_EQUAL(EFI_ACCESS_DENIED, status);
+}
+
+TEST(UefiVariableStoreTests, runtimeAccess)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name = L"test_variable";
+ std::string input_data = "a variable with access restricted to runtime";
+ std::string output_data;
+
+ status = set_variable(
+ var_name,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* 'Reboot' */
+ power_cycle();
+
+ status = get_variable(var_name, output_data);
+
+ UNSIGNED_LONGS_EQUAL(EFI_ACCESS_DENIED, status);
+ /* End of boot phase */
+ status = uefi_variable_store_exit_boot_service(&m_uefi_variable_store);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Expect access to be permitted */
+ status = get_variable(var_name, output_data);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ UNSIGNED_LONGS_EQUAL(input_data.size(), output_data.size());
+ LONGS_EQUAL(0, input_data.compare(output_data));
+}
+
+TEST(UefiVariableStoreTests, enumerateStoreContents)
+{
+ efi_status_t status = EFI_SUCCESS;
+ std::wstring var_name_1 = L"test_variable_1";
+ std::wstring var_name_2 = L"test_variable_2";
+ std::wstring var_name_3 = L"test_variable_3";
+ std::string input_data = "blah blah";
+
+ /* Add some variables - a mixture of NV and volatile */
+ status = set_variable(
+ var_name_1,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = set_variable(
+ var_name_2,
+ input_data,
+ 0);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ status = set_variable(
+ var_name_3,
+ input_data,
+ EFI_VARIABLE_NON_VOLATILE);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+
+ /* Prepare to enumerate */
+ uint8_t msg_buffer[VARIABLE_BUFFER_SIZE];
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *next_name =
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)msg_buffer;
+ size_t max_name_len = VARIABLE_BUFFER_SIZE -
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET;
+
+ /* Enumerate store contents */
+ size_t total_len = 0;
+ next_name->NameSize = sizeof(int16_t);
+ next_name->Name[0] = 0;
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_2, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_3, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGS_EQUAL(EFI_NOT_FOUND, status);
+
+ power_cycle();
+
+ /* Enumerate again - should be left with just NV variables.
+ * Use a different but equally valid null name.
+ */
+ next_name->NameSize = 10 * sizeof(int16_t);
+ memset(next_name->Name, 0, next_name->NameSize);
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_1, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
+ CHECK_TRUE(compare_variable_name(var_name_3, next_name->Name, next_name->NameSize));
+
+ status = uefi_variable_store_get_next_variable_name(
+ &m_uefi_variable_store,
+ next_name,
+ max_name_len,
+ &total_len);
+ UNSIGNED_LONGS_EQUAL(EFI_NOT_FOUND, status);
+}
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index d89443fa6..1ffcb695f 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -16,6 +16,7 @@ add_components(
COMPONENTS
"components/app/ts-demo"
"components/app/ts-demo/test"
+ "components/common/utils"
"components/common/uuid"
"components/common/uuid/test"
"components/common/tlv"
@@ -117,6 +118,8 @@ add_components(
"components/service/test_runner/provider"
"components/service/test_runner/provider/serializer/packed-c"
"components/service/test_runner/provider/backend/null"
+ "components/service/smm_variable/backend"
+ "components/service/smm_variable/backend/test"
"protocols/rpc/common/protobuf"
"protocols/rpc/common/packed-c"
"protocols/service/crypto/packed-c"