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