flashrom: Abstract mmap() in physmap.c and only open /dev/mem on the first physmap...
[coreboot.git] / util / flashrom / flashrom.c
index 5e84134d3179f92627e47291a1501194049b3533..5d0f1ed5ab1c240a4d615934c00e1c56ab6e599c 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -44,7 +43,6 @@ char *chip_to_probe = NULL;
 struct pci_access *pacc;       /* For board and chipset_enable */
 int exclude_start_page, exclude_end_page;
 int verbose = 0;
-int fd_mem;
 
 struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
 {
@@ -84,28 +82,17 @@ struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
        return NULL;
 }
 
-int map_flash_registers(struct flashchip *flash)
+void map_flash_registers(struct flashchip *flash)
 {
-       volatile uint8_t *registers;
        size_t size = flash->total_size * 1024;
-
-       registers = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
-                        fd_mem, (off_t) (0xFFFFFFFF - 0x400000 - size + 1));
-
-       if (registers == MAP_FAILED) {
-               perror("Can't mmap registers using " MEM_DEV);
-               exit(1);
-       }
-       flash->virtual_registers = registers;
-
-       return 0;
+       flash->virtual_registers = physmap("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
 }
 
 struct flashchip *probe_flash(struct flashchip *first_flash, int force)
 {
        volatile uint8_t *bios;
        struct flashchip *flash;
-       unsigned long flash_baseaddr = 0, size;
+       unsigned long base = 0, size;
 
        for (flash = first_flash; flash && flash->name; flash++) {
                if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
@@ -133,21 +120,9 @@ struct flashchip *probe_flash(struct flashchip *first_flash, int force)
                         */
                        size = getpagesize();
                }
-#ifdef TS5300
-               // FIXME: Wrong place for this decision
-               // FIXME: This should be autodetected. It is trivial.
-               flash_baseaddr = 0x9400000;
-#else
-               flash_baseaddr = (0xffffffff - size + 1);
-#endif
 
-               bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
-                           fd_mem, (off_t) flash_baseaddr);
-               if (bios == MAP_FAILED) {
-                       perror("Can't mmap memory using " MEM_DEV);
-                       exit(1);
-               }
-               flash->virtual_memory = bios;
+               base = flashbase ? flashbase : (0xffffffff - size + 1);
+               flash->virtual_memory = bios = physmap("flash chip", base, size);
 
                if (force)
                        break;
@@ -160,14 +135,15 @@ struct flashchip *probe_flash(struct flashchip *first_flash, int force)
                        break;
 
 notfound:
-               munmap((void *)bios, size);
+               physunmap((void *)bios, size);
        }
 
        if (!flash || !flash->name)
                return NULL;
 
        printf("Found chip \"%s %s\" (%d KB) at physical address 0x%lx.\n",
-              flash->vendor, flash->name, flash->total_size, flash_baseaddr);
+              flash->vendor, flash->name, flash->total_size, base);
+       flashbase = base;
        return flash;
 }
 
@@ -191,10 +167,11 @@ int verify_flash(struct flashchip *flash, uint8_t *buf)
                        printf("0x%08x", idx);
 
                if (*(buf2 + idx) != *(buf + idx)) {
-                       if (verbose) {
-                               printf("0x%08x ", idx);
-                       }
-                       printf("FAILED!  Expected=0x%02x, Read=0x%02x\n",
+                       if (verbose)
+                               printf("0x%08x FAILED!", idx);
+                       else
+                               printf("FAILED at 0x%08x!", idx);
+                       printf("  Expected=0x%02x, Read=0x%02x\n",
                               *(buf + idx), *(buf2 + idx));
                        return 1;
                }
@@ -210,14 +187,61 @@ int verify_flash(struct flashchip *flash, uint8_t *buf)
        return 0;
 }
 
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)
+
 void print_supported_chips(void)
 {
-       int i;
+       int okcol = 0, pos = 0;
+       struct flashchip *f;
 
-       printf("Supported ROM chips:\n\n");
+       for (f = flashchips; f->name != NULL; f++) {
+               if (GENERIC_DEVICE_ID == f->model_id)
+                       continue;
+               okcol = MAX(okcol, strlen(f->vendor) + 1 + strlen(f->name));
+       }
+       okcol = (okcol + 7) & ~7;
 
-       for (i = 0; flashchips[i].name != NULL; i++)
-               printf("%s %s\n", flashchips[i].vendor, flashchips[i].name);
+       POS_PRINT("Supported flash chips:");
+       while (pos < okcol) {
+               printf("\t");
+               pos += 8 - (pos % 8);
+       }
+       printf("Tested OK operations:\tKnown BAD operations:\n\n");
+
+       for (f = flashchips; f->name != NULL; f++) {
+               printf("%s %s", f->vendor, f->name);
+               pos = strlen(f->vendor) + 1 + strlen(f->name);
+               while (pos < okcol) {
+                       printf("\t");
+                       pos += 8 - (pos % 8);
+               }
+               if ((f->tested & TEST_OK_MASK)) {
+                       if ((f->tested & TEST_OK_PROBE))
+                               POS_PRINT("PROBE ");
+                       if ((f->tested & TEST_OK_READ))
+                               POS_PRINT("READ ");
+                       if ((f->tested & TEST_OK_ERASE))
+                               POS_PRINT("ERASE ");
+                       if ((f->tested & TEST_OK_WRITE))
+                               POS_PRINT("WRITE");
+               }
+               while (pos < okcol + 24) {
+                       printf("\t");
+                       pos += 8 - (pos % 8);
+               }
+               if ((f->tested & TEST_BAD_MASK)) {
+                       if ((f->tested & TEST_BAD_PROBE))
+                               printf("PROBE ");
+                       if ((f->tested & TEST_BAD_READ))
+                               printf("READ ");
+                       if ((f->tested & TEST_BAD_ERASE))
+                               printf("ERASE ");
+                       if ((f->tested & TEST_BAD_WRITE))
+                               printf("WRITE");
+               }
+               printf("\n");
+       }
 }
 
 void usage(const char *name)
