trivial patch for abuild: allow powerpc-elf-gcc, too.
[coreboot.git] / util / flashrom / flashrom.c
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2000 Silicon Integrated System Corporation
5  * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
6  * Copyright (C) 2005-2008 coresystems GmbH 
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21  */
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <getopt.h>
32 #include <pci/pci.h>
33 /* for iopl */
34 #if defined (__sun) && (defined(__i386) || defined(__amd64))
35 #include <strings.h>
36 #include <sys/sysi86.h>
37 #include <sys/psw.h>
38 #include <asm/sunddi.h>
39 #endif
40 #include "flash.h"
41
42 char *chip_to_probe = NULL;
43 struct pci_access *pacc;        /* For board and chipset_enable */
44 int exclude_start_page, exclude_end_page;
45 int verbose = 0;
46
47 struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
48 {
49         struct pci_dev *temp;
50         struct pci_filter filter;
51
52         pci_filter_init(NULL, &filter);
53         filter.vendor = vendor;
54         filter.device = device;
55
56         for (temp = pacc->devices; temp; temp = temp->next)
57                 if (pci_filter_match(&filter, temp))
58                         return temp;
59
60         return NULL;
61 }
62
63 struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
64                               uint16_t card_vendor, uint16_t card_device)
65 {
66         struct pci_dev *temp;
67         struct pci_filter filter;
68
69         pci_filter_init(NULL, &filter);
70         filter.vendor = vendor;
71         filter.device = device;
72
73         for (temp = pacc->devices; temp; temp = temp->next)
74                 if (pci_filter_match(&filter, temp)) {
75                         if ((card_vendor ==
76                              pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
77                             && (card_device ==
78                                 pci_read_word(temp, PCI_SUBSYSTEM_ID)))
79                                 return temp;
80                 }
81
82         return NULL;
83 }
84
85 void map_flash_registers(struct flashchip *flash)
86 {
87         size_t size = flash->total_size * 1024;
88         flash->virtual_registers = physmap("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
89 }
90
91 struct flashchip *probe_flash(struct flashchip *first_flash, int force)
92 {
93         volatile uint8_t *bios;
94         struct flashchip *flash;
95         unsigned long base = 0, size;
96
97         for (flash = first_flash; flash && flash->name; flash++) {
98                 if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
99                         continue;
100                 printf_debug("Probing for %s %s, %d KB: ",
101                              flash->vendor, flash->name, flash->total_size);
102                 if (!flash->probe && !force) {
103                         printf_debug("failed! flashrom has no probe function for this flash chip.\n");
104                         continue;
105                 }
106
107                 size = flash->total_size * 1024;
108
109                 /* If getpagesize() > size -> 
110                  * "Can't mmap memory using /dev/mem: Invalid argument"
111                  * This should never happen as we don't support any flash chips
112                  * smaller than 4k or 8k (yet).
113                  */
114
115                 if (getpagesize() > size) {
116                         /*
117                          * if a flash size of 0 is mapped, we map a single page
118                          * so we can probe in that area whether we know the
119                          * vendor at least.
120                          */
121                         size = getpagesize();
122                 }
123
124                 base = flashbase && flashchips == first_flash ? flashbase : (0xffffffff - size + 1);
125                 flash->virtual_memory = bios = physmap("flash chip", base, size);
126
127                 if (force)
128                         break;
129
130                 if (flash->probe(flash) != 1)
131                         goto notfound;
132
133                 if (first_flash == flashchips
134                     || flash->model_id != GENERIC_DEVICE_ID)
135                         break;
136
137 notfound:
138                 physunmap((void *)bios, size);
139         }
140
141         if (!flash || !flash->name)
142                 return NULL;
143
144         printf("Found chip \"%s %s\" (%d KB) at physical address 0x%lx.\n",
145                flash->vendor, flash->name, flash->total_size, base);
146         flashbase = base;
147         return flash;
148 }
149
150 int verify_flash(struct flashchip *flash, uint8_t *buf)
151 {
152         int idx;
153         int total_size = flash->total_size * 1024;
154         uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
155         if (flash->read == NULL)
156                 memcpy(buf2, (const char *)flash->virtual_memory, total_size);
157         else
158                 flash->read(flash, buf2);
159
160         printf("Verifying flash... ");
161
162         if (verbose)
163                 printf("address: 0x00000000\b\b\b\b\b\b\b\b\b\b");
164
165         for (idx = 0; idx < total_size; idx++) {
166                 if (verbose && ((idx & 0xfff) == 0xfff))
167                         printf("0x%08x", idx);
168
169                 if (*(buf2 + idx) != *(buf + idx)) {
170                         if (verbose)
171                                 printf("0x%08x FAILED!", idx);
172                         else
173                                 printf("FAILED at 0x%08x!", idx);
174                         printf("  Expected=0x%02x, Read=0x%02x\n",
175                                *(buf + idx), *(buf2 + idx));
176                         return 1;
177                 }
178
179                 if (verbose && ((idx & 0xfff) == 0xfff))
180                         printf("\b\b\b\b\b\b\b\b\b\b");
181         }
182         if (verbose)
183                 printf("\b\b\b\b\b\b\b\b\b\b ");
184
185         printf("VERIFIED.          \n");
186
187         return 0;
188 }
189
190 int read_flash(struct flashchip *flash, char *filename, unsigned int exclude_start_position, unsigned int exclude_end_position)
191 {
192         unsigned long numbytes;
193         FILE *image;
194         unsigned long size = flash->total_size * 1024;
195         unsigned char *buf = calloc(size, sizeof(char));
196         if ((image = fopen(filename, "w")) == NULL) {
197                 perror(filename);
198                 exit(1);
199         }
200         printf("Reading flash... ");
201         if (flash->read == NULL)
202                 memcpy(buf, (const char *)flash->virtual_memory, size);
203         else
204                 flash->read(flash, buf);
205
206         if (exclude_end_position - exclude_start_position > 0)
207                 memset(buf + exclude_start_position, 0,
208                        exclude_end_position - exclude_start_position);
209
210         numbytes = fwrite(buf, 1, size, image);
211         fclose(image);
212         printf("%s.\n", numbytes == size ? "done" : "FAILED");
213         if (numbytes != size)
214                 return 1;
215         return 0;
216 }
217
218 int erase_flash(struct flashchip *flash)
219 {
220         uint32_t erasedbytes;
221         unsigned long size = flash->total_size * 1024;
222         unsigned char *buf = calloc(size, sizeof(char));
223         printf("Erasing flash chip... ");
224         if (NULL == flash->erase) {
225                 printf("FAILED!\n");
226                 fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
227                 return 1;
228         }
229         flash->erase(flash);
230         if (NULL == flash->read)
231                 memcpy(buf, (const char *)flash->virtual_memory, size);
232         else
233                 flash->read(flash, buf);
234         for (erasedbytes = 0; erasedbytes < size; erasedbytes++)
235                 if (0xff != buf[erasedbytes]) {
236                         printf("FAILED!\n");
237                         fprintf(stderr, "ERROR at 0x%08x: Expected=0xff, Read=0x%02x\n",
238                                 erasedbytes, buf[erasedbytes]);
239                         return 1;
240                 }
241         printf("SUCCESS.\n");
242         return 0;
243 }
244
245 #define MAX(a, b) ((a) > (b) ? (a) : (b))
246 #define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)
247
248 void print_supported_chips(void)
249 {
250         int okcol = 0, pos = 0;
251         struct flashchip *f;
252
253         for (f = flashchips; f->name != NULL; f++) {
254                 if (GENERIC_DEVICE_ID == f->model_id)
255                         continue;
256                 okcol = MAX(okcol, strlen(f->vendor) + 1 + strlen(f->name));
257         }
258         okcol = (okcol + 7) & ~7;
259
260         POS_PRINT("Supported flash chips:");
261         while (pos < okcol) {
262                 printf("\t");
263                 pos += 8 - (pos % 8);
264         }
265         printf("Tested OK operations:\tKnown BAD operations:\n\n");
266
267         for (f = flashchips; f->name != NULL; f++) {
268                 printf("%s %s", f->vendor, f->name);
269                 pos = strlen(f->vendor) + 1 + strlen(f->name);
270                 while (pos < okcol) {
271                         printf("\t");
272                         pos += 8 - (pos % 8);
273                 }
274                 if ((f->tested & TEST_OK_MASK)) {
275                         if ((f->tested & TEST_OK_PROBE))
276                                 POS_PRINT("PROBE ");
277                         if ((f->tested & TEST_OK_READ))
278                                 POS_PRINT("READ ");
279                         if ((f->tested & TEST_OK_ERASE))
280                                 POS_PRINT("ERASE ");
281                         if ((f->tested & TEST_OK_WRITE))
282                                 POS_PRINT("WRITE");
283                 }
284                 while (pos < okcol + 24) {
285                         printf("\t");
286                         pos += 8 - (pos % 8);
287                 }
288                 if ((f->tested & TEST_BAD_MASK)) {
289                         if ((f->tested & TEST_BAD_PROBE))
290                                 printf("PROBE ");
291                         if ((f->tested & TEST_BAD_READ))
292                                 printf("READ ");
293                         if ((f->tested & TEST_BAD_ERASE))
294                                 printf("ERASE ");
295                         if ((f->tested & TEST_BAD_WRITE))
296                                 printf("WRITE");
297                 }
298                 printf("\n");
299         }
300 }
301
302 void usage(const char *name)
303 {
304         printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n",
305                name);
306         printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
307         printf
308             ("   -r | --read:                      read flash and save into file\n"
309              "   -w | --write:                     write file into flash\n"
310              "   -v | --verify:                    verify flash against file\n"
311              "   -E | --erase:                     erase flash device\n"
312              "   -V | --verbose:                   more verbose output\n"
313              "   -c | --chip <chipname>:           probe only for specified flash chip\n"
314              "   -s | --estart <addr>:             exclude start position\n"
315              "   -e | --eend <addr>:               exclude end postion\n"
316              "   -m | --mainboard <[vendor:]part>: override mainboard settings\n"
317              "   -f | --force:                     force write without checking image\n"
318              "   -l | --layout <file.layout>:      read rom layout from file\n"
319              "   -i | --image <name>:              only flash image name from flash layout\n"
320              "   -L | --list-supported:            print supported devices\n"
321              "   -h | --help:                      print this help text\n"
322              "   -R | --version:                   print the version (release)\n"
323              "\n" " If no file is specified, then all that happens"
324              " is that flash info is dumped.\n\n");
325         exit(1);
326 }
327
328 void print_version(void)
329 {
330         printf("flashrom r%s\n", FLASHROM_VERSION);
331 }
332
333 int main(int argc, char *argv[])
334 {
335         uint8_t *buf;
336         unsigned long size, numbytes;
337         FILE *image;
338         /* Probe for up to three flash chips. */
339         struct flashchip *flash, *flashes[3];
340         int opt;
341         int option_index = 0;
342         int force = 0;
343         int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
344         int ret = 0, i;
345 #ifdef __FreeBSD__
346         int io_fd;
347 #endif
348
349         static struct option long_options[] = {
350                 {"read", 0, 0, 'r'},
351                 {"write", 0, 0, 'w'},
352                 {"erase", 0, 0, 'E'},
353                 {"verify", 0, 0, 'v'},
354                 {"chip", 1, 0, 'c'},
355                 {"estart", 1, 0, 's'},
356                 {"eend", 1, 0, 'e'},
357                 {"mainboard", 1, 0, 'm'},
358                 {"verbose", 0, 0, 'V'},
359                 {"force", 0, 0, 'f'},
360                 {"layout", 1, 0, 'l'},
361                 {"image", 1, 0, 'i'},
362                 {"list-supported", 0, 0, 'L'},
363                 {"help", 0, 0, 'h'},
364                 {"version", 0, 0, 'R'},
365                 {0, 0, 0, 0}
366         };
367
368         char *filename = NULL;
369
370         unsigned int exclude_start_position = 0, exclude_end_position = 0;      // [x,y)
371         char *tempstr = NULL, *tempstr2 = NULL;
372
373         if (argc > 1) {
374                 /* Yes, print them. */
375                 int i;
376                 printf_debug("The arguments are:\n");
377                 for (i = 1; i < argc; ++i)
378                         printf_debug("%s\n", argv[i]);
379         }
380
381         setbuf(stdout, NULL);
382         while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:Lh",
383                                   long_options, &option_index)) != EOF) {
384                 switch (opt) {
385                 case 'r':
386                         read_it = 1;
387                         break;
388                 case 'w':
389                         write_it = 1;
390                         break;
391                 case 'v':
392                         verify_it = 1;
393                         break;
394                 case 'c':
395                         chip_to_probe = strdup(optarg);
396                         break;
397                 case 'V':
398                         verbose = 1;
399                         break;
400                 case 'E':
401                         erase_it = 1;
402                         break;
403                 case 's':
404                         tempstr = strdup(optarg);
405                         sscanf(tempstr, "%x", &exclude_start_position);
406                         break;
407                 case 'e':
408                         tempstr = strdup(optarg);
409                         sscanf(tempstr, "%x", &exclude_end_position);
410                         break;
411                 case 'm':
412                         tempstr = strdup(optarg);
413                         strtok(tempstr, ":");
414                         tempstr2 = strtok(NULL, ":");
415                         if (tempstr2) {
416                                 lb_vendor = tempstr;
417                                 lb_part = tempstr2;
418                         } else {
419                                 lb_vendor = NULL;
420                                 lb_part = tempstr;
421                         }
422                         break;
423                 case 'f':
424                         force = 1;
425                         break;
426                 case 'l':
427                         tempstr = strdup(optarg);
428                         if (read_romlayout(tempstr))
429                                 exit(1);
430                         break;
431                 case 'i':
432                         tempstr = strdup(optarg);
433                         find_romentry(tempstr);
434                         break;
435                 case 'L':
436                         print_supported_chips();
437                         print_supported_chipsets();
438                         print_supported_boards();
439                         exit(0);
440                         break;
441                 case 'R':
442                         print_version();
443                         exit(0);
444                         break;
445                 case 'h':
446                 default:
447                         usage(argv[0]);
448                         break;
449                 }
450         }
451
452         if (read_it && write_it) {
453                 printf("Error: -r and -w are mutually exclusive.\n");
454                 usage(argv[0]);
455         }
456
457         if (optind < argc)
458                 filename = argv[optind++];
459
460         /* First get full io access */
461 #if defined (__sun) && (defined(__i386) || defined(__amd64))
462         if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
463 #elif defined(__FreeBSD__)
464         if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
465 #else
466         if (iopl(3) != 0) {
467 #endif
468                 fprintf(stderr, "ERROR: Could not get IO privileges (%s).\nYou need to be root.\n", strerror(errno));
469                 exit(1);
470         }
471
472         /* Initialize PCI access for flash enables */
473         pacc = pci_alloc();     /* Get the pci_access structure */
474         /* Set all options you want -- here we stick with the defaults */
475         pci_init(pacc);         /* Initialize the PCI library */
476         pci_scan_bus(pacc);     /* We want to get the list of devices */
477
478         myusec_calibrate_delay();
479
480         /* We look at the lbtable first to see if we need a
481          * mainboard specific flash enable sequence.
482          */
483         coreboot_init();
484
485         /* try to enable it. Failure IS an option, since not all motherboards
486          * really need this to be done, etc., etc.
487          */
488         ret = chipset_flash_enable();
489         if (ret == -2) {
490                 printf("WARNING: No chipset found. Flash detection "
491                        "will most likely fail.\n");
492         }
493
494         board_flash_enable(lb_vendor, lb_part);
495
496         for (i = 0; i < ARRAY_SIZE(flashes); i++) {
497                 flashes[i] =
498                     probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
499                 if (!flashes[i])
500                         for (i++; i < ARRAY_SIZE(flashes); i++)
501                                 flashes[i] = NULL;
502         }
503
504         if (flashes[1]) {
505                 printf("Multiple flash chips were detected:");
506                 for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++)
507                         printf(" %s", flashes[i]->name);
508                 printf("\nPlease specify which chip to use with the -c <chipname> option.\n");
509                 exit(1);
510         } else if (!flashes[0]) {
511                 printf("No EEPROM/flash device found.\n");
512                 if (!force || !chip_to_probe) {
513                         printf("If you know which flash chip you have, and if this version of flashrom\n");
514                         printf("supports a similar flash chip, you can try to force read your chip. Run:\n");
515                         printf("flashrom -f -r -c similar_supported_flash_chip filename\n");
516                         printf("\n");
517                         printf("Note: flashrom can never write when the flash chip isn't found automatically.\n");
518                 }
519                 if (force && read_it && chip_to_probe) {
520                         printf("Force read (-f -r -c) requested, forcing chip probe success:\n");
521                         flashes[0] = probe_flash(flashchips, 1);
522                         if (!flashes[0]) {
523                                 printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe);
524                                 printf("Run flashrom -L to view the hardware supported in this flashrom version.\n");
525                                 exit(1);
526                         }
527                         if (!filename) {
528                                 printf("Error: No filename specified.\n");
529                                 exit(1);
530                         }
531                         size = flashes[0]->total_size * 1024;
532                         buf = (uint8_t *) calloc(size, sizeof(char));
533
534                         if ((image = fopen(filename, "w")) == NULL) {
535                                 perror(filename);
536                                 exit(1);
537                         }
538                         printf("Force reading flash... ");
539                         if (!flashes[0]->read)
540                                 memcpy(buf, (const char *)flashes[0]->virtual_memory, size);
541                         else
542                                 flashes[0]->read(flashes[0], buf);
543
544                         if (exclude_end_position - exclude_start_position > 0)
545                                 memset(buf + exclude_start_position, 0,
546                                        exclude_end_position -
547                                        exclude_start_position);
548
549                         numbytes = fwrite(buf, 1, size, image);
550                         fclose(image);
551                         printf("%s.\n", numbytes == size ? "done" : "FAILED");
552                         free(buf);
553                         return numbytes != size;
554                 }
555                 // FIXME: flash writes stay enabled!
556                 exit(1);
557         }
558
559         flash = flashes[0];
560
561         if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) {
562                 printf("===\n");
563                 if (flash->tested & TEST_BAD_MASK) {
564                         printf("This flash part has status NOT WORKING for operations:");
565                         if (flash->tested & TEST_BAD_PROBE)
566                                 printf(" PROBE");
567                         if (flash->tested & TEST_BAD_READ)
568                                 printf(" READ");
569                         if (flash->tested & TEST_BAD_ERASE)
570                                 printf(" ERASE");
571                         if (flash->tested & TEST_BAD_WRITE)
572                                 printf(" WRITE");
573                         printf("\n");
574                 }
575                 if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) ||
576                     (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) ||
577                     (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) ||
578                     (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) {
579                         printf("This flash part has status UNTESTED for operations:");
580                         if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
581                                 printf(" PROBE");
582                         if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
583                                 printf(" READ");
584                         if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
585                                 printf(" ERASE");
586                         if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
587                                 printf(" WRITE");
588                         printf("\n");
589                 }
590                 printf("Please email a report to flashrom@coreboot.org if any of the above operations\n");
591                 printf("work correctly for you with this flash part. Please include the full output\n");
592                 printf("from the program, including chipset found. Thank you for your help!\n");
593                 printf("===\n");
594         }
595
596         if (!(read_it | write_it | verify_it | erase_it)) {
597                 printf("No operations were specified.\n");
598                 // FIXME: flash writes stay enabled!
599                 exit(1);
600         }
601
602         if (!filename && !erase_it) {
603                 printf("Error: No filename specified.\n");
604                 // FIXME: flash writes stay enabled!
605                 exit(1);
606         }
607
608         size = flash->total_size * 1024;
609         buf = (uint8_t *) calloc(size, sizeof(char));
610
611         if (erase_it) {
612                 if (erase_flash(flash))
613                         return 1;
614         } else if (read_it) {
615                 if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
616                         return 1;
617         } else {
618                 struct stat image_stat;
619
620                 if ((image = fopen(filename, "r")) == NULL) {
621                         perror(filename);
622                         exit(1);
623                 }
624                 if (fstat(fileno(image), &image_stat) != 0) {
625                         perror(filename);
626                         exit(1);
627                 }
628                 if (image_stat.st_size != flash->total_size * 1024) {
629                         fprintf(stderr, "Error: Image size doesn't match\n");
630                         exit(1);
631                 }
632
633                 numbytes = fread(buf, 1, size, image);
634                 show_id(buf, size, force);
635                 fclose(image);
636                 if (numbytes != size) {
637                         fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
638                         return 1;
639                 }
640         }
641
642         /* exclude range stuff. Nice idea, but at the moment it is only
643          * supported in hardware by the pm49fl004 chips. 
644          * Instead of implementing this for all chips I suggest advancing
645          * it to the rom layout feature below and drop exclude range
646          * completely once all flash chips can do rom layouts. stepan
647          */
648
649         // ////////////////////////////////////////////////////////////
650         if (exclude_end_position - exclude_start_position > 0)
651                 memcpy(buf + exclude_start_position,
652                        (const char *)flash->virtual_memory +
653                        exclude_start_position,
654                        exclude_end_position - exclude_start_position);
655
656         exclude_start_page = exclude_start_position / flash->page_size;
657         if ((exclude_start_position % flash->page_size) != 0) {
658                 exclude_start_page++;
659         }
660         exclude_end_page = exclude_end_position / flash->page_size;
661         // ////////////////////////////////////////////////////////////
662
663         // This should be moved into each flash part's code to do it 
664         // cleanly. This does the job.
665         handle_romentries(buf, (uint8_t *) flash->virtual_memory);
666
667         // ////////////////////////////////////////////////////////////
668
669         if (write_it) {
670                 if (!flash->write) {
671                         fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n");
672                         return 1;
673                 }
674                 ret |= flash->write(flash, buf);
675         }
676
677         if (verify_it)
678                 ret |= verify_flash(flash, buf);
679
680 #ifdef __FreeBSD__
681         close(io_fd);
682 #endif
683         return ret;
684 }