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