summaryrefslogtreecommitdiff
path: root/tests/drivers/efivars.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/drivers/efivars.c')
-rw-r--r--tests/drivers/efivars.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/tests/drivers/efivars.c b/tests/drivers/efivars.c
new file mode 100644
index 0000000000..6899ce5bba
--- /dev/null
+++ b/tests/drivers/efivars.c
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <drivers/efi/efivars.h>
+#include <limits.h>
+#include <vendorcode/intel/edk2/UDK2017/MdePkg/Include/Pi/PiFirmwareVolume.h>
+#include <vendorcode/intel/edk2/UDK2017/MdeModulePkg/Include/Guid/VariableFormat.h>
+#include <string.h>
+#include <tests/test.h>
+#include <types.h>
+
+/* Dummy firmware volume header for a 0x30000 byte partition with a single entry
+ * in a formatted variable store.
+ */
+static const uint8_t FVH[] = {
+ /* EFI_FIRMWARE_VOLUME_HEADER */
+ /* UINT8 ZeroVector[16] */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ /* EFI_GUID FileSystemGuid */
+ 0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b,
+ 0x4f, 0x50,
+ /* UINT64 FvLength */
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* UINT32 Signature */
+ 0x5f, 0x46, 0x56, 0x48,
+ /* EFI_FVB_ATTRIBUTES_2 Attributes */
+ 0x36, 0x0e, 0x00, 0x00,
+ /* UINT16 HeaderLength */
+ 0x48, 0x00,
+ /* UINT16 Checksum */
+ 0x00, 0xfa,
+ /* UINT16 ExtHeaderOffset */
+ 0x00, 0x00,
+ /* UINT8 Reserved[1] */
+ 0x00,
+ /* UINT8 Revision */
+ 0x02,
+ /* EFI_FV_BLOCK_MAP_ENTRY BlockMap[2] */
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* Variable Info Header */
+ /* EFI_GUID Signature */
+ 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3,
+ 0x77, 0x92,
+ /* UINT32 Size */
+ 0xb8, 0xff, 0x00, 0x00,
+ /* UINT8 Format */
+ 0x5a,
+ /* UINT8 State */
+ 0xfe,
+ /* UINT16 Reserved */
+ 0x00, 0x00,
+ /* UINT32 Reserved1 */
+ 0x00, 0x00, 0x00, 0x00,
+ /* AUTHENTICATED_VARIABLE_HEADER */
+ /* UINT16 StartId */
+ 0xaa, 0x55,
+ /* UINT8 State */
+ 0x3f,
+ /* UINT8 Reserved */
+ 0xff,
+ /* UINT32 Attributes */
+ 0x07, 0x00, 0x00, 0x00,
+ /* UINT64 MonotonicCount */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* EFI_TIME TimeStamp */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ /* UINT32 PubKeyIndex */
+ 0xff, 0xff, 0xff, 0xff,
+ /* UINT32 NameSize */
+ 0x12, 0x00, 0x00, 0x00,
+ /* UINT32 DataSize */
+ 0x09, 0x00, 0x00, 0x00,
+ /* EFI_GUID VendorGuid */
+ 0x1d, 0x4c, 0xae, 0xce, 0x5b, 0x33, 0x85, 0x46, 0xa4, 0xa0, 0xfc, 0x4a,
+ 0x94, 0xee, 0xa0, 0x85,
+ /* L"coreboot" */
+ 0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x62, 0x00,
+ 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x00, 0x00,
+ /* "is great" */
+ 0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x00,
+};
+
+#define FVH_CHECKSUMMED_SIZE (sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 8 + sizeof(EFI_GUID))
+
+static struct region_device flash_rdev_rw;
+static uint8_t flash_buffer[0x30000];
+
+static const char *name = "coreboot";
+
+static void mock_rdev(bool init)
+{
+ if (init) {
+ /* Emulate NOR flash by setting all bits to 1 */
+ memset(flash_buffer, 0xff, sizeof(flash_buffer));
+ /* Place _FVH and VIH headers, as well as test data */
+ memcpy(flash_buffer, FVH, sizeof(FVH));
+ }
+
+ rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, sizeof(flash_buffer));
+}
+
+static const EFI_GUID EficorebootNvDataGuid = {
+ 0xceae4c1d, 0x335b, 0x4685, { 0xa4, 0xa0, 0xfc, 0x4a, 0x94, 0xee, 0xa0, 0x85 } };
+
+/* Test valid and corrupted FVH header */
+static void efi_test_header(void **state)
+{
+ enum cb_err ret;
+ uint8_t buf[16];
+ uint32_t size;
+ int i;
+
+ mock_rdev(true);
+
+ /* Test variable lookup with intact header */
+ size = sizeof(buf);
+ ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf, &size);
+ assert_int_equal(ret, CB_SUCCESS);
+ assert_int_equal(size, strlen("is great")+1);
+ assert_string_equal((const char *)buf, "is great");
+
+ for (i = 0; i < FVH_CHECKSUMMED_SIZE; i++) {
+ mock_rdev(true);
+
+ /* Flip some bits */
+ flash_buffer[i] ^= 0xff;
+
+ size = sizeof(buf);
+ ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf,
+ &size);
+ assert_int_not_equal(ret, CB_SUCCESS);
+ }
+}
+
+/* Write with the same key and value should not modify the store */
+static void efi_test_noop_existing_write(void **state)
+{
+ enum cb_err ret;
+ int i;
+
+ mock_rdev(true);
+
+ ret = efi_fv_set_option(&flash_rdev_rw,
+ &EficorebootNvDataGuid,
+ name,
+ "is great",
+ strlen("is great") + 1);
+
+ assert_int_equal(ret, CB_SUCCESS);
+
+ for (i = sizeof(FVH); i < sizeof(flash_buffer); i++)
+ assert_int_equal(flash_buffer[i], 0xff);
+}
+
+static void efi_test_new_write(void **state)
+{
+ enum cb_err ret;
+ uint8_t buf[16];
+ uint32_t size;
+ int i;
+
+ mock_rdev(true);
+
+ ret = efi_fv_set_option(&flash_rdev_rw, &EficorebootNvDataGuid,
+ name, "is awesome", strlen("is awesome") + 1);
+ assert_int_equal(ret, CB_SUCCESS);
+
+ /* New variable has been written */
+ assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4)], 0xaa);
+ assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55);
+
+ /* Remaining space is blank */
+ for (i = ALIGN_UP(sizeof(FVH), 4) + 89; i < sizeof(flash_buffer); i++)
+ assert_int_equal(flash_buffer[i], 0xff);
+
+ mock_rdev(false);
+
+ memset(buf, 0, sizeof(buf));
+ size = sizeof(buf);
+ ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf,
+ &size);
+ assert_int_equal(ret, CB_SUCCESS);
+ assert_int_equal(size, strlen("is awesome")+1);
+
+ assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55);
+ assert_string_equal((const char *)buf, "is awesome");
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(efi_test_header),
+ cmocka_unit_test(efi_test_noop_existing_write),
+ cmocka_unit_test(efi_test_new_write)
+ };
+
+ return cb_run_group_tests(tests, NULL, NULL);
+}