xref: /aosp_15_r20/external/coreboot/tests/drivers/efivars.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <drivers/efi/efivars.h>
4 #include <vendorcode/intel/edk2/UDK2017/MdePkg/Include/Pi/PiFirmwareVolume.h>
5 #include <vendorcode/intel/edk2/UDK2017/MdeModulePkg/Include/Guid/VariableFormat.h>
6 #include <string.h>
7 #include <tests/test.h>
8 #include <types.h>
9 
10 /* Dummy firmware volume header for a 0x30000 byte partition with a single entry
11  * in a formatted variable store.
12  */
13 static const uint8_t FVH[] = {
14 	/* EFI_FIRMWARE_VOLUME_HEADER */
15 	/* UINT8 ZeroVector[16] */
16 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17 	0x00, 0x00,
18 	/* EFI_GUID FileSystemGuid */
19 	0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b,
20 	0x4f, 0x50,
21 	/* UINT64 FvLength */
22 	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
23 	/* UINT32 Signature */
24 	0x5f, 0x46, 0x56, 0x48,
25 	/* EFI_FVB_ATTRIBUTES_2 Attributes */
26 	0x36, 0x0e, 0x00, 0x00,
27 	/* UINT16 HeaderLength */
28 	0x48, 0x00,
29 	/* UINT16 Checksum */
30 	0x00, 0xfa,
31 	/* UINT16 ExtHeaderOffset */
32 	0x00, 0x00,
33 	/* UINT8 Reserved[1] */
34 	0x00,
35 	/* UINT8 Revision */
36 	0x02,
37 	/* EFI_FV_BLOCK_MAP_ENTRY BlockMap[2] */
38 	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
39 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 
41 	/* Variable Info Header */
42 	/* EFI_GUID Signature */
43 	0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3,
44 	0x77, 0x92,
45 	/* UINT32 Size */
46 	0xb8, 0xff, 0x00, 0x00,
47 	/* UINT8 Format */
48 	0x5a,
49 	/* UINT8 State */
50 	0xfe,
51 	/* UINT16 Reserved */
52 	0x00, 0x00,
53 	/* UINT32 Reserved1 */
54 	0x00, 0x00, 0x00, 0x00,
55 	/* AUTHENTICATED_VARIABLE_HEADER */
56 	/* UINT16 StartId */
57 	0xaa, 0x55,
58 	/* UINT8 State */
59 	0x3f,
60 	/* UINT8 Reserved */
61 	0xff,
62 	/* UINT32 Attributes */
63 	0x07, 0x00, 0x00, 0x00,
64 	/* UINT64 MonotonicCount */
65 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66 	/* EFI_TIME TimeStamp */
67 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68 	0xff, 0xff, 0xff, 0xff,
69 	/* UINT32 PubKeyIndex */
70 	0xff, 0xff, 0xff, 0xff,
71 	/* UINT32 NameSize */
72 	0x12, 0x00, 0x00, 0x00,
73 	/* UINT32 DataSize */
74 	0x09, 0x00, 0x00, 0x00,
75 	/* EFI_GUID VendorGuid */
76 	0x1d, 0x4c, 0xae, 0xce, 0x5b, 0x33, 0x85, 0x46, 0xa4, 0xa0, 0xfc, 0x4a,
77 	0x94, 0xee, 0xa0, 0x85,
78 	/* L"coreboot" */
79 	0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x62, 0x00,
80 	0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x00, 0x00,
81 	/* "is great" */
82 	0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x00,
83 };
84 
85 #define FVH_CHECKSUMMED_SIZE (sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 8 + sizeof(EFI_GUID))
86 
87 static struct region_device flash_rdev_rw;
88 static uint8_t flash_buffer[0x30000];
89 
90 static const char *name = "coreboot";
91 
mock_rdev(bool init)92 static void mock_rdev(bool init)
93 {
94 	if (init) {
95 		/* Emulate NOR flash by setting all bits to 1 */
96 		memset(flash_buffer, 0xff, sizeof(flash_buffer));
97 		/* Place _FVH and VIH headers, as well as test data */
98 		memcpy(flash_buffer, FVH, sizeof(FVH));
99 	}
100 
101 	rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, sizeof(flash_buffer));
102 }
103 
104 static const EFI_GUID EficorebootNvDataGuid = {
105 	0xceae4c1d, 0x335b, 0x4685, { 0xa4, 0xa0, 0xfc, 0x4a, 0x94, 0xee, 0xa0, 0x85 } };
106 
107 /* Test valid and corrupted FVH header */
efi_test_header(void ** state)108 static void efi_test_header(void **state)
109 {
110 	enum cb_err ret;
111 	uint8_t buf[16];
112 	uint32_t size;
113 	int i;
114 
115 	mock_rdev(true);
116 
117 	/* Test variable lookup with intact header */
118 	size = sizeof(buf);
119 	ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf, &size);
120 	assert_int_equal(ret, CB_SUCCESS);
121 	assert_int_equal(size, strlen("is great")+1);
122 	assert_string_equal((const char *)buf, "is great");
123 
124 	for (i = 0; i < FVH_CHECKSUMMED_SIZE; i++) {
125 		mock_rdev(true);
126 
127 		/* Flip some bits */
128 		flash_buffer[i] ^= 0xff;
129 
130 		size = sizeof(buf);
131 		ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf,
132 					&size);
133 		assert_int_not_equal(ret, CB_SUCCESS);
134 	}
135 }
136 
137 /* Write with the same key and value should not modify the store */
efi_test_noop_existing_write(void ** state)138 static void efi_test_noop_existing_write(void **state)
139 {
140 	enum cb_err ret;
141 	int i;
142 
143 	mock_rdev(true);
144 
145 	ret = efi_fv_set_option(&flash_rdev_rw,
146 				&EficorebootNvDataGuid,
147 				name,
148 				"is great",
149 				strlen("is great") + 1);
150 
151 	assert_int_equal(ret, CB_SUCCESS);
152 
153 	for (i = sizeof(FVH); i < sizeof(flash_buffer); i++)
154 		assert_int_equal(flash_buffer[i], 0xff);
155 }
156 
efi_test_new_write(void ** state)157 static void efi_test_new_write(void **state)
158 {
159 	enum cb_err ret;
160 	uint8_t buf[16];
161 	uint32_t size;
162 	int i;
163 
164 	mock_rdev(true);
165 
166 	ret = efi_fv_set_option(&flash_rdev_rw, &EficorebootNvDataGuid,
167 				name, "is awesome", strlen("is awesome") + 1);
168 	assert_int_equal(ret, CB_SUCCESS);
169 
170 	/* New variable has been written */
171 	assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4)], 0xaa);
172 	assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55);
173 
174 	/* Remaining space is blank */
175 	for (i = ALIGN_UP(sizeof(FVH), 4) + 89; i < sizeof(flash_buffer); i++)
176 		assert_int_equal(flash_buffer[i], 0xff);
177 
178 	mock_rdev(false);
179 
180 	memset(buf, 0, sizeof(buf));
181 	size = sizeof(buf);
182 	ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf,
183 				&size);
184 	assert_int_equal(ret, CB_SUCCESS);
185 	assert_int_equal(size, strlen("is awesome")+1);
186 
187 	assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55);
188 	assert_string_equal((const char *)buf, "is awesome");
189 }
190 
main(void)191 int main(void)
192 {
193 	const struct CMUnitTest tests[] = {
194 		cmocka_unit_test(efi_test_header),
195 		cmocka_unit_test(efi_test_noop_existing_write),
196 		cmocka_unit_test(efi_test_new_write)
197 	};
198 
199 	return cb_run_group_tests(tests, NULL, NULL);
200 }
201