int probe_m29f400bt(struct flashctx *flash) { chipaddr bios = flash->virtual_memory; uint8_t id1, id2; chip_writeb(flash, 0xAA, bios + 0xAAA); chip_writeb(flash, 0x55, bios + 0x555); chip_writeb(flash, 0x90, bios + 0xAAA); programmer_delay(10); id1 = chip_readb(flash, bios); /* The data sheet says id2 is at (bios + 0x01) and id2 listed in * flash.h does not match. It should be possible to use JEDEC probe. */ id2 = chip_readb(flash, bios + 0x02); chip_writeb(flash, 0xAA, bios + 0xAAA); chip_writeb(flash, 0x55, bios + 0x555); chip_writeb(flash, 0xF0, bios + 0xAAA); programmer_delay(10); msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id) return 1; return 0; }
int probe_82802ab(struct flashctx *flash) { chipaddr bios = flash->virtual_memory; uint8_t id1, id2, flashcontent1, flashcontent2; int shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED) ? 1 : 0; /* Reset to get a clean state */ chip_writeb(flash, 0xFF, bios); programmer_delay(10); /* Enter ID mode */ chip_writeb(flash, 0x90, bios); programmer_delay(10); id1 = chip_readb(flash, bios + (0x00 << shifted)); id2 = chip_readb(flash, bios + (0x01 << shifted)); /* Leave ID mode */ chip_writeb(flash, 0xFF, bios); programmer_delay(10); msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2); if (!oddparity(id1)) msg_cdbg(", id1 parity violation"); /* * Read the product ID location again. We should now see normal * flash contents. */ flashcontent1 = chip_readb(flash, bios + (0x00 << shifted)); flashcontent2 = chip_readb(flash, bios + (0x01 << shifted)); if (id1 == flashcontent1) msg_cdbg(", id1 is normal flash content"); if (id2 == flashcontent2) msg_cdbg(", id2 is normal flash content"); msg_cdbg("\n"); if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id) return 0; if (flash->chip->feature_bits & FEATURE_REGISTERMAP) map_flash_registers(flash); return 1; }
/* According to the Winbond W29EE011, W29EE012, W29C010M, W29C011A * datasheets this is the only valid probe function for those chips. */ int probe_w29ee011(struct flashctx *flash) { chipaddr bios = flash->virtual_memory; uint8_t id1, id2; if (!chip_to_probe || strcmp(chip_to_probe, flash->chip->name)) { msg_cdbg("Old Winbond W29* probe method disabled because " "the probing sequence puts the AMIC A49LF040A in " "a funky state. Use 'flashrom -c %s' if you " "have a board with such a chip.\n", flash->chip->name); return 0; } /* Issue JEDEC Product ID Entry command */ chip_writeb(flash, 0xAA, bios + 0x5555); programmer_delay(10); chip_writeb(flash, 0x55, bios + 0x2AAA); programmer_delay(10); chip_writeb(flash, 0x80, bios + 0x5555); programmer_delay(10); chip_writeb(flash, 0xAA, bios + 0x5555); programmer_delay(10); chip_writeb(flash, 0x55, bios + 0x2AAA); programmer_delay(10); chip_writeb(flash, 0x60, bios + 0x5555); programmer_delay(10); /* Read product ID */ id1 = chip_readb(flash, bios); id2 = chip_readb(flash, bios + 0x01); /* Issue JEDEC Product ID Exit command */ chip_writeb(flash, 0xAA, bios + 0x5555); programmer_delay(10); chip_writeb(flash, 0x55, bios + 0x2AAA); programmer_delay(10); chip_writeb(flash, 0xF0, bios + 0x5555); programmer_delay(10); msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id) return 1; return 0; }
static uint8_t w39_idmode_readb(struct flashchip *flash, int offset) { chipaddr bios = flash->virtual_memory; uint8_t val; /* Product Identification Entry */ chip_writeb(0xAA, bios + 0x5555); chip_writeb(0x55, bios + 0x2AAA); chip_writeb(0x90, bios + 0x5555); programmer_delay(10); /* Read something, maybe hardware lock bits */ val = chip_readb(bios + offset); /* Product Identification Exit */ chip_writeb(0xAA, bios + 0x5555); chip_writeb(0x55, bios + 0x2AAA); chip_writeb(0xF0, bios + 0x5555); programmer_delay(10); return val; }
static int erase_28sf040(struct flashchip *flash) { chipaddr bios = flash->virtual_memory; chip_writeb(CHIP_ERASE, bios); chip_writeb(CHIP_ERASE, bios); programmer_delay(10); toggle_ready_jedec(bios); if (check_erased_range(flash, 0, flash->total_size * 1024)) { msg_cerr("ERASE FAILED!\n"); return -1; } return 0; }
static int stm50_erase_sector(struct flashctx *flash, unsigned int addr) { chipaddr bios = flash->virtual_memory + addr; // clear status register chip_writeb(flash, 0x50, bios); // now start it chip_writeb(flash, 0x32, bios); chip_writeb(flash, 0xd0, bios); programmer_delay(10); uint8_t status = wait_82802ab(flash); print_status_82802ab(status); return status == 0x80; }
int erase_m29f400bt(struct flashctx *flash) { chipaddr bios = flash->virtual_memory; chip_writeb(flash, 0xAA, bios + 0xAAA); chip_writeb(flash, 0x55, bios + 0x555); chip_writeb(flash, 0x80, bios + 0xAAA); chip_writeb(flash, 0xAA, bios + 0xAAA); chip_writeb(flash, 0x55, bios + 0x555); chip_writeb(flash, 0x10, bios + 0xAAA); programmer_delay(10); toggle_ready_jedec(flash, bios); /* FIXME: Check the status register for errors. */ return 0; }
int block_erase_m29f400bt(struct flashctx *flash, unsigned int start, unsigned int len) { chipaddr bios = flash->virtual_memory; chipaddr dst = bios + start; chip_writeb(flash, 0xAA, bios + 0xAAA); chip_writeb(flash, 0x55, bios + 0x555); chip_writeb(flash, 0x80, bios + 0xAAA); chip_writeb(flash, 0xAA, bios + 0xAAA); chip_writeb(flash, 0x55, bios + 0x555); chip_writeb(flash, 0x30, dst); programmer_delay(10); toggle_ready_jedec(flash, bios); /* FIXME: Check the status register for errors. */ return 0; }
int erase_block_82802ab(struct flashctx *flash, unsigned int page, unsigned int pagesize) { chipaddr bios = flash->virtual_memory; uint8_t status; // clear status register chip_writeb(flash, 0x50, bios + page); // now start it chip_writeb(flash, 0x20, bios + page); chip_writeb(flash, 0xd0, bios + page); programmer_delay(10); // now let's see what the register is status = wait_82802ab(flash); print_status_82802ab(status); /* FIXME: Check the status register for errors. */ return 0; }
/* This function will poll the keyboard status register until either * an expected value shows up, or * timeout reaches. * * Returns: 0 -- the expected value has shown. * 1 -- timeout reached. */ static int wait_for( const unsigned int mask, const unsigned int expected_value, const int timeout, /* in usec */ const char* error_message, const char* function_name, const int lineno ) { int time_passed; for (time_passed = 0;; ++time_passed) { if ((INB(LEGACY_KBC_PORT_CMD) & mask) == expected_value) return 0; if (time_passed >= timeout) break; programmer_delay(1); } if (error_message) msg_perr("%s():%d %s", function_name, lineno, error_message); return 1; }
/* Page size is usually 256 bytes */ static int it8716f_spi_page_program(struct flashchip *flash, uint8_t *buf, int start) { int i; int result; chipaddr bios = flash->virtual_memory; result = spi_write_enable(); if (result) return result; /* FIXME: The command below seems to be redundant or wrong. */ OUTB(0x06, it8716f_flashport + 1); OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport); for (i = 0; i < flash->page_size; i++) { chip_writeb(buf[i], bios + start + i); } OUTB(0, it8716f_flashport); /* Wait until the Write-In-Progress bit is cleared. * This usually takes 1-10 ms, so wait in 1 ms steps. */ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) programmer_delay(1000); return 0; }
/* W83627DHG has 11 command modes: * 1=1 command only * 2=1 command+1 data write * 3=1 command+2 data read * 4=1 command+3 address * 5=1 command+3 address+1 data write * 6=1 command+3 address+4 data write * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read * 8=1 command+3 address+1 data read * 9=1 command+3 address+2 data read * a=1 command+3 address+3 data read * b=1 command+3 address+4 data read * * mode[7:4] holds the command mode * mode[3:0] holds SPI address bits [19:16] * * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\ * Would one more byte of RAM in the chip (to get all 24 bits) really make * such a big difference? */ static int wbsio_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { int i; uint8_t mode = 0; msg_pspew("%s:", __func__); if (1 == writecnt && 0 == readcnt) { mode = 0x10; } else if (2 == writecnt && 0 == readcnt) { OUTB(writearr[1], wbsio_spibase + 4); msg_pspew(" data=0x%02x", writearr[1]); mode = 0x20; } else if (1 == writecnt && 2 == readcnt) { mode = 0x30; } else if (4 == writecnt && 0 == readcnt) { msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); for (i = 2; i < writecnt; i++) { OUTB(writearr[i], wbsio_spibase + i); msg_pspew("%02x", writearr[i]); } mode = 0x40 | (writearr[1] & 0x0f); } else if (5 == writecnt && 0 == readcnt) { msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); for (i = 2; i < 4; i++) { OUTB(writearr[i], wbsio_spibase + i); msg_pspew("%02x", writearr[i]); } OUTB(writearr[i], wbsio_spibase + i); msg_pspew(" data=0x%02x", writearr[i]); mode = 0x50 | (writearr[1] & 0x0f); } else if (8 == writecnt && 0 == readcnt) { msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); for (i = 2; i < 4; i++) { OUTB(writearr[i], wbsio_spibase + i); msg_pspew("%02x", writearr[i]); } msg_pspew(" data=0x"); for (; i < writecnt; i++) { OUTB(writearr[i], wbsio_spibase + i); msg_pspew("%02x", writearr[i]); } mode = 0x60 | (writearr[1] & 0x0f); } else if (5 == writecnt && 4 == readcnt) { /* XXX: TODO not supported by flashrom infrastructure! * This mode, 7, discards the fifth byte in writecnt, * but since we can not express that in flashrom, fail * the operation for now. */ ; } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) { msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); for (i = 2; i < writecnt; i++) { OUTB(writearr[i], wbsio_spibase + i); msg_pspew("%02x", writearr[i]); } mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f); } msg_pspew(" cmd=%02x mode=%02x\n", writearr[0], mode); if (!mode) { msg_perr("%s: unsupported command type wr=%d rd=%d\n", __func__, writecnt, readcnt); /* Command type refers to the number of bytes read/written. */ return SPI_INVALID_LENGTH; } OUTB(writearr[0], wbsio_spibase); OUTB(mode, wbsio_spibase + 1); programmer_delay(10); if (!readcnt) return 0; msg_pspew("%s: returning data =", __func__); for (i = 0; i < readcnt; i++) { readarr[i] = INB(wbsio_spibase + 4 + i); msg_pspew(" 0x%02x", readarr[i]); } msg_pspew("\n"); return 0; }
int cli_classic(int argc, char *argv[]) { unsigned long size; /* Probe for up to three flash chips. */ const struct flashchip *flash; struct flashchip flashes[3]; struct flashchip *fill_flash; int startchip = 0; int chipcount = 0; const char *name; int namelen; int opt; int option_index = 0; int force = 0; int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; int dont_verify_it = 0, list_supported = 0; #if CONFIG_PRINT_WIKI == 1 int list_supported_wiki = 0; #endif int operation_specified = 0; int i; static const char optstring[] = "r:Rw:v:nVEfc:m:l:i:p:Lzh"; static const struct option long_options[] = { {"read", 1, NULL, 'r'}, {"write", 1, NULL, 'w'}, {"erase", 0, NULL, 'E'}, {"verify", 1, NULL, 'v'}, {"noverify", 0, NULL, 'n'}, {"chip", 1, NULL, 'c'}, {"mainboard", 1, NULL, 'm'}, {"verbose", 0, NULL, 'V'}, {"force", 0, NULL, 'f'}, {"layout", 1, NULL, 'l'}, {"image", 1, NULL, 'i'}, {"list-supported", 0, NULL, 'L'}, {"list-supported-wiki", 0, NULL, 'z'}, {"programmer", 1, NULL, 'p'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'R'}, {NULL, 0, NULL, 0} }; char *filename = NULL; char *tempstr = NULL; char *pparam = NULL; print_version(); print_banner(); if (selfcheck()) exit(1); setbuf(stdout, NULL); /* FIXME: Delay all operation_specified checks until after command * line parsing to allow --help overriding everything else. */ while ((opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != EOF) { switch (opt) { case 'r': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } filename = strdup(optarg); read_it = 1; break; case 'w': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } filename = strdup(optarg); write_it = 1; break; case 'v': //FIXME: gracefully handle superfluous -v if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } if (dont_verify_it) { fprintf(stderr, "--verify and --noverify are" "mutually exclusive. Aborting.\n"); cli_classic_abort_usage(); } filename = strdup(optarg); verify_it = 1; break; case 'n': if (verify_it) { fprintf(stderr, "--verify and --noverify are" "mutually exclusive. Aborting.\n"); cli_classic_abort_usage(); } dont_verify_it = 1; break; case 'c': chip_to_probe = strdup(optarg); break; case 'V': verbose++; break; case 'E': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } erase_it = 1; break; case 'm': #if CONFIG_INTERNAL == 1 tempstr = strdup(optarg); lb_vendor_dev_from_string(tempstr); #else fprintf(stderr, "Error: Internal programmer support " "was not compiled in and --mainboard only\n" "applies to the internal programmer. Aborting.\n"); cli_classic_abort_usage(); #endif break; case 'f': force = 1; break; case 'l': tempstr = strdup(optarg); if (read_romlayout(tempstr)) cli_classic_abort_usage(); break; case 'i': tempstr = strdup(optarg); find_romentry(tempstr); break; case 'L': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } list_supported = 1; break; case 'z': #if CONFIG_PRINT_WIKI == 1 if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } list_supported_wiki = 1; #else fprintf(stderr, "Error: Wiki output was not compiled " "in. Aborting.\n"); cli_classic_abort_usage(); #endif break; case 'p': for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) { name = programmer_table[programmer].name; namelen = strlen(name); if (strncmp(optarg, name, namelen) == 0) { switch (optarg[namelen]) { case ':': pparam = strdup(optarg + namelen + 1); if (!strlen(pparam)) { free(pparam); pparam = NULL; } break; case '\0': break; default: /* The continue refers to the * for loop. It is here to be * able to differentiate between * foo and foobar. */ continue; } break; } } if (programmer == PROGRAMMER_INVALID) { fprintf(stderr, "Error: Unknown programmer " "%s.\n", optarg); cli_classic_abort_usage(); } break; case 'R': /* print_version() is always called during startup. */ if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } exit(0); break; case 'h': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } cli_classic_usage(argv[0]); exit(0); break; default: cli_classic_abort_usage(); break; } } /* FIXME: Print the actions flashrom will take. */ if (list_supported) { print_supported(); exit(0); } #if CONFIG_PRINT_WIKI == 1 if (list_supported_wiki) { print_supported_wiki(); exit(0); } #endif if (optind < argc) { fprintf(stderr, "Error: Extra parameter found.\n"); cli_classic_abort_usage(); } #if CONFIG_INTERNAL == 1 if ((programmer != PROGRAMMER_INTERNAL) && (lb_part || lb_vendor)) { fprintf(stderr, "Error: --mainboard requires the internal " "programmer. Aborting.\n"); cli_classic_abort_usage(); } #endif if (chip_to_probe) { for (flash = flashchips; flash && flash->name; flash++) if (!strcmp(flash->name, chip_to_probe)) break; if (!flash || !flash->name) { fprintf(stderr, "Error: Unknown chip '%s' specified.\n", chip_to_probe); printf("Run flashrom -L to view the hardware supported " "in this flashrom version.\n"); exit(1); } /* Clean up after the check. */ flash = NULL; } /* FIXME: Delay calibration should happen in programmer code. */ myusec_calibrate_delay(); if (programmer_init(pparam)) { fprintf(stderr, "Error: Programmer initialization failed.\n"); programmer_shutdown(); exit(1); } for (i = 0; i < ARRAY_SIZE(flashes); i++) { startchip = probe_flash(startchip, &flashes[i], 0); if (startchip == -1) break; chipcount++; startchip++; } if (chipcount > 1) { printf("Multiple flash chips were detected:"); for (i = 0; i < chipcount; i++) printf(" %s", flashes[i].name); printf("\nPlease specify which chip to use with the -c <chipname> option.\n"); programmer_shutdown(); exit(1); } else if (!chipcount) { printf("No EEPROM/flash device found.\n"); if (!force || !chip_to_probe) { printf("Note: flashrom can never write if the flash chip isn't found automatically.\n"); } if (force && read_it && chip_to_probe) { printf("Force read (-f -r -c) requested, pretending the chip is there:\n"); startchip = probe_flash(0, &flashes[0], 1); if (startchip == -1) { printf("Probing for flash chip '%s' failed.\n", chip_to_probe); programmer_shutdown(); exit(1); } printf("Please note that forced reads most likely contain garbage.\n"); return read_flash_to_file(&flashes[0], filename); } // FIXME: flash writes stay enabled! programmer_shutdown(); exit(1); } fill_flash = &flashes[0]; check_chip_supported(fill_flash); size = fill_flash->total_size * 1024; if (check_max_decode((buses_supported & fill_flash->bustype), size) && (!force)) { fprintf(stderr, "Chip is too big for this programmer " "(-V gives details). Use --force to override.\n"); programmer_shutdown(); return 1; } if (!(read_it | write_it | verify_it | erase_it)) { printf("No operations were specified.\n"); // FIXME: flash writes stay enabled! programmer_shutdown(); exit(0); } if (!filename && !erase_it) { printf("Error: No filename specified.\n"); // FIXME: flash writes stay enabled! programmer_shutdown(); exit(1); } /* Always verify write operations unless -n is used. */ if (write_it && !dont_verify_it) verify_it = 1; /* FIXME: We should issue an unconditional chip reset here. This can be * done once we have a .reset function in struct flashchip. * Give the chip time to settle. */ programmer_delay(100000); return doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it); }
int main(int argc, char *argv[]) { const struct flashchip *chip = NULL; /* Probe for up to eight flash chips. */ struct flashctx flashes[8] = {{0}}; struct flashctx *fill_flash; const char *name; int namelen, opt, i, j; int startchip = -1, chipcount = 0, option_index = 0, force = 0, ifd = 0, fmap = 0; #if CONFIG_PRINT_WIKI == 1 int list_supported_wiki = 0; #endif int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; int dont_verify_it = 0, dont_verify_all = 0, list_supported = 0, operation_specified = 0; struct flashrom_layout *layout = NULL; enum programmer prog = PROGRAMMER_INVALID; enum { OPTION_IFD = 0x0100, OPTION_FMAP, OPTION_FMAP_FILE, OPTION_FLASH_CONTENTS, }; int ret = 0; static const char optstring[] = "r:Rw:v:nNVEfc:l:i:p:Lzho:"; static const struct option long_options[] = { {"read", 1, NULL, 'r'}, {"write", 1, NULL, 'w'}, {"erase", 0, NULL, 'E'}, {"verify", 1, NULL, 'v'}, {"noverify", 0, NULL, 'n'}, {"noverify-all", 0, NULL, 'N'}, {"chip", 1, NULL, 'c'}, {"verbose", 0, NULL, 'V'}, {"force", 0, NULL, 'f'}, {"layout", 1, NULL, 'l'}, {"ifd", 0, NULL, OPTION_IFD}, {"fmap", 0, NULL, OPTION_FMAP}, {"fmap-file", 1, NULL, OPTION_FMAP_FILE}, {"image", 1, NULL, 'i'}, {"flash-contents", 1, NULL, OPTION_FLASH_CONTENTS}, {"list-supported", 0, NULL, 'L'}, {"list-supported-wiki", 0, NULL, 'z'}, {"programmer", 1, NULL, 'p'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'R'}, {"output", 1, NULL, 'o'}, {NULL, 0, NULL, 0}, }; char *filename = NULL; char *referencefile = NULL; char *layoutfile = NULL; char *fmapfile = NULL; #ifndef STANDALONE char *logfile = NULL; #endif /* !STANDALONE */ char *tempstr = NULL; char *pparam = NULL; flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb); print_version(); print_banner(); if (selfcheck()) exit(1); setbuf(stdout, NULL); /* FIXME: Delay all operation_specified checks until after command * line parsing to allow --help overriding everything else. */ while ((opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != EOF) { switch (opt) { case 'r': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } filename = strdup(optarg); read_it = 1; break; case 'w': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } filename = strdup(optarg); write_it = 1; break; case 'v': //FIXME: gracefully handle superfluous -v if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } if (dont_verify_it) { fprintf(stderr, "--verify and --noverify are mutually exclusive. Aborting.\n"); cli_classic_abort_usage(); } filename = strdup(optarg); verify_it = 1; break; case 'n': if (verify_it) { fprintf(stderr, "--verify and --noverify are mutually exclusive. Aborting.\n"); cli_classic_abort_usage(); } dont_verify_it = 1; break; case 'N': dont_verify_all = 1; break; case 'c': chip_to_probe = strdup(optarg); break; case 'V': verbose_screen++; if (verbose_screen > FLASHROM_MSG_DEBUG2) verbose_logfile = verbose_screen; break; case 'E': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } erase_it = 1; break; case 'f': force = 1; break; case 'l': if (layoutfile) { fprintf(stderr, "Error: --layout specified " "more than once. Aborting.\n"); cli_classic_abort_usage(); } if (ifd) { fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); } if (fmap) { fprintf(stderr, "Error: --layout and --fmap-file both specified. Aborting.\n"); cli_classic_abort_usage(); } layoutfile = strdup(optarg); break; case OPTION_IFD: if (layoutfile) { fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); } if (fmap) { fprintf(stderr, "Error: --fmap-file and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); } ifd = 1; break; case OPTION_FMAP_FILE: if (fmap) { fprintf(stderr, "Error: --fmap or --fmap-file specified " "more than once. Aborting.\n"); cli_classic_abort_usage(); } if (ifd) { fprintf(stderr, "Error: --fmap-file and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); } if (layoutfile) { fprintf(stderr, "Error: --fmap-file and --layout both specified. Aborting.\n"); cli_classic_abort_usage(); } fmapfile = strdup(optarg); fmap = 1; break; case OPTION_FMAP: if (fmap) { fprintf(stderr, "Error: --fmap or --fmap-file specified " "more than once. Aborting.\n"); cli_classic_abort_usage(); } if (ifd) { fprintf(stderr, "Error: --fmap and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); } if (layoutfile) { fprintf(stderr, "Error: --layout and --fmap both specified. Aborting.\n"); cli_classic_abort_usage(); } fmap = 1; break; case 'i': tempstr = strdup(optarg); if (register_include_arg(tempstr)) { free(tempstr); cli_classic_abort_usage(); } break; case OPTION_FLASH_CONTENTS: referencefile = strdup(optarg); break; case 'L': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } list_supported = 1; break; case 'z': #if CONFIG_PRINT_WIKI == 1 if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } list_supported_wiki = 1; #else fprintf(stderr, "Error: Wiki output was not compiled " "in. Aborting.\n"); cli_classic_abort_usage(); #endif break; case 'p': if (prog != PROGRAMMER_INVALID) { fprintf(stderr, "Error: --programmer specified " "more than once. You can separate " "multiple\nparameters for a programmer " "with \",\". Please see the man page " "for details.\n"); cli_classic_abort_usage(); } for (prog = 0; prog < PROGRAMMER_INVALID; prog++) { name = programmer_table[prog].name; namelen = strlen(name); if (strncmp(optarg, name, namelen) == 0) { switch (optarg[namelen]) { case ':': pparam = strdup(optarg + namelen + 1); if (!strlen(pparam)) { free(pparam); pparam = NULL; } break; case '\0': break; default: /* The continue refers to the * for loop. It is here to be * able to differentiate between * foo and foobar. */ continue; } break; } } if (prog == PROGRAMMER_INVALID) { fprintf(stderr, "Error: Unknown programmer \"%s\". Valid choices are:\n", optarg); list_programmers_linebreak(0, 80, 0); msg_ginfo(".\n"); cli_classic_abort_usage(); } break; case 'R': /* print_version() is always called during startup. */ if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } exit(0); break; case 'h': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " "specified. Aborting.\n"); cli_classic_abort_usage(); } cli_classic_usage(argv[0]); exit(0); break; case 'o': #ifdef STANDALONE fprintf(stderr, "Log file not supported in standalone mode. Aborting.\n"); cli_classic_abort_usage(); #else /* STANDALONE */ logfile = strdup(optarg); if (logfile[0] == '\0') { fprintf(stderr, "No log filename specified.\n"); cli_classic_abort_usage(); } #endif /* STANDALONE */ break; default: cli_classic_abort_usage(); break; } } if (optind < argc) { fprintf(stderr, "Error: Extra parameter found.\n"); cli_classic_abort_usage(); } if ((read_it | write_it | verify_it) && check_filename(filename, "image")) { cli_classic_abort_usage(); } if (layoutfile && check_filename(layoutfile, "layout")) { cli_classic_abort_usage(); } if (fmapfile && check_filename(fmapfile, "fmap")) { cli_classic_abort_usage(); } if (referencefile && check_filename(referencefile, "reference")) { cli_classic_abort_usage(); } #ifndef STANDALONE if (logfile && check_filename(logfile, "log")) cli_classic_abort_usage(); if (logfile && open_logfile(logfile)) cli_classic_abort_usage(); #endif /* !STANDALONE */ #if CONFIG_PRINT_WIKI == 1 if (list_supported_wiki) { print_supported_wiki(); goto out; } #endif if (list_supported) { if (print_supported()) ret = 1; goto out; } #ifndef STANDALONE start_logging(); #endif /* !STANDALONE */ print_buildinfo(); msg_gdbg("Command line (%i args):", argc - 1); for (i = 0; i < argc; i++) { msg_gdbg(" %s", argv[i]); } msg_gdbg("\n"); if (layoutfile && read_romlayout(layoutfile)) { ret = 1; goto out; } if (!ifd && !fmap && process_include_args(get_global_layout())) { ret = 1; goto out; } /* Does a chip with the requested name exist in the flashchips array? */ if (chip_to_probe) { for (chip = flashchips; chip && chip->name; chip++) if (!strcmp(chip->name, chip_to_probe)) break; if (!chip || !chip->name) { msg_cerr("Error: Unknown chip '%s' specified.\n", chip_to_probe); msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n"); ret = 1; goto out; } /* Keep chip around for later usage in case a forced read is requested. */ } if (prog == PROGRAMMER_INVALID) { if (CONFIG_DEFAULT_PROGRAMMER != PROGRAMMER_INVALID) { prog = CONFIG_DEFAULT_PROGRAMMER; /* We need to strdup here because we free(pparam) unconditionally later. */ pparam = strdup(CONFIG_DEFAULT_PROGRAMMER_ARGS); msg_pinfo("Using default programmer \"%s\" with arguments \"%s\".\n", programmer_table[CONFIG_DEFAULT_PROGRAMMER].name, pparam); } else { msg_perr("Please select a programmer with the --programmer parameter.\n" "Previously this was not necessary because there was a default set.\n" #if CONFIG_INTERNAL == 1 "To choose the mainboard of this computer use 'internal'. " #endif "Valid choices are:\n"); list_programmers_linebreak(0, 80, 0); msg_ginfo(".\n"); ret = 1; goto out; } } /* FIXME: Delay calibration should happen in programmer code. */ myusec_calibrate_delay(); if (programmer_init(prog, pparam)) { msg_perr("Error: Programmer initialization failed.\n"); ret = 1; goto out_shutdown; } tempstr = flashbuses_to_text(get_buses_supported()); msg_pdbg("The following protocols are supported: %s.\n", tempstr); free(tempstr); for (j = 0; j < registered_master_count; j++) { startchip = 0; while (chipcount < ARRAY_SIZE(flashes)) { startchip = probe_flash(®istered_masters[j], startchip, &flashes[chipcount], 0); if (startchip == -1) break; chipcount++; startchip++; } } if (chipcount > 1) { msg_cinfo("Multiple flash chip definitions match the detected chip(s): \"%s\"", flashes[0].chip->name); for (i = 1; i < chipcount; i++) msg_cinfo(", \"%s\"", flashes[i].chip->name); msg_cinfo("\nPlease specify which chip definition to use with the -c <chipname> option.\n"); ret = 1; goto out_shutdown; } else if (!chipcount) { msg_cinfo("No EEPROM/flash device found.\n"); if (!force || !chip_to_probe) { msg_cinfo("Note: flashrom can never write if the flash chip isn't found " "automatically.\n"); } if (force && read_it && chip_to_probe) { struct registered_master *mst; int compatible_masters = 0; msg_cinfo("Force read (-f -r -c) requested, pretending the chip is there:\n"); /* This loop just counts compatible controllers. */ for (j = 0; j < registered_master_count; j++) { mst = ®istered_masters[j]; /* chip is still set from the chip_to_probe earlier in this function. */ if (mst->buses_supported & chip->bustype) compatible_masters++; } if (!compatible_masters) { msg_cinfo("No compatible controller found for the requested flash chip.\n"); ret = 1; goto out_shutdown; } if (compatible_masters > 1) msg_cinfo("More than one compatible controller found for the requested flash " "chip, using the first one.\n"); for (j = 0; j < registered_master_count; j++) { mst = ®istered_masters[j]; startchip = probe_flash(mst, 0, &flashes[0], 1); if (startchip != -1) break; } if (startchip == -1) { // FIXME: This should never happen! Ask for a bug report? msg_cinfo("Probing for flash chip '%s' failed.\n", chip_to_probe); ret = 1; goto out_shutdown; } if (map_flash(&flashes[0]) != 0) { free(flashes[0].chip); ret = 1; goto out_shutdown; } msg_cinfo("Please note that forced reads most likely contain garbage.\n"); ret = read_flash_to_file(&flashes[0], filename); unmap_flash(&flashes[0]); free(flashes[0].chip); goto out_shutdown; } ret = 1; goto out_shutdown; } else if (!chip_to_probe) { /* repeat for convenience when looking at foreign logs */ tempstr = flashbuses_to_text(flashes[0].chip->bustype); msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n", flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size, tempstr); free(tempstr); } fill_flash = &flashes[0]; print_chip_support_status(fill_flash->chip); unsigned int limitexceeded = count_max_decode_exceedings(fill_flash); if (limitexceeded > 0 && !force) { enum chipbustype commonbuses = fill_flash->mst->buses_supported & fill_flash->chip->bustype; /* Sometimes chip and programmer have more than one bus in common, * and the limit is not exceeded on all buses. Tell the user. */ if ((bitcount(commonbuses) > limitexceeded)) { msg_pdbg("There is at least one interface available which could support the size of\n" "the selected flash chip.\n"); } msg_cerr("This flash chip is too big for this programmer (--verbose/-V gives details).\n" "Use --force/-f to override at your own risk.\n"); ret = 1; goto out_shutdown; } if (!(read_it | write_it | verify_it | erase_it)) { msg_ginfo("No operations were specified.\n"); goto out_shutdown; } if (layoutfile) { layout = get_global_layout(); } else if (ifd && (flashrom_layout_read_from_ifd(&layout, fill_flash, NULL, 0) || process_include_args(layout))) { ret = 1; goto out_shutdown; } else if (fmap && fmapfile) { struct stat s; if (stat(fmapfile, &s) != 0) { msg_gerr("Failed to stat fmapfile \"%s\"\n", fmapfile); ret = 1; goto out_shutdown; } size_t fmapfile_size = s.st_size; uint8_t *fmapfile_buffer = malloc(fmapfile_size); if (!fmapfile_buffer) { ret = 1; goto out_shutdown; } if (read_buf_from_file(fmapfile_buffer, fmapfile_size, fmapfile)) { ret = 1; free(fmapfile_buffer); goto out_shutdown; } if (flashrom_layout_read_fmap_from_buffer(&layout, fill_flash, fmapfile_buffer, fmapfile_size) || process_include_args(layout)) { ret = 1; free(fmapfile_buffer); goto out_shutdown; } free(fmapfile_buffer); } else if (fmap && (flashrom_layout_read_fmap_from_rom(&layout, fill_flash, 0, fill_flash->chip->total_size * 1024) || process_include_args(layout))) { ret = 1; goto out_shutdown; } flashrom_layout_set(fill_flash, layout); flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE, !!force); #if CONFIG_INTERNAL == 1 flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE_BOARDMISMATCH, !!force_boardmismatch); #endif flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_AFTER_WRITE, !dont_verify_it); flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, !dont_verify_all); /* FIXME: We should issue an unconditional chip reset here. This can be * done once we have a .reset function in struct flashchip. * Give the chip time to settle. */ programmer_delay(100000); if (read_it) ret = do_read(fill_flash, filename); else if (erase_it) ret = do_erase(fill_flash); else if (write_it) ret = do_write(fill_flash, filename, referencefile); else if (verify_it) ret = do_verify(fill_flash, filename); flashrom_layout_release(layout); out_shutdown: programmer_shutdown(); out: for (i = 0; i < chipcount; i++) free(flashes[i].chip); layout_cleanup(); free(filename); free(fmapfile); free(referencefile); free(layoutfile); free(pparam); /* clean up global variables */ free((char *)chip_to_probe); /* Silence! Freeing is not modifying contents. */ chip_to_probe = NULL; #ifndef STANDALONE free(logfile); ret |= close_logfile(); #endif /* !STANDALONE */ return ret; }