xref: /aosp_15_r20/external/vboot_reference/tests/vb2_host_nvdata_flashrom_tests.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2020 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Tests for crossystem flashrom-based nvdata functions.
6  */
7 
8 #include <fcntl.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include "2api.h"
16 #include "2common.h"
17 #include "2constants.h"
18 #include "2nvstorage.h"
19 #include "2return_codes.h"
20 #include "common/tests.h"
21 #include "crossystem_vbnv.h"
22 #include "flashrom.h"
23 
24 /* Mocked flashrom only supports host programmer, and RW_NVRAM
25    region. */
assert_mock_params(const char * programmer,const char * region)26 static void assert_mock_params(const char *programmer, const char *region)
27 {
28 	TEST_STR_EQ(programmer, FLASHROM_PROGRAMMER_INTERNAL_AP,
29 		    "Using internal AP programmer");
30 	TEST_STR_EQ(region, "RW_NVRAM", "Using NVRAM region");
31 }
32 
33 static bool mock_flashrom_fail;
34 
35 /* To support both 16-byte and 64-byte nvdata with the same fake
36    eeprom, we can size the flash chip to be 16x64. So, for 16-byte
37    nvdata, this is a flash chip with 64 entries, and for 64-byte
38    nvdata, this is a flash chip with 16 entries. */
39 static uint8_t fake_flash_region[VB2_NVDATA_SIZE * VB2_NVDATA_SIZE_V2];
40 static int fake_flash_entry_count;
41 
42 static const uint8_t test_nvdata_16b[] = {
43 	0x60, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4e,
44 	0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x5e,
45 };
46 
47 static const uint8_t test_nvdata2_16b[] = {
48 	0x60, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4c,
49 	0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78,
50 };
51 
52 static const uint8_t blank_nvdata_16b[] = {
53 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55 };
56 
reset_test_data(struct vb2_context * ctx,int nvdata_size)57 static void reset_test_data(struct vb2_context *ctx, int nvdata_size)
58 {
59 	/* Initialize the context value. */
60 	ctx->flags = 0;
61 
62 	switch (nvdata_size) {
63 	case VB2_NVDATA_SIZE:
64 		fake_flash_entry_count = VB2_NVDATA_SIZE_V2;
65 		memcpy(ctx->nvdata, test_nvdata_16b, sizeof(test_nvdata_16b));
66 		break;
67 	case VB2_NVDATA_SIZE_V2:
68 		ctx->flags |= VB2_CONTEXT_NVDATA_V2;
69 		fake_flash_entry_count = VB2_NVDATA_SIZE;
70 		/* TODO: create some test data for 64-byte nvdata and
71 		   put it here. Right now, this only tests 16-byte
72 		   nvdata. */
73 		break;
74 	default:
75 		/* This is not valid. */
76 		TEST_TRUE(false, "Test failed, invalid nvdata size");
77 		fake_flash_entry_count = 0;
78 		break;
79 	}
80 
81 	/* Clear the fake flash chip. */
82 	memset(fake_flash_region, 0xff, sizeof(fake_flash_region));
83 
84 	/* Flashrom succeeds unless the test says otherwise. */
85 	mock_flashrom_fail = false;
86 }
87 
88 /* Mocked flashrom_read for tests. */
flashrom_read(struct firmware_image * image,const char * region)89 vb2_error_t flashrom_read(struct firmware_image *image, const char *region)
90 {
91 	if (mock_flashrom_fail) {
92 		image->data = NULL;
93 		image->size = 0;
94 		return VB2_ERROR_FLASHROM;
95 	}
96 
97 	assert_mock_params(image->programmer, region);
98 
99 	image->data = malloc(sizeof(fake_flash_region));
100 	image->size = sizeof(fake_flash_region);
101 	memcpy(image->data, fake_flash_region, sizeof(fake_flash_region));
102 	return VB2_SUCCESS;
103 }
104 
105 /* Mocked flashrom_write for tests. */
flashrom_write(struct firmware_image * image,const char * region)106 vb2_error_t flashrom_write(struct firmware_image *image, const char *region)
107 {
108 	if (mock_flashrom_fail)
109 		return VB2_ERROR_FLASHROM;
110 
111 	assert_mock_params(image->programmer, region);
112 
113 	TEST_EQ(image->size, sizeof(fake_flash_region),
114 		"The flash size is correct");
115 	memcpy(fake_flash_region, image->data, image->size);
116 	return VB2_SUCCESS;
117 }
118 
test_read_ok_beginning(void)119 static void test_read_ok_beginning(void)
120 {
121 	struct vb2_context ctx;
122 
123 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
124 	memcpy(fake_flash_region, test_nvdata2_16b, sizeof(test_nvdata2_16b));
125 
126 	TEST_EQ(vb2_read_nv_storage_flashrom(&ctx), 0,
127 		"Reading storage succeeds");
128 	TEST_EQ(memcmp(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)),
129 		0, "The nvdata in the vb2_context was updated from flash");
130 }
131 
test_read_ok_2ndentry(void)132 static void test_read_ok_2ndentry(void)
133 {
134 	struct vb2_context ctx;
135 
136 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
137 	memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b));
138 	memcpy(fake_flash_region + VB2_NVDATA_SIZE, test_nvdata2_16b,
139 	       sizeof(test_nvdata2_16b));
140 
141 	TEST_EQ(vb2_read_nv_storage_flashrom(&ctx), 0,
142 		"Reading storage succeeds");
143 	TEST_EQ(memcmp(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)),
144 		0, "The nvdata in the vb2_context was updated from flash");
145 }
146 
test_read_ok_full(void)147 static void test_read_ok_full(void)
148 {
149 	struct vb2_context ctx;
150 
151 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
152 
153 	for (int entry = 0; entry < fake_flash_entry_count - 1; entry++)
154 		memcpy(fake_flash_region + (entry * VB2_NVDATA_SIZE),
155 		       test_nvdata_16b, sizeof(test_nvdata_16b));
156 
157 	memcpy(fake_flash_region +
158 	       ((fake_flash_entry_count - 1) * VB2_NVDATA_SIZE),
159 	       test_nvdata2_16b, sizeof(test_nvdata2_16b));
160 
161 	TEST_EQ(vb2_read_nv_storage_flashrom(&ctx), 0,
162 		"Reading storage succeeds");
163 	TEST_EQ(memcmp(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)),
164 		0, "The nvdata in the vb2_context was updated from flash");
165 }
166 
test_read_fail_uninitialized(void)167 static void test_read_fail_uninitialized(void)
168 {
169 	struct vb2_context ctx;
170 
171 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
172 
173 	TEST_NEQ(vb2_read_nv_storage_flashrom(&ctx), 0,
174 		 "Reading storage fails when flash is erased");
175 }
176 
test_read_fail_flashrom(void)177 static void test_read_fail_flashrom(void)
178 {
179 	struct vb2_context ctx;
180 
181 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
182 	memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b));
183 	mock_flashrom_fail = true;
184 
185 	TEST_NEQ(vb2_read_nv_storage_flashrom(&ctx), 0,
186 		 "Reading storage fails when flashrom fails");
187 }
188 
test_write_ok_uninitialized(void)189 static void test_write_ok_uninitialized(void)
190 {
191 	struct vb2_context ctx;
192 
193 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
194 	memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b));
195 
196 	TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0,
197 		"Writing storage succeeds when the flash is erased");
198 	TEST_EQ(memcmp(fake_flash_region, test_nvdata2_16b,
199 		       sizeof(test_nvdata2_16b)),
200 		0, "Entry 0 in the flash was written");
201 }
202 
test_write_ok_beginning(void)203 static void test_write_ok_beginning(void)
204 {
205 	struct vb2_context ctx;
206 
207 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
208 	memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b));
209 	memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b));
210 
211 	TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0,
212 		"Writing storage succeeds");
213 	TEST_EQ(memcmp(fake_flash_region + VB2_NVDATA_SIZE, test_nvdata2_16b,
214 		       sizeof(test_nvdata2_16b)),
215 		0, "Entry 1 in the flash was written");
216 }
217 
test_write_ok_2ndentry(void)218 static void test_write_ok_2ndentry(void)
219 {
220 	struct vb2_context ctx;
221 
222 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
223 	memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b));
224 	memcpy(fake_flash_region + VB2_NVDATA_SIZE, test_nvdata_16b,
225 	       sizeof(test_nvdata_16b));
226 	memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b));
227 
228 	TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0,
229 		"Writing storage succeeds");
230 	TEST_EQ(memcmp(fake_flash_region + (2 * VB2_NVDATA_SIZE),
231 		       test_nvdata2_16b, sizeof(test_nvdata2_16b)),
232 		0, "Entry 2 in the flash was written");
233 }
234 
test_write_ok_full(void)235 static void test_write_ok_full(void)
236 {
237 	struct vb2_context ctx;
238 	uint8_t expected_flash[sizeof(fake_flash_region)];
239 
240 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
241 
242 	for (int entry = 0; entry < fake_flash_entry_count; entry++)
243 		memcpy(fake_flash_region + (entry * VB2_NVDATA_SIZE),
244 		       test_nvdata_16b, sizeof(test_nvdata_16b));
245 
246 	memcpy(expected_flash, test_nvdata2_16b, sizeof(test_nvdata2_16b));
247 	memset(expected_flash + VB2_NVDATA_SIZE, 0xff,
248 	       sizeof(expected_flash) - VB2_NVDATA_SIZE);
249 	memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b));
250 
251 	TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0,
252 		"Writing storage succeeds");
253 	TEST_EQ(memcmp(fake_flash_region, expected_flash,
254 		       sizeof(expected_flash)),
255 		0,
256 		"The flash was erased and the new entry was placed at "
257 		"the beginning");
258 }
259 
test_write_ok_corrupted_flash(void)260 static void test_write_ok_corrupted_flash(void)
261 {
262 	struct vb2_context ctx;
263 
264 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
265 
266 	/* Entry 0 is blank, but entry 1 is used */
267 	memcpy(fake_flash_region + VB2_NVDATA_SIZE,
268 	       test_nvdata_16b, sizeof(test_nvdata_16b));
269 	memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b));
270 
271 	TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0,
272 		"Writing corrupted storage succeeds");
273 	TEST_EQ(memcmp(fake_flash_region, test_nvdata2_16b,
274 		       sizeof(test_nvdata2_16b)),
275 		0, "Entry 0 in the flash was written");
276 	TEST_EQ(memcmp(fake_flash_region + VB2_NVDATA_SIZE,
277 		       blank_nvdata_16b, sizeof(blank_nvdata_16b)),
278 		0, "Entry 1 in the flash was erased");
279 	TEST_EQ(memcmp(fake_flash_region + (2 * VB2_NVDATA_SIZE),
280 		       blank_nvdata_16b, sizeof(blank_nvdata_16b)),
281 		0, "Entry 2 in the flash was not written");
282 }
283 
test_write_fail_flashrom(void)284 static void test_write_fail_flashrom(void)
285 {
286 	struct vb2_context ctx;
287 
288 	reset_test_data(&ctx, sizeof(test_nvdata_16b));
289 	memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b));
290 	mock_flashrom_fail = true;
291 
292 	TEST_NEQ(vb2_write_nv_storage_flashrom(&ctx), 0,
293 		 "Writing storage fails when flashrom fails");
294 }
295 
main(int argc,char * argv[])296 int main(int argc, char *argv[])
297 {
298 	test_read_ok_beginning();
299 	test_read_ok_2ndentry();
300 	test_read_ok_full();
301 	test_read_fail_uninitialized();
302 	test_read_fail_flashrom();
303 	test_write_ok_uninitialized();
304 	test_write_ok_beginning();
305 	test_write_ok_2ndentry();
306 	test_write_ok_full();
307 	test_write_ok_corrupted_flash();
308 	test_write_fail_flashrom();
309 
310 	return gTestSuccess ? 0 : 255;
311 }
312