xref: /aosp_15_r20/external/vboot_reference/tests/vb2_host_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 host flashrom utilities.
6  */
7 
8 /* For strdup */
9 #define _POSIX_C_SOURCE 200809L
10 
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include "2common.h"
20 #include "2return_codes.h"
21 #include "common/tests.h"
22 #include "host_misc.h"
23 #include "flashrom.h"
24 #include "subprocess.h"
25 
26 #define MOCK_TMPFILE_NAME "/tmp/vb2_unittest"
27 #define MOCK_ROM_CONTENTS "bloop123"
28 
29 static bool flashrom_mock_success = true;
30 static enum { FLASHROM_NONE, FLASHROM_READ, FLASHROM_WRITE } captured_operation;
31 static enum {
32 	FLASHROM_VERIFY_UNSPECIFIED,
33 	FLASHROM_VERIFY_FAST,
34 } captured_verify;
35 static const char *captured_op_filename;
36 static const char *captured_region_param;
37 static const char *captured_programmer;
38 static uint8_t *captured_rom_contents;
39 static uint32_t captured_rom_size;
40 
41 /* Mocked mkstemp for tests. */
mkstemp(char * template_name)42 int mkstemp(char *template_name)
43 {
44 	strncpy(template_name, MOCK_TMPFILE_NAME, strlen(template_name));
45 	return open(template_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
46 }
47 
48 /* Mocked subprocess_run for tests. */
subprocess_run(const char * const argv[],struct subprocess_target * input,struct subprocess_target * output,struct subprocess_target * error)49 int subprocess_run(const char *const argv[],
50 		   struct subprocess_target *input,
51 		   struct subprocess_target *output,
52 		   struct subprocess_target *error)
53 {
54 	int argc;
55 	int opt;
56 	int rv;
57 	/* getopt_long wants an int instead of an enum, bummer... */
58 	int captured_verify_int = FLASHROM_VERIFY_UNSPECIFIED;
59 	struct option long_opts[] = {
60 		{
61 			.name = "noverify-all",
62 			.has_arg = no_argument,
63 			.flag = &captured_verify_int,
64 			.val = FLASHROM_VERIFY_FAST,
65 		},
66 	};
67 
68 	/* Reset static variables to their defaults. */
69 	captured_operation = FLASHROM_NONE;
70 	captured_operation = FLASHROM_VERIFY_UNSPECIFIED;
71 	captured_op_filename = NULL;
72 	captured_region_param = NULL;
73 	captured_programmer = NULL;
74 	captured_rom_contents = NULL;
75 	captured_rom_size = 0;
76 	optind = 0;
77 
78 	/* Count the number of arguments, a required formalism for
79 	   getopt. */
80 	for (argc = 0; argv[argc]; argc++)
81 		continue;
82 
83 	/* We only understand the subset of arguments used by the
84 	   wrapper library.  If it's updated to support more modes of
85 	   operation, this unit test code should be updated too. */
86 	while ((opt = getopt_long(argc, (char *const *)argv,
87 				  ":p:r:w:i:", long_opts, NULL)) != -1) {
88 		/* Always consume the next argument if it does not
89 		   start with a dash.  We have to muck with getopt's
90 		   global variables to make this happen. */
91 		if (opt == ':' && argv[optind] && argv[optind][0] != '-') {
92 			optarg = strdup(argv[optind]);
93 			optind++;
94 			opt = optopt;
95 		} else if (optarg && optarg[0] == '-') {
96 			optarg = NULL;
97 			optind--;
98 		} else if (optarg) {
99 			optarg = strdup(optarg);
100 		}
101 
102 		switch (opt) {
103 		case 'p':
104 			captured_programmer = optarg;
105 			break;
106 		case 'r':
107 			captured_operation = FLASHROM_READ;
108 			captured_op_filename = optarg;
109 			break;
110 		case 'w':
111 			captured_operation = FLASHROM_WRITE;
112 			captured_op_filename = optarg;
113 			break;
114 		case 'i':
115 			captured_region_param = optarg;
116 			break;
117 		case 0:
118 			/* long option */
119 			break;
120 		default:
121 			return 1;
122 		}
123 	}
124 
125 	if (optind != argc) {
126 		/* Extra arguments we don't understand. */
127 		return 1;
128 	}
129 
130 	rv = !flashrom_mock_success;
131 	captured_verify = captured_verify_int;
132 
133 	if (captured_operation == FLASHROM_READ) {
134 		/* Write the mocked string we read from the ROM. */
135 		rv |= vb2_write_file(MOCK_TMPFILE_NAME, MOCK_ROM_CONTENTS,
136 				     strlen(MOCK_ROM_CONTENTS));
137 	} else if (captured_operation == FLASHROM_WRITE) {
138 		/* Capture the buffer contents we wrote to the ROM. */
139 		rv |= vb2_read_file(MOCK_TMPFILE_NAME, &captured_rom_contents,
140 				    &captured_rom_size);
141 	}
142 
143 	return rv;
144 }
145 
test_read_whole_chip(void)146 static void test_read_whole_chip(void)
147 {
148 	struct firmware_image image = {
149 		.programmer = "someprog",
150 	};
151 
152 	TEST_SUCC(flashrom_read(&image, NULL),
153 		  "Flashrom read succeeds");
154 	TEST_STR_EQ(captured_programmer, "someprog",
155 		    "Using specified programmer");
156 	TEST_EQ(captured_operation, FLASHROM_READ, "Doing a read operation");
157 	TEST_EQ(captured_verify, FLASHROM_VERIFY_UNSPECIFIED,
158 		"Verification not enabled");
159 	TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME,
160 		    "Reading to correct file");
161 	TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region");
162 	TEST_EQ(image.size, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
163 	TEST_SUCC(memcmp(image.data, MOCK_ROM_CONTENTS, image.size),
164 		  "Buffer has correct contents");
165 
166 	free(image.data);
167 }
168 
test_read_region(void)169 static void test_read_region(void)
170 {
171 	struct firmware_image image = {
172 		.programmer = "someprog",
173 	};
174 
175 	TEST_SUCC(flashrom_read(&image, "SOME_REGION"),
176 		  "Flashrom read succeeds");
177 	TEST_STR_EQ(captured_programmer, "someprog",
178 		    "Using specified programmer");
179 	TEST_EQ(captured_operation, FLASHROM_READ, "Doing a read operation");
180 	TEST_EQ(captured_verify, FLASHROM_VERIFY_UNSPECIFIED,
181 		"Verification not enabled");
182 	TEST_PTR_EQ(captured_op_filename, NULL,
183 		    "Not doing a read of the whole ROM");
184 	TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME,
185 		    "Reading to correct file and from correct region");
186 	TEST_EQ(image.size, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
187 	TEST_SUCC(memcmp(image.data, MOCK_ROM_CONTENTS, image.size),
188 		  "Buffer has correct contents");
189 
190 	free(image.data);
191 }
192 
test_read_failure(void)193 static void test_read_failure(void)
194 {
195 	struct firmware_image image = {
196 		.programmer = "someprog",
197 	};
198 
199 	flashrom_mock_success = false;
200 	TEST_NEQ(flashrom_read(&image, "SOME_REGION"),
201 		 VB2_SUCCESS, "Flashrom read fails");
202 	flashrom_mock_success = true;
203 }
204 
test_write_whole_chip(void)205 static void test_write_whole_chip(void)
206 {
207 	uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1];
208 	struct firmware_image image = {
209 		.programmer = "someprog",
210 		.data = buf,
211 		.size = sizeof(buf),
212 	};
213 
214 	memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf));
215 
216 	TEST_SUCC(flashrom_write(&image, NULL),
217 		  "Flashrom write succeeds");
218 	TEST_STR_EQ(captured_programmer, "someprog",
219 		    "Using specified programmer");
220 	TEST_EQ(captured_operation, FLASHROM_WRITE, "Doing a write operation");
221 	TEST_EQ(captured_verify, FLASHROM_VERIFY_FAST,
222 		"Fast verification enabled");
223 	TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME,
224 		    "Writing to correct file");
225 	TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region");
226 	TEST_EQ(captured_rom_size, strlen(MOCK_ROM_CONTENTS),
227 		"Contents correct size");
228 	TEST_SUCC(memcmp(captured_rom_contents, MOCK_ROM_CONTENTS,
229 			 captured_rom_size), "Buffer has correct contents");
230 }
231 
test_write_region(void)232 static void test_write_region(void)
233 {
234 	uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1];
235 	struct firmware_image image = {
236 		.programmer = "someprog",
237 		.data = buf,
238 		.size = sizeof(buf),
239 	};
240 
241 	memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf));
242 
243 	TEST_SUCC(flashrom_write(&image, "SOME_REGION"),
244 		  "Flashrom write succeeds");
245 	TEST_STR_EQ(captured_programmer, "someprog",
246 		    "Using specified programmer");
247 	TEST_EQ(captured_operation, FLASHROM_WRITE, "Doing a write operation");
248 	TEST_EQ(captured_verify, FLASHROM_VERIFY_FAST,
249 		"Fast verification enabled");
250 	TEST_PTR_EQ(captured_op_filename, NULL,
251 		    "Not doing a write of the whole ROM");
252 	TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME,
253 		    "Writing to correct file and from correct region");
254 	TEST_EQ(captured_rom_size, strlen(MOCK_ROM_CONTENTS),
255 		"Contents correct size");
256 	TEST_SUCC(memcmp(captured_rom_contents, MOCK_ROM_CONTENTS,
257 			 captured_rom_size), "Buffer has correct contents");
258 }
259 
test_write_failure(void)260 static void test_write_failure(void)
261 {
262 	uint8_t buf[20] = { 0 };
263 	struct firmware_image image = {
264 		.programmer = "someprog",
265 		.data = buf,
266 		.size = sizeof(buf),
267 	};
268 
269 	flashrom_mock_success = false;
270 	TEST_NEQ(flashrom_write(&image, "SOME_REGION"),
271 		 VB2_SUCCESS, "Flashrom write fails");
272 	flashrom_mock_success = true;
273 }
274 
main(int argc,char * argv[])275 int main(int argc, char *argv[])
276 {
277 	test_read_whole_chip();
278 	test_read_region();
279 	test_read_failure();
280 	test_write_whole_chip();
281 	test_write_region();
282 	test_write_failure();
283 
284 	return gTestSuccess ? 0 : 255;
285 }
286