factor out register mapping code (trivial)
[coreboot.git] / util / flashrom / flashrom.c
1 /*
2  * flashrom.c: Flash programming utility
3  *
4  * Copyright 2000 Silicon Integrated System Corporation
5  * Copyright 2004 Tyan Corp
6  *      yhlu yhlu@tyan.com add exclude start and end option
7  * Copyright 2005-2007 coresystems GmbH 
8  *      Stefan Reinauer <stepan@coresystems.de> added rom layout
9  *      support, and checking for suitable rom image, various fixes
10  *      support for flashing the Technologic Systems 5300.
11  * 
12  *      This program is free software; you can redistribute it and/or modify
13  *      it under the terms of the GNU General Public License as published by
14  *      the Free Software Foundation; either version 2 of the License, or
15  *      (at your option) any later version.
16  *
17  *      This program is distributed in the hope that it will be useful,
18  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *      GNU General Public License for more details.
21  *
22  *      You should have received a copy of the GNU General Public License
23  *      along with this program; if not, write to the Free Software
24  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  */
27
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <sys/mman.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <getopt.h>
38 #include <pci/pci.h>
39
40 /* for iopl */
41 #if defined (__sun) && (defined(__i386) || defined(__amd64))
42 #include <strings.h>
43 #include <sys/sysi86.h>
44 #include <sys/psw.h>
45 #include <asm/sunddi.h>
46 #endif
47
48 #include "flash.h"
49 #include "lbtable.h"
50 #include "layout.h"
51 #include "debug.h"
52
53 char *chip_to_probe = NULL;
54 struct pci_access *pacc;        /* For board and chipset_enable */
55 int exclude_start_page, exclude_end_page;
56 int force = 0, verbose = 0;
57
58 int fd_mem;
59
60 /*
61  *
62  */
63 struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
64 {
65         struct pci_dev *temp;
66         struct pci_filter filter;
67
68         pci_filter_init(NULL, &filter);
69         filter.vendor = vendor;
70         filter.device = device;
71
72         for (temp = pacc->devices; temp; temp = temp->next)
73                 if (pci_filter_match(&filter, temp))
74                         return temp;
75
76         return NULL;
77 }
78
79 /*
80  *
81  */
82 struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
83                               uint16_t card_vendor, uint16_t card_device)
84 {
85         struct pci_dev *temp;
86         struct pci_filter filter;
87
88         pci_filter_init(NULL, &filter);
89         filter.vendor = vendor;
90         filter.device = device;
91
92         for (temp = pacc->devices; temp; temp = temp->next)
93                 if (pci_filter_match(&filter, temp)) {
94                         if ((card_vendor == pci_read_word(temp, 0x2C)) &&
95                             (card_device == pci_read_word(temp, 0x2E)))
96                                 return temp;
97                 }
98
99         return NULL;
100 }
101
102 int map_flash_registers(struct flashchip *flash)
103 {
104         volatile uint8_t *registers;
105         size_t size = flash->total_size * 1024;
106
107         registers = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
108                     fd_mem, (off_t) (0xFFFFFFFF - 0x400000 - size + 1));
109
110         if (registers == MAP_FAILED) {
111                 perror("Can't mmap registers using " MEM_DEV);
112                 exit(1);
113         }
114         flash->virtual_registers = registers;
115
116         return 0;
117 }
118
119 struct flashchip *probe_flash(struct flashchip *flash)
120 {
121         volatile uint8_t *bios;
122         unsigned long flash_baseaddr, size;
123
124         while (flash->name != NULL) {
125                 if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0) {
126                         flash++;
127                         continue;
128                 }
129                 printf_debug("Probing for %s, %d KB\n",
130                              flash->name, flash->total_size);
131
132                 size = flash->total_size * 1024;
133
134 #ifdef TS5300
135                 // FIXME: Wrong place for this decision
136                 // FIXME: This should be autodetected. It is trivial.
137                 flash_baseaddr = 0x9400000;
138 #else
139                 flash_baseaddr = (0xffffffff - size + 1);
140 #endif
141
142                 /* If getpagesize() > size -> 
143                  * "Can't mmap memory using /dev/mem: Invalid argument"
144                  * This should never happen as we don't support any flash chips
145                  * smaller than 4k or 8k (yet).
146                  */
147
148                 if (getpagesize() > size) {
149                         size = getpagesize();
150                         printf("WARNING: size: %d -> %ld (page size)\n",
151                                flash->total_size * 1024, (unsigned long)size);
152                 }
153
154                 bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
155                             fd_mem, (off_t) flash_baseaddr);
156                 if (bios == MAP_FAILED) {
157                         perror("Can't mmap memory using " MEM_DEV);
158                         exit(1);
159                 }
160                 flash->virtual_memory = bios;
161
162                 if (flash->probe(flash) == 1) {
163                         printf("%s found at physical address: 0x%lx\n",
164                                flash->name, flash_baseaddr);
165                         return flash;
166                 }
167                 munmap((void *)bios, size);
168
169                 flash++;
170         }
171         return NULL;
172 }
173
174 int verify_flash(struct flashchip *flash, uint8_t *buf)
175 {
176         int idx;
177         int total_size = flash->total_size * 1024;
178         volatile uint8_t *bios = flash->virtual_memory;
179
180         printf("Verifying flash ");
181
182         if (verbose)
183                 printf("address: 0x00000000\b\b\b\b\b\b\b\b\b\b");
184
185         for (idx = 0; idx < total_size; idx++) {
186                 if (verbose && ((idx & 0xfff) == 0xfff))
187                         printf("0x%08x", idx);
188
189                 if (*(bios + idx) != *(buf + idx)) {
190                         if (verbose) {
191                                 printf("0x%08x ", idx);
192                         }
193                         printf("- FAILED\n");
194                         return 1;
195                 }
196
197                 if (verbose && ((idx & 0xfff) == 0xfff))
198                         printf("\b\b\b\b\b\b\b\b\b\b");
199         }
200         if (verbose)
201                 printf("\b\b\b\b\b\b\b\b\b\b ");
202
203         printf("- VERIFIED         \n");
204         return 0;
205 }
206
207 void usage(const char *name)
208 {
209         printf("usage: %s [-rwvEVfh] [-c chipname] [-s exclude_start]\n", name);
210         printf("       [-e exclude_end] [-m vendor:part] [-l file.layout] [-i imagename] [file]\n");
211         printf
212             ("   -r | --read:                    read flash and save into file\n"
213              "   -w | --write:                   write file into flash (default when\n"
214              "                                   file is specified)\n"
215              "   -v | --verify:                  verify flash against file\n"
216              "   -E | --erase:                   erase flash device\n"
217              "   -V | --verbose:                 more verbose output\n"
218              "   -c | --chip <chipname>:         probe only for specified flash chip\n"
219              "   -s | --estart <addr>:           exclude start position\n"
220              "   -e | --eend <addr>:             exclude end postion\n"
221              "   -m | --mainboard <vendor:part>: override mainboard settings\n"
222              "   -f | --force:                   force write without checking image\n"
223              "   -l | --layout <file.layout>:    read rom layout from file\n"
224              "   -i | --image <name>:            only flash image name from flash layout\n"
225              "\n" " If no file is specified, then all that happens\n"
226              " is that flash info is dumped.\n\n");
227         exit(1);
228 }
229
230 int main(int argc, char *argv[])
231 {
232         uint8_t *buf;
233         unsigned long size;
234         FILE *image;
235         struct flashchip *flash;
236         int opt;
237         int option_index = 0;
238         int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
239         int ret = 0;
240
241         static struct option long_options[] = {
242                 {"read", 0, 0, 'r'},
243                 {"write", 0, 0, 'w'},
244                 {"erase", 0, 0, 'E'},
245                 {"verify", 0, 0, 'v'},
246                 {"chip", 1, 0, 'c'},
247                 {"estart", 1, 0, 's'},
248                 {"eend", 1, 0, 'e'},
249                 {"mainboard", 1, 0, 'm'},
250                 {"verbose", 0, 0, 'V'},
251                 {"force", 0, 0, 'f'},
252                 {"layout", 1, 0, 'l'},
253                 {"image", 1, 0, 'i'},
254                 {"help", 0, 0, 'h'},
255                 {0, 0, 0, 0}
256         };
257
258         char *filename = NULL;
259
260         unsigned int exclude_start_position = 0, exclude_end_position = 0;      // [x,y)
261         char *tempstr = NULL, *tempstr2 = NULL;
262
263         if (argc > 1) {
264                 /* Yes, print them. */
265                 int i;
266                 printf_debug("The arguments are:\n");
267                 for (i = 1; i < argc; ++i)
268                         printf_debug("%s\n", argv[i]);
269         }
270
271         setbuf(stdout, NULL);
272         while ((opt = getopt_long(argc, argv, "rwvVEfc:s:e:m:l:i:h",
273                                   long_options, &option_index)) != EOF) {
274                 switch (opt) {
275                 case 'r':
276                         read_it = 1;
277                         break;
278                 case 'w':
279                         write_it = 1;
280                         break;
281                 case 'v':
282                         verify_it = 1;
283                         break;
284                 case 'c':
285                         chip_to_probe = strdup(optarg);
286                         break;
287                 case 'V':
288                         verbose = 1;
289                         break;
290                 case 'E':
291                         erase_it = 1;
292                         break;
293                 case 's':
294                         tempstr = strdup(optarg);
295                         sscanf(tempstr, "%x", &exclude_start_position);
296                         break;
297                 case 'e':
298                         tempstr = strdup(optarg);
299                         sscanf(tempstr, "%x", &exclude_end_position);
300                         break;
301                 case 'm':
302                         tempstr = strdup(optarg);
303                         strtok(tempstr, ":");
304                         tempstr2 = strtok(NULL, ":");
305                         if (tempstr2) {
306                                 lb_vendor = tempstr;
307                                 lb_part = tempstr2;
308                         } else {
309                                 printf("warning: ignored wrong format of"
310                                        " mainboard: %s\n", tempstr);
311                         }
312                         break;
313                 case 'f':
314                         force = 1;
315                         break;
316                 case 'l':
317                         tempstr = strdup(optarg);
318                         if (read_romlayout(tempstr))
319                                 exit(1);
320                         break;
321                 case 'i':
322                         tempstr = strdup(optarg);
323                         find_romentry(tempstr);
324                         break;
325                 case 'h':
326                 default:
327                         usage(argv[0]);
328                         break;
329                 }
330         }
331
332         if (read_it && write_it) {
333                 printf("-r and -w are mutually exclusive\n");
334                 usage(argv[0]);
335         }
336
337         if (optind < argc)
338                 filename = argv[optind++];
339
340         /* First get full io access */
341 #if defined (__sun) && (defined(__i386) || defined(__amd64))
342         if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
343 #else
344         if (iopl(3) != 0) {
345 #endif
346                 fprintf(stderr, "ERROR: iopl failed: \"%s\"\n",
347                         strerror(errno));
348                 exit(1);
349         }
350
351         /* Initialize PCI access for flash enables */
352         pacc = pci_alloc();     /* Get the pci_access structure */
353         /* Set all options you want -- here we stick with the defaults */
354         pci_init(pacc);         /* Initialize the PCI library */
355         pci_scan_bus(pacc);     /* We want to get the list of devices */
356
357         /* Open the memory device. A lot of functions need it */
358         if ((fd_mem = open(MEM_DEV, O_RDWR)) < 0) {
359                 perror("Error: Can not access memory using " MEM_DEV
360                        ". You need to be root.");
361                 exit(1);
362         }
363
364         myusec_calibrate_delay();
365
366         /* We look at the lbtable first to see if we need a
367          * mainboard specific flash enable sequence.
368          */
369         linuxbios_init();
370
371         /* try to enable it. Failure IS an option, since not all motherboards
372          * really need this to be done, etc., etc.
373          */
374         ret = chipset_flash_enable();
375         if (ret == -2) {
376                 printf("WARNING: No chipset found. Flash detection "
377                        "will most likely fail.\n");
378         }
379
380         board_flash_enable(lb_vendor, lb_part);
381
382         if ((flash = probe_flash(flashchips)) == NULL) {
383                 printf("No EEPROM/flash device found.\n");
384                 exit(1);
385         }
386
387         printf("Flash part is %s (%d KB)\n", flash->name, flash->total_size);
388
389         if (!filename && !erase_it) {
390                 // FIXME: Do we really want this feature implicitly?
391                 printf("OK, only ENABLING flash write, but NOT FLASHING.\n");
392                 return 0;
393         }
394
395         size = flash->total_size * 1024;
396         buf = (uint8_t *) calloc(size, sizeof(char));
397
398         if (erase_it) {
399                 printf("Erasing flash chip\n");
400                 flash->erase(flash);
401                 exit(0);
402         } else if (read_it) {
403                 if ((image = fopen(filename, "w")) == NULL) {
404                         perror(filename);
405                         exit(1);
406                 }
407                 printf("Reading Flash...");
408                 if (flash->read == NULL)
409                         memcpy(buf, (const char *)flash->virtual_memory, size);
410                 else
411                         flash->read(flash, buf);
412
413                 if (exclude_end_position - exclude_start_position > 0)
414                         memset(buf + exclude_start_position, 0,
415                                exclude_end_position - exclude_start_position);
416
417                 fwrite(buf, sizeof(char), size, image);
418                 fclose(image);
419                 printf("done\n");
420         } else {
421                 struct stat image_stat;
422
423                 if ((image = fopen(filename, "r")) == NULL) {
424                         perror(filename);
425                         exit(1);
426                 }
427                 if (fstat(fileno(image), &image_stat) != 0) {
428                         perror(filename);
429                         exit(1);
430                 }
431                 if (image_stat.st_size != flash->total_size * 1024) {
432                         fprintf(stderr, "Error: Image size doesnt match\n");
433                         exit(1);
434                 }
435
436                 fread(buf, sizeof(char), size, image);
437                 show_id(buf, size);
438                 fclose(image);
439         }
440
441         /* exclude range stuff. Nice idea, but at the moment it is only
442          * supported in hardware by the pm49fl004 chips. 
443          * Instead of implementing this for all chips I suggest advancing
444          * it to the rom layout feature below and drop exclude range
445          * completely once all flash chips can do rom layouts. stepan
446          */
447
448         // ////////////////////////////////////////////////////////////
449         if (exclude_end_position - exclude_start_position > 0)
450                 memcpy(buf + exclude_start_position,
451                        (const char *)flash->virtual_memory + exclude_start_position,
452                        exclude_end_position - exclude_start_position);
453
454         exclude_start_page = exclude_start_position / flash->page_size;
455         if ((exclude_start_position % flash->page_size) != 0) {
456                 exclude_start_page++;
457         }
458         exclude_end_page = exclude_end_position / flash->page_size;
459         // ////////////////////////////////////////////////////////////
460
461         // This should be moved into each flash part's code to do it 
462         // cleanly. This does the job.
463         handle_romentries(buf, (uint8_t *) flash->virtual_memory);
464
465         // ////////////////////////////////////////////////////////////
466
467         if (write_it)
468                 ret |= flash->write(flash, buf);
469
470         if (verify_it)
471                 ret |= verify_flash(flash, buf);
472
473         return ret;
474 }