@@ -254,7 +278,8 @@ void print_version(void)
 int main(int argc, char *argv[])
 {
        uint8_t *buf;
-       unsigned long size;
+       unsigned long size, numbytes;
+       uint32_t erasedbytes;
        FILE *image;
        /* Probe for up to three flash chips. */
        struct flashchip *flash, *flashes[3];
@@ -396,13 +421,6 @@ int main(int argc, char *argv[])
        pci_init(pacc);         /* Initialize the PCI library */
        pci_scan_bus(pacc);     /* We want to get the list of devices */
 
-       /* Open the memory device UNCACHED. That's important for MMIO. */
-       if ((fd_mem = open(MEM_DEV, O_RDWR | O_SYNC)) < 0) {
-               perror("Error: Can not access memory using " MEM_DEV
-                      ". You need to be root.");
-               exit(1);
-       }
-
        myusec_calibrate_delay();
 
        /* We look at the lbtable first to see if we need a
@@ -474,11 +492,11 @@ int main(int argc, char *argv[])
                                       exclude_end_position -
                                       exclude_start_position);
 
-                       fwrite(buf, sizeof(char), size, image);
+                       numbytes = fwrite(buf, 1, size, image);
                        fclose(image);
-                       printf("done.\n");
+                       printf("%s.\n", numbytes == size ? "done" : "FAILED");
                        free(buf);
-                       exit(0);
+                       return numbytes != size;
                }
                // FIXME: flash writes stay enabled!
                exit(1);
@@ -538,13 +556,25 @@ int main(int argc, char *argv[])
 
        if (erase_it) {
                printf("Erasing flash chip... ");
-               if (!flash->erase) {
-                       fprintf(stderr, "Error: flashrom has no erase function for this flash chip.\n");
+               if (NULL == flash->erase) {
+                       printf("FAILED!\n");
+                       fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
                        return 1;
                }
                flash->erase(flash);
-               printf("done.\n");
-               exit(0);
+               if (NULL == flash->read)
+                       memcpy(buf, (const char *)flash->virtual_memory, size);
+               else
+                       flash->read(flash, buf);
+               for (erasedbytes = 0; erasedbytes < size; erasedbytes++)
+                       if (0xff != buf[erasedbytes]) {
+                               printf("FAILED!\n");
+                               fprintf(stderr, "ERROR at 0x%08x: Expected=0xff, Read=0x%02x\n",
+                                       erasedbytes, buf[erasedbytes]);
+                               return 1;
+                       }
+               printf("SUCCESS.\n");
+               return 0;
        } else if (read_it) {
                if ((image = fopen(filename, "w")) == NULL) {
                        perror(filename);
@@ -560,9 +590,11 @@ int main(int argc, char *argv[])
                        memset(buf + exclude_start_position, 0,
                               exclude_end_position - exclude_start_position);
 
-               fwrite(buf, sizeof(char), size, image);
+               numbytes = fwrite(buf, 1, size, image);
                fclose(image);
-               printf("done.\n");
+               printf("%s.\n", numbytes == size ? "done" : "FAILED");
+               if (numbytes != size)
+                       return 1;
        } else {
                struct stat image_stat;
 
@@ -579,9 +611,13 @@ int main(int argc, char *argv[])
                        exit(1);
                }
 
-               fread(buf, sizeof(char), size, image);
+               numbytes = fread(buf, 1, size, image);
                show_id(buf, size, force);
                fclose(image);
+               if (numbytes != size) {
+                       fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
+                       return 1;
+               }
        }
 
        /* exclude range stuff. Nice idea, but at the moment it is only