int main(int argc, char *argv[]) { const char *pname = argv[0]; uint32_t address = 0, read_size = 0, write_size = 0; uint32_t erase_start = 0, erase_size = 0; bool erase = false, do_clear = false; bool program = false, erase_all = false, info = false, do_read = false; bool enable_4B = false, disable_4B = false; bool show_help = false, show_version = false; bool no_action = false, tune = false; char *write_file = NULL, *read_file = NULL, *part_name = NULL; bool ffs_toc_seen = false; int rc; while(1) { static struct option long_opts[] = { {"address", required_argument, NULL, 'a'}, {"size", required_argument, NULL, 's'}, {"partition", required_argument, NULL, 'P'}, {"bmc", no_argument, NULL, 'b'}, {"enable-4B", no_argument, NULL, '4'}, {"disable-4B", no_argument, NULL, '3'}, {"read", required_argument, NULL, 'r'}, {"erase-all", no_argument, NULL, 'E'}, {"erase", no_argument, NULL, 'e'}, {"program", required_argument, NULL, 'p'}, {"force", no_argument, NULL, 'f'}, {"info", no_argument, NULL, 'i'}, {"tune", no_argument, NULL, 't'}, {"dummy", no_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {"debug", no_argument, NULL, 'g'}, {"side", required_argument, NULL, 'S'}, {"toc", required_argument, NULL, 'T'}, {"clear", no_argument, NULL, 'c'} }; int c, oidx = 0; c = getopt_long(argc, argv, "a:s:P:r:43Eep:fdihvbtgS:T:c", long_opts, &oidx); if (c == EOF) break; switch(c) { case 'a': address = strtoul(optarg, NULL, 0); break; case 's': read_size = write_size = strtoul(optarg, NULL, 0); break; case 'P': part_name = strdup(optarg); break; case '4': enable_4B = true; break; case '3': disable_4B = true; break; case 'r': do_read = true; read_file = strdup(optarg); break; case 'E': erase_all = erase = true; break; case 'e': erase = true; break; case 'p': program = true; write_file = strdup(optarg); break; case 'f': must_confirm = false; break; case 'd': must_confirm = false; dummy_run = true; break; case 'i': info = true; break; case 'b': bmc_flash = true; break; case 't': tune = true; break; case 'v': show_version = true; break; case 'h': show_help = show_version = true; break; case 'g': libflash_debug = true; break; case 'S': flash_side = atoi(optarg); break; case 'T': ffs_toc_seen = true; ffs_toc = strtoul(optarg, NULL, 0); break; case 'c': do_clear = true; break; default: exit(1); } } /* Check if we need to access the flash at all (which will * also tune them as a side effect */ no_action = !erase && !program && !info && !do_read && !enable_4B && !disable_4B && !tune && !do_clear; /* Nothing to do, if we didn't already, print usage */ if (no_action && !show_version) show_help = show_version = true; if (show_version) print_version(); if (show_help) print_help(pname); if (no_action) return 0; /* --enable-4B and --disable-4B are mutually exclusive */ if (enable_4B && disable_4B) { fprintf(stderr, "--enable-4B and --disable-4B are mutually" " exclusive !\n"); exit(1); } /* 4B not supported on BMC flash */ if (enable_4B && bmc_flash) { fprintf(stderr, "--enable-4B not supported on BMC flash !\n"); exit(1); } /* partitions not supported on BMC flash */ if (part_name && bmc_flash) { fprintf(stderr, "--partition not supported on BMC flash !\n"); exit(1); } /* part-name and erase-all make no sense together */ if (part_name && erase_all) { fprintf(stderr, "--partition and --erase-all are mutually" " exclusive !\n"); exit(1); } /* Read command should always come with a file */ if (do_read && !read_file) { fprintf(stderr, "Read with no file specified !\n"); exit(1); } /* Program command should always come with a file */ if (program && !write_file) { fprintf(stderr, "Program with no file specified !\n"); exit(1); } /* If both partition and address specified, error out */ if (address && part_name) { fprintf(stderr, "Specify partition or address, not both !\n"); exit(1); } if (do_clear && !part_name) { fprintf(stderr, "--clear only supported on a partition name\n"); exit(1); } /* Explicitly only support two sides */ if (flash_side != 0 && flash_side != 1) { fprintf(stderr, "Unexpected value for --side '%d'\n", flash_side); exit(1); } if (ffs_toc_seen && flash_side) { fprintf(stderr, "--toc and --side are exclusive"); exit(1); } /* If file specified but not size, get size from file */ if (write_file && !write_size) { struct stat stbuf; if (stat(write_file, &stbuf)) { perror("Failed to get file size"); exit(1); } write_size = stbuf.st_size; } if (bmc_flash) { if (arch_flash_bmc(NULL, 1) == -1) { fprintf(stderr, "Can't switch to BMC flash on this architecture\n"); exit(1); } } if (arch_flash_init(&bl, NULL, true)) exit(1); on_exit(exiting, NULL); rc = blocklevel_get_info(bl, &fl_name, &fl_total_size, &fl_erase_granule); if (rc) { fprintf(stderr, "Error %d getting flash info\n", rc); exit(1); } /* If -t is passed, then print a nice message */ if (tune) printf("Flash and controller tuned\n"); /* If read specified and no read_size, use flash size */ if (do_read && !read_size && !part_name) read_size = fl_total_size; /* We have a partition specified, grab the details */ if (part_name) lookup_partition(part_name); /* We have a partition, adjust read/write size if needed */ if (ffsh && ffs_index >= 0) { uint32_t pstart, pmaxsz, pactsize; bool ecc; int rc; rc = ffs_part_info(ffsh, ffs_index, NULL, &pstart, &pmaxsz, &pactsize, &ecc); if (rc) { fprintf(stderr,"Failed to get partition info\n"); exit(1); } if (!ecc && do_clear) { fprintf(stderr, "The partition on which to do --clear " "does not have ECC, are you sure?\n"); check_confirm(); /* Still confirm later on */ must_confirm = true; } /* Read size is obtained from partition "actual" size */ if (!read_size) read_size = pactsize; /* Write size is max size of partition */ if (!write_size) write_size = pmaxsz; /* Crop write size to partition size */ if (write_size > pmaxsz) { printf("WARNING: Size (%d bytes) larger than partition" " (%d bytes), cropping to fit\n", write_size, pmaxsz); write_size = pmaxsz; } /* If erasing, check partition alignment */ if (erase && ((pstart | pmaxsz) & 0xfff)) { fprintf(stderr,"Partition not aligned properly\n"); exit(1); } /* Set address */ address = pstart; } /* Align erase boundaries */ if (erase && !erase_all) { uint32_t mask = 0xfff; uint32_t erase_end; /* Dummy size for erase, will be adjusted later */ if (!write_size) write_size = 1; erase_start = address & ~mask; erase_end = ((address + write_size) + mask) & ~mask; erase_size = erase_end - erase_start; if (erase_start != address || erase_size != write_size) fprintf(stderr, "WARNING: Erase region adjusted" " to 0x%08x..0x%08x\n", erase_start, erase_end); } /* Process commands */ if (enable_4B) enable_4B_addresses(); if (disable_4B) disable_4B_addresses(); if (info) { /* * Don't pass through modfied TOC value if the modification was done * because of --size, but still respect if it came from --toc (we * assume the user knows what they're doing in that case) */ print_flash_info(flash_side ? 0 : ffs_toc); } /* Unlock flash (PNOR only) */ if ((erase || program || do_clear) && !bmc_flash) { need_relock = arch_flash_set_wrprotect(bl, false); if (need_relock == -1) { fprintf(stderr, "Architecture doesn't support write protection on flash\n"); need_relock = 0; exit (1); } } if (do_read) do_read_file(read_file, address, read_size); if (erase_all) erase_chip(); else if (erase) erase_range(erase_start, erase_size, program); if (program) program_file(write_file, address, write_size); if (do_clear) set_ecc(address, write_size); return 0; }
uint8_t flash(FlashControl* flash_control,bool bmc_flash, uint32_t address, char* write_file, char* obj_path) { bool has_sfc = false, has_ast = false, use_lpc = true; bool erase = true, program = true; int rc; printf("flasher: %s, BMC = %d, address = 0x%x\n",write_file,bmc_flash,address); #ifdef __arm__ /* Check platform */ check_platform(&has_sfc, &has_ast); /* Prepare for access */ if(bmc_flash) { if(!has_ast) { fprintf(stderr, "No BMC on this platform\n"); return FLASH_SETUP_ERROR; } rc = flash_access_setup_bmc(use_lpc, erase || program); if(rc) { return FLASH_SETUP_ERROR; } } else { if(!has_ast && !has_sfc) { fprintf(stderr, "No BMC nor SFC on this platform\n"); return FLASH_SETUP_ERROR; } rc = flash_access_setup_pnor(use_lpc, has_sfc, erase || program); if(rc) { return FLASH_SETUP_ERROR; } } rc = flash_get_info(fl_chip, &fl_name, &fl_total_size, &fl_erase_granule); if(rc) { fprintf(stderr, "Error %d getting flash info\n", rc); return FLASH_SETUP_ERROR; } #endif if(strcmp(write_file,"")!=0) { // If file specified but not size, get size from file struct stat stbuf; if(stat(write_file, &stbuf)) { perror("Failed to get file size"); return FLASH_ERROR; } uint32_t write_size = stbuf.st_size; #ifdef __arm__ rc = erase_chip(); if(rc) { return FLASH_ERROR; } rc = program_file(flash_control, write_file, address, write_size); if(rc) { return FLASH_ERROR; } #endif printf("Flash done\n"); } else { printf("Flash tuned\n"); } return FLASH_OK; }