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
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 0000000..8464e6e
--- /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 0000000..0c9cafe
--- /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 0000000..66def8f
--- /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 d89443f..1ffcb69 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -16,6 +16,7 @@
 	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 @@
 		"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"