1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright 2021 Google LLC
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * This file contains tests for operations on flash chip.
16 *
17 * Two flash chip test variants are used:
18 *
19 * 1) Mock chip state backed by `g_chip_state`.
20 * Example of test: erase_chip_test_success.
21 *
22 * 2) Mock chip operations backed by `dummyflasher` emulation.
23 * Dummyflasher controls chip state and emulates read/write/erase.
24 * `g_chip_state` is NOT used for this type of tests.
25 * Example of test: erase_chip_with_dummyflasher_test_success.
26 */
27
28 #include <include/test.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "tests.h"
34 #include "chipdrivers.h"
35 #include "flash.h"
36 #include "io_mock.h"
37 #include "libflashrom.h"
38 #include "programmer.h"
39
40 #define MOCK_CHIP_SIZE (8*MiB)
41 #define MOCK_CHIP_CONTENT 0xCC /* 0x00 is a zeroed heap and 0xFF is an erased chip. */
42
43 static struct {
44 uint8_t buf[MOCK_CHIP_SIZE]; /* buffer of total size of chip, to emulate a chip */
45 } g_chip_state = {
46 .buf = { 0 },
47 };
48
read_chip(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)49 static int read_chip(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
50 {
51 printf("Read chip called with start=0x%x, len=0x%x\n", start, len);
52
53 assert_in_range(start + len, 0, MOCK_CHIP_SIZE);
54
55 memcpy(buf, &g_chip_state.buf[start], len);
56 return 0;
57 }
58
write_chip(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)59 static int write_chip(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
60 {
61 printf("Write chip called with start=0x%x, len=0x%x\n", start, len);
62
63 assert_in_range(start + len, 0, MOCK_CHIP_SIZE);
64
65 memcpy(&g_chip_state.buf[start], buf, len);
66 return 0;
67 }
68
block_erase_chip(struct flashctx * flash,unsigned int blockaddr,unsigned int blocklen)69 static int block_erase_chip(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen)
70 {
71 printf("Block erase called with blockaddr=0x%x, blocklen=0x%x\n", blockaddr, blocklen);
72
73 assert_in_range(blockaddr + blocklen, 0, MOCK_CHIP_SIZE);
74
75 memset(&g_chip_state.buf[blockaddr], 0xff, blocklen);
76 return 0;
77 }
78
setup_chip(struct flashrom_flashctx * flashctx,struct flashrom_layout ** layout,struct flashchip * chip,const char * programmer_param,const struct io_mock * io)79 static void setup_chip(struct flashrom_flashctx *flashctx, struct flashrom_layout **layout,
80 struct flashchip *chip, const char *programmer_param, const struct io_mock *io)
81 {
82 io_mock_register(io);
83
84 flashctx->chip = chip;
85
86 memset(g_chip_state.buf, MOCK_CHIP_CONTENT, sizeof(g_chip_state.buf));
87
88 printf("Creating layout with one included region... ");
89 assert_int_equal(0, flashrom_layout_new(layout));
90 /* One region which covers total size of chip. */
91 assert_int_equal(0, flashrom_layout_add_region(*layout, 0, chip->total_size * KiB - 1, "region"));
92 assert_int_equal(0, flashrom_layout_include_region(*layout, "region"));
93
94 flashrom_layout_set(flashctx, *layout);
95 printf("done\n");
96
97 /*
98 * We need some programmer (any), and dummy is a very good one,
99 * because it doesn't need any mocking. So no extra complexity
100 * from a programmer side, and test can focus on working with the chip.
101 */
102 printf("Dummyflasher initialising with param=\"%s\"... ", programmer_param);
103 assert_int_equal(0, programmer_init(&programmer_dummy, programmer_param));
104 /* Assignment below normally happens while probing, but this test is not probing. */
105 flashctx->mst = ®istered_masters[0];
106 printf("done\n");
107 }
108
teardown(struct flashrom_layout ** layout)109 static void teardown(struct flashrom_layout **layout)
110 {
111 printf("Dummyflasher shutdown... ");
112 assert_int_equal(0, programmer_shutdown());
113 printf("done\n");
114
115 printf("Releasing layout... ");
116 flashrom_layout_release(*layout);
117 printf("done\n");
118
119 io_mock_register(NULL);
120 }
121
122 extern write_func_t *g_test_write_injector;
123 extern read_func_t *g_test_read_injector;
124 extern erasefunc_t *g_test_erase_injector;
125
126 static const struct flashchip chip_8MiB = {
127 .vendor = "aklm",
128 .total_size = MOCK_CHIP_SIZE / KiB,
129 .tested = TEST_OK_PREW,
130 .read = TEST_READ_INJECTOR,
131 .write = TEST_WRITE_INJECTOR,
132 .block_erasers =
133 {{
134 /* All blocks within total size of the chip. */
135 .eraseblocks = { {2 * MiB, 4} },
136 .block_erase = TEST_ERASE_INJECTOR,
137 }},
138 };
139
140 /* Chip expected to be processed with dummyflasher, so using real op functions. */
141 static const struct flashchip chip_no_erase = {
142 .vendor = "aklm&dummyflasher",
143 .total_size = 16 * 1024,
144 .tested = TEST_OK_PREW,
145 .read = SPI_CHIP_READ,
146 .write = SPI_CHIP_WRITE256,
147 .page_size = 256,
148 .feature_bits = FEATURE_NO_ERASE | FEATURE_ERASED_ZERO,
149 .block_erasers =
150 {
151 {
152 .eraseblocks = { {16 * 1024 * 1024, 1} },
153 /* Special erase fn for chips without erase capability. */
154 .block_erase = SPI_BLOCK_ERASE_EMULATION,
155 }
156 },
157 };
158
159 /* Setup the struct for W25Q128.V, all values come from flashchips.c */
160 static const struct flashchip chip_W25Q128_V = {
161 .vendor = "aklm&dummyflasher",
162 .total_size = 16 * 1024,
163 .tested = TEST_OK_PREW,
164 .read = SPI_CHIP_READ,
165 .write = SPI_CHIP_WRITE256,
166 .page_size = 256,
167 .block_erasers =
168 {
169 {
170 .eraseblocks = { {4 * 1024, 4096} },
171 .block_erase = SPI_BLOCK_ERASE_20,
172 }, {
173 .eraseblocks = { {32 * 1024, 512} },
174 .block_erase = SPI_BLOCK_ERASE_52,
175 }, {
176 .eraseblocks = { {64 * 1024, 256} },
177 .block_erase = SPI_BLOCK_ERASE_D8,
178 }, {
179 .eraseblocks = { {16 * 1024 * 1024, 1} },
180 .block_erase = SPI_BLOCK_ERASE_60,
181 }, {
182 .eraseblocks = { {16 * 1024 * 1024, 1} },
183 .block_erase = SPI_BLOCK_ERASE_C7,
184 }
185 },
186 };
187
erase_chip_test_success(void ** state)188 void erase_chip_test_success(void **state)
189 {
190 (void) state; /* unused */
191
192 static struct io_mock_fallback_open_state data = {
193 .noc = 0,
194 .paths = { SUSPEND_ANNOUNCED_FILE, NULL },
195 };
196 const struct io_mock chip_io = {
197 .fallback_open_state = &data,
198 };
199
200 g_test_write_injector = write_chip;
201 g_test_read_injector = read_chip;
202 g_test_erase_injector = block_erase_chip;
203 struct flashrom_flashctx flashctx = { 0 };
204 struct flashrom_layout *layout;
205 struct flashchip mock_chip = chip_8MiB;
206 const char *param = ""; /* Default values for all params. */
207
208 setup_chip(&flashctx, &layout, &mock_chip, param, &chip_io);
209
210 printf("Erase chip operation started.\n");
211 assert_int_equal(0, flashrom_flash_erase(&flashctx));
212 printf("Erase chip operation done.\n");
213
214 teardown(&layout);
215 }
216
erase_chip_with_dummyflasher_test_success(void ** state)217 void erase_chip_with_dummyflasher_test_success(void **state)
218 {
219 (void) state; /* unused */
220
221 static struct io_mock_fallback_open_state data = {
222 .noc = 0,
223 .paths = { NULL },
224 };
225 const struct io_mock chip_io = {
226 .fallback_open_state = &data,
227 };
228
229 struct flashrom_flashctx flashctx = { 0 };
230 struct flashrom_layout *layout;
231 struct flashchip mock_chip = chip_W25Q128_V;
232 /*
233 * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
234 * Nothing to mock, dummy is taking care of this already.
235 */
236 const char *param_dup = "bus=spi,emulate=W25Q128FV";
237
238 setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
239
240 printf("Erase chip operation started.\n");
241 assert_int_equal(0, flashrom_flash_erase(&flashctx));
242 printf("Erase chip operation done.\n");
243
244 teardown(&layout);
245 }
246
read_chip_test_success(void ** state)247 void read_chip_test_success(void **state)
248 {
249 (void) state; /* unused */
250
251 static struct io_mock_fallback_open_state data = {
252 .noc = 0,
253 .paths = { NULL },
254 };
255 const struct io_mock chip_io = {
256 .fallback_open_state = &data,
257 };
258
259 g_test_write_injector = write_chip;
260 g_test_read_injector = read_chip;
261 g_test_erase_injector = block_erase_chip;
262 struct flashrom_flashctx flashctx = { 0 };
263 struct flashrom_layout *layout;
264 struct flashchip mock_chip = chip_8MiB;
265 const char *param = ""; /* Default values for all params. */
266
267 setup_chip(&flashctx, &layout, &mock_chip, param, &chip_io);
268
269 const char *const filename = "read_chip.test";
270 unsigned long size = mock_chip.total_size * 1024;
271 unsigned char *buf = calloc(size, sizeof(unsigned char));
272 assert_non_null(buf);
273
274 printf("Read chip operation started.\n");
275 assert_int_equal(0, flashrom_image_read(&flashctx, buf, size));
276 assert_int_equal(0, write_buf_to_file(buf, size, filename));
277 printf("Read chip operation done.\n");
278
279 teardown(&layout);
280
281 free(buf);
282 }
283
read_chip_with_dummyflasher_test_success(void ** state)284 void read_chip_with_dummyflasher_test_success(void **state)
285 {
286 (void) state; /* unused */
287
288 static struct io_mock_fallback_open_state data = {
289 .noc = 0,
290 .paths = { NULL },
291 };
292 const struct io_mock chip_io = {
293 .fallback_open_state = &data,
294 };
295
296 struct flashrom_flashctx flashctx = { 0 };
297 struct flashrom_layout *layout;
298 struct flashchip mock_chip = chip_W25Q128_V;
299 /*
300 * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
301 * Nothing to mock, dummy is taking care of this already.
302 */
303 const char *param_dup = "bus=spi,emulate=W25Q128FV";
304
305 setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
306
307 const char *const filename = "read_chip.test";
308 unsigned long size = mock_chip.total_size * 1024;
309 unsigned char *buf = calloc(size, sizeof(unsigned char));
310 assert_non_null(buf);
311
312 printf("Read chip operation started.\n");
313 assert_int_equal(0, flashrom_image_read(&flashctx, buf, size));
314 assert_int_equal(0, write_buf_to_file(buf, size, filename));
315 printf("Read chip operation done.\n");
316
317 teardown(&layout);
318
319 free(buf);
320 }
321
write_chip_test_success(void ** state)322 void write_chip_test_success(void **state)
323 {
324 (void) state; /* unused */
325
326 static struct io_mock_fallback_open_state data = {
327 .noc = 0,
328 .paths = { NULL },
329 };
330 const struct io_mock chip_io = {
331 .fallback_open_state = &data,
332 };
333
334 g_test_write_injector = write_chip;
335 g_test_read_injector = read_chip;
336 g_test_erase_injector = block_erase_chip;
337 struct flashrom_flashctx flashctx = { 0 };
338 struct flashrom_layout *layout;
339 struct flashchip mock_chip = chip_8MiB;
340 const char *param = ""; /* Default values for all params. */
341
342 setup_chip(&flashctx, &layout, &mock_chip, param, &chip_io);
343
344 /*
345 * Providing filename "-" means content is taken from standard input.
346 * This doesn't change much because all file operations are mocked.
347 * However filename "-" makes a difference for
348 * flashrom.c#read_buf_from_file and allows to avoid mocking
349 * image_stat.st_size.
350 *
351 * Now this does mean test covers successful path only, but this test
352 * is designed to cover only successful write operation anyway.
353 *
354 * To cover error path of image_stat.st_size != flash size, filename
355 * needs to be provided and image_stat.st_size needs to be mocked.
356 */
357 const char *const filename = "-";
358 unsigned long size = mock_chip.total_size * 1024;
359 uint8_t *const newcontents = malloc(size);
360 assert_non_null(newcontents);
361
362 printf("Write chip operation started.\n");
363 assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
364 assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
365 printf("Write chip operation done.\n");
366
367 teardown(&layout);
368
369 free(newcontents);
370 }
371
write_chip_with_dummyflasher_test_success(void ** state)372 void write_chip_with_dummyflasher_test_success(void **state)
373 {
374 (void) state; /* unused */
375
376 static struct io_mock_fallback_open_state data = {
377 .noc = 0,
378 .paths = { NULL },
379 };
380 const struct io_mock chip_io = {
381 .fallback_open_state = &data,
382 };
383
384 struct flashrom_flashctx flashctx = { 0 };
385 struct flashrom_layout *layout;
386 struct flashchip mock_chip = chip_W25Q128_V;
387 /*
388 * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
389 * Nothing to mock, dummy is taking care of this already.
390 */
391 const char *param_dup = "bus=spi,emulate=W25Q128FV";
392
393 setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
394
395 /* See comment in write_chip_test_success */
396 const char *const filename = "-";
397 unsigned long size = mock_chip.total_size * 1024;
398 uint8_t *const newcontents = malloc(size);
399 assert_non_null(newcontents);
400
401 printf("Write chip operation started.\n");
402 assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
403 assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
404 printf("Write chip operation done.\n");
405
406 teardown(&layout);
407
408 free(newcontents);
409 }
410
write_chip_feature_no_erase(void ** state)411 void write_chip_feature_no_erase(void **state)
412 {
413 (void) state; /* unused */
414
415 static struct io_mock_fallback_open_state data = {
416 .noc = 0,
417 .paths = { NULL },
418 };
419 const struct io_mock chip_io = {
420 .fallback_open_state = &data,
421 };
422
423 struct flashrom_flashctx flashctx = { 0 };
424 struct flashrom_layout *layout;
425
426 /*
427 * Tricking the dummyflasher by asking to emulate W25Q128FV but giving to it
428 * mock chip with FEATURE_NO_ERASE.
429 * As long as chip size is the same, this is fine.
430 */
431 struct flashchip mock_chip = chip_no_erase;
432 const char *param_dup = "bus=spi,emulate=W25Q128FV";
433
434 setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
435
436 /* See comment in write_chip_test_success */
437 const char *const filename = "-";
438 unsigned long size = mock_chip.total_size * 1024;
439 uint8_t *const newcontents = malloc(size);
440 assert_non_null(newcontents);
441
442 printf("Write chip operation started.\n");
443 assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
444 assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
445 assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, size));
446 printf("Write chip operation done.\n");
447
448 teardown(&layout);
449
450 free(newcontents);
451 }
452
write_nonaligned_region_with_dummyflasher_test_success(void ** state)453 void write_nonaligned_region_with_dummyflasher_test_success(void **state)
454 {
455 (void) state; /* unused */
456
457 static struct io_mock_fallback_open_state data = {
458 .noc = 0,
459 .paths = { NULL },
460 };
461 const struct io_mock chip_io = {
462 .fallback_open_state = &data,
463 };
464
465 struct flashrom_flashctx flashctx = { 0 };
466 struct flashrom_layout *layout;
467 struct flashchip mock_chip = chip_W25Q128_V;
468 const uint32_t mock_chip_size = mock_chip.total_size * KiB;
469 /*
470 * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
471 * Nothing to mock, dummy is taking care of this already.
472 */
473 const char *param_dup = "bus=spi,emulate=W25Q128FV";
474
475 /* FIXME: MOCK_CHIP_CONTENT is buggy within setup_chip, it should also
476 * not be either 0x00 or 0xFF as those are specific values related to
477 * either a erased chip or zero'ed heap thus ambigous.
478 */
479 #define MOCK_CHIP_SUBREGION_CONTENTS 0xCC
480 /**
481 * Step 0 - Prepare newcontents as contiguous sample data bytes as follows:
482 * {MOCK_CHIP_SUBREGION_CONTENTS, [..]}.
483 */
484 uint8_t *newcontents = calloc(1, mock_chip_size);
485 assert_non_null(newcontents);
486 memset(newcontents, MOCK_CHIP_SUBREGION_CONTENTS, mock_chip_size);
487
488 setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
489 /* Expect to verify only the non-aligned write operation within the region. */
490 flashrom_flag_set(&flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true);
491 flashrom_flag_set(&flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, false);
492
493 /**
494 * Prepare mock chip content and release setup_chip() layout for our
495 * custom ones.
496 */
497 assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, mock_chip_size, NULL));
498 flashrom_layout_release(layout);
499
500 /**
501 * Create region smaller than erase granularity of chip.
502 */
503 printf("Creating custom region layout... ");
504 assert_int_equal(0, flashrom_layout_new(&layout));
505 printf("Adding and including region0... ");
506 assert_int_equal(0, flashrom_layout_add_region(layout, 0, (1 * KiB), "region0"));
507 assert_int_equal(0, flashrom_layout_include_region(layout, "region0"));
508 flashrom_layout_set(&flashctx, layout);
509 printf("Subregion layout configuration done.\n");
510
511 /**
512 * Step 1 - Modify newcontents as non-contiguous sample data bytes as follows:
513 * 0xAA 0xAA {MOCK_CHIP_SUBREGION_CONTENTS}, [..]}.
514 */
515 printf("Subregion chip write op..\n");
516 memset(newcontents, 0xAA, 2);
517 assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, mock_chip_size, NULL));
518 printf("Subregion chip write op done.\n");
519
520 /**
521 * FIXME: A 'NULL' layout should indicate a default layout however this
522 * causes a crash for a unknown reason. For now prepare a new default
523 * layout of the entire chip. flashrom_layout_set(&flashctx, NULL); // use default layout.
524 */
525 flashrom_layout_release(layout);
526 assert_int_equal(0, flashrom_layout_new(&layout));
527 assert_int_equal(0, flashrom_layout_add_region(layout, 0, mock_chip_size - 1, "entire"));
528 assert_int_equal(0, flashrom_layout_include_region(layout, "entire"));
529 flashrom_layout_set(&flashctx, layout);
530
531 /**
532 * Expect a verification pass that the previous content within the region, however
533 * outside the region write length, is untouched.
534 */
535 printf("Entire chip verify op..\n");
536 assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, mock_chip_size));
537 printf("Entire chip verify op done.\n");
538
539 teardown(&layout);
540 free(newcontents);
541 }
542
verify_chip_fread(void * state,void * buf,size_t size,size_t len,FILE * fp)543 static size_t verify_chip_fread(void *state, void *buf, size_t size, size_t len, FILE *fp)
544 {
545 /*
546 * Verify operation compares contents of the file vs contents on the chip.
547 * To emulate successful verification we emulate file contents to be the
548 * same as what is on the chip.
549 */
550 memset(buf, MOCK_CHIP_CONTENT, len);
551 return len;
552 }
553
verify_chip_test_success(void ** state)554 void verify_chip_test_success(void **state)
555 {
556 (void) state; /* unused */
557
558 static struct io_mock_fallback_open_state data = {
559 .noc = 0,
560 .paths = { NULL },
561 };
562 const struct io_mock verify_chip_io = {
563 .iom_fread = verify_chip_fread,
564 .fallback_open_state = &data,
565 };
566
567 g_test_write_injector = write_chip;
568 g_test_read_injector = read_chip;
569 g_test_erase_injector = block_erase_chip;
570 struct flashrom_flashctx flashctx = { 0 };
571 struct flashrom_layout *layout;
572 struct flashchip mock_chip = chip_8MiB;
573 const char *param = ""; /* Default values for all params. */
574
575 setup_chip(&flashctx, &layout, &mock_chip, param, &verify_chip_io);
576
577 /* See comment in write_chip_test_success */
578 const char *const filename = "-";
579 unsigned long size = mock_chip.total_size * 1024;
580 uint8_t *const newcontents = malloc(size);
581 assert_non_null(newcontents);
582
583 printf("Verify chip operation started.\n");
584 assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
585 assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, size));
586 printf("Verify chip operation done.\n");
587
588 teardown(&layout);
589
590 free(newcontents);
591 }
592
verify_chip_with_dummyflasher_test_success(void ** state)593 void verify_chip_with_dummyflasher_test_success(void **state)
594 {
595 (void) state; /* unused */
596
597 static struct io_mock_fallback_open_state data = {
598 .noc = 0,
599 .paths = { NULL },
600 };
601 const struct io_mock verify_chip_io = {
602 .iom_fread = verify_chip_fread,
603 .fallback_open_state = &data,
604 };
605
606 struct flashrom_flashctx flashctx = { 0 };
607 struct flashrom_layout *layout;
608 struct flashchip mock_chip = chip_W25Q128_V;
609 /*
610 * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
611 * Nothing to mock, dummy is taking care of this already.
612 */
613 const char *param_dup = "bus=spi,emulate=W25Q128FV";
614
615 setup_chip(&flashctx, &layout, &mock_chip, param_dup, &verify_chip_io);
616
617 /* See comment in write_chip_test_success */
618 const char *const filename = "-";
619 unsigned long size = mock_chip.total_size * 1024;
620 uint8_t *const newcontents = malloc(size);
621 assert_non_null(newcontents);
622
623 /*
624 * Dummyflasher controls chip state and fully emulates reads and writes,
625 * so to set up initial chip state we need to write on chip. Write
626 * operation takes content from file and writes on chip. File content is
627 * emulated in verify_chip_fread mock.
628 */
629
630 printf("Write chip operation started.\n");
631 assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
632 assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
633 printf("Write chip operation done.\n");
634
635 printf("Verify chip operation started.\n");
636 assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, size));
637 printf("Verify chip operation done.\n");
638
639 teardown(&layout);
640
641 free(newcontents);
642 }
643