diff --git a/modules/script/script.c b/modules/script/script.c index 2728a48..a9fc89a 100644 --- a/modules/script/script.c +++ b/modules/script/script.c @@ -3080,40 +3080,70 @@ static int cmd_flash_detect(script_ctx *ctx, char *line) return JTAG_CORE_NO_ERROR; } +/* Set up the proxy transport and detect the flash. Returns NO_ERROR with + * sf->chip set, or an error code (with a message already printed). */ +static int flash_setup_detected(script_ctx *ctx, int device, + spi_flash *sf, struct flash_proxy_ctx *pc) +{ + int r = flash_setup(ctx, device, sf, pc); + if (r != JTAG_CORE_NO_ERROR) return r; + if (spi_flash_detect(sf) < 0 || !sf->chip) { + ctx->script_printf(ctx, MSG_ERROR, "Flash not detected/known - run flash_detect first.\n"); + return JTAG_CORE_NOT_FOUND; + } + return JTAG_CORE_NO_ERROR; +} + +/* Read a whole file into a malloc'd buffer. Caller frees. */ +static uint8_t *read_file(const char *path, size_t *out_len) +{ + FILE *f = fopen(path, "rb"); + long sz; + uint8_t *b; + if (!f) return NULL; + if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; } + sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return NULL; } + b = malloc((size_t)sz); + if (!b) { fclose(f); return NULL; } + if (fread(b, 1, (size_t)sz, f) != (size_t)sz) { free(b); fclose(f); return NULL; } + fclose(f); + *out_len = (size_t)sz; + return b; +} + const char *cmd_flash_read_help[] = { - " ", - "Read bytes from the SPI flash at (hex) and hex-dump them.", - "Read-only. Requires a proxy loaded and a flash recognised by flash_detect.", + " [file]", + "Read bytes from the SPI flash at (hex). With [file], dump", + "the raw bytes to it (e.g. to back up before erasing); otherwise hex-dump.", + "Read-only. Requires a proxy loaded and a flash known to flash_detect.", ""}; static int cmd_flash_read(script_ctx *ctx, char *line) { - char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], len_txt[DEFAULT_BUFLEN]; + char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], len_txt[DEFAULT_BUFLEN], file[DEFAULT_BUFLEN]; struct flash_proxy_ctx pc; spi_flash sf; uint8_t *buf; uint32_t addr; size_t len, i; - int device, r; + int device, r, to_file; if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || get_param(ctx, line, 3, len_txt) < 0) { - ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_read \n"); + ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_read [file]\n"); return JTAG_CORE_BAD_PARAMETER; } + to_file = (get_param(ctx, line, 4, file) > 0); device = (int)strtoul(dev_txt, NULL, 0); addr = (uint32_t)strtoul(addr_txt, NULL, 0); len = (size_t)strtoul(len_txt, NULL, 0); if (len == 0) return JTAG_CORE_NO_ERROR; - if (len > 65536) { - ctx->script_printf(ctx, MSG_ERROR, "flash_read: len capped at 65536 for an interactive dump\n"); + if (!to_file && len > 65536) { + ctx->script_printf(ctx, MSG_ERROR, "flash_read: len capped at 65536 for a hex dump (use a file for more)\n"); return JTAG_CORE_BAD_PARAMETER; } - if ((r = flash_setup(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; - - if (spi_flash_detect(&sf) < 0 || !sf.chip) { - ctx->script_printf(ctx, MSG_ERROR, "Flash not detected/known — run flash_detect first.\n"); - return JTAG_CORE_NOT_FOUND; - } + if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; buf = malloc(len); if (!buf) return JTAG_CORE_BAD_PARAMETER; @@ -3123,6 +3153,20 @@ static int cmd_flash_read(script_ctx *ctx, char *line) return JTAG_CORE_IO_ERROR; } + if (to_file) { + FILE *f = fopen(file, "wb"); + size_t wr = 0; + if (f) { wr = fwrite(buf, 1, len, f); fclose(f); } + free(buf); + if (!f || wr != len) { + ctx->script_printf(ctx, MSG_ERROR, "Can't write %s\n", file); + return JTAG_CORE_IO_ERROR; + } + ctx->script_printf(ctx, MSG_INFO_0, "Read %lu bytes from 0x%.8X to %s\n", + (unsigned long)len, (unsigned)addr, file); + return JTAG_CORE_NO_ERROR; + } + for (i = 0; i < len; i += 16) { char linebuf[16 * 3 + 16]; size_t j, pos = 0; @@ -3136,6 +3180,130 @@ static int cmd_flash_read(script_ctx *ctx, char *line) return JTAG_CORE_NO_ERROR; } +const char *cmd_flash_erase_help[] = { + " ", + "Erase the flash sectors covering [addr, addr+len) (hex). DESTRUCTIVE.", + "Requires a proxy loaded and a flash known to flash_detect.", + ""}; +static int cmd_flash_erase(script_ctx *ctx, char *line) +{ + char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], len_txt[DEFAULT_BUFLEN]; + struct flash_proxy_ctx pc; + spi_flash sf; + uint32_t addr, end, a, ss; + size_t len; + int device, r, nsec = 0; + + if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || + get_param(ctx, line, 3, len_txt) < 0) { + ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_erase \n"); + return JTAG_CORE_BAD_PARAMETER; + } + device = (int)strtoul(dev_txt, NULL, 0); + addr = (uint32_t)strtoul(addr_txt, NULL, 0); + len = (size_t)strtoul(len_txt, NULL, 0); + if (len == 0) return JTAG_CORE_NO_ERROR; + if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; + + ss = sf.chip->sector_size; + end = addr + (uint32_t)len; /* exclusive */ + for (a = addr - (addr % ss); a < end; a += ss) { + if (spi_flash_erase_sector(&sf, a) < 0) { + ctx->script_printf(ctx, MSG_ERROR, "Erase failed at 0x%.8X\n", a); + return JTAG_CORE_IO_ERROR; + } + nsec++; + } + ctx->script_printf(ctx, MSG_INFO_0, "Erased %d sector(s) of %u B from 0x%.8X\n", + nsec, ss, addr - (addr % ss)); + return JTAG_CORE_NO_ERROR; +} + +const char *cmd_flash_write_help[] = { + " ", + "Program the flash at (hex) with the contents of . DESTRUCTIVE.", + "Does NOT erase first - run flash_erase over the range beforehand.", + ""}; +static int cmd_flash_write(script_ctx *ctx, char *line) +{ + char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], file[DEFAULT_BUFLEN]; + struct flash_proxy_ctx pc; + spi_flash sf; + uint8_t *data; + uint32_t addr; + size_t len = 0; + int device, r; + + if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || + get_param(ctx, line, 3, file) < 0) { + ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_write \n"); + return JTAG_CORE_BAD_PARAMETER; + } + device = (int)strtoul(dev_txt, NULL, 0); + addr = (uint32_t)strtoul(addr_txt, NULL, 0); + if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; + + data = read_file(file, &len); + if (!data) { + ctx->script_printf(ctx, MSG_ERROR, "Can't read %s\n", file); + return JTAG_CORE_IO_ERROR; + } + if (spi_flash_program(&sf, addr, data, len) < 0) { + free(data); + ctx->script_printf(ctx, MSG_ERROR, "spi_flash_program failed\n"); + return JTAG_CORE_IO_ERROR; + } + free(data); + ctx->script_printf(ctx, MSG_INFO_0, "Wrote %lu bytes to 0x%.8X\n", + (unsigned long)len, (unsigned)addr); + return JTAG_CORE_NO_ERROR; +} + +const char *cmd_flash_verify_help[] = { + " ", + "Compare the flash content at (hex) against .", + ""}; +static int cmd_flash_verify(script_ctx *ctx, char *line) +{ + char dev_txt[DEFAULT_BUFLEN], addr_txt[DEFAULT_BUFLEN], file[DEFAULT_BUFLEN]; + struct flash_proxy_ctx pc; + spi_flash sf; + uint8_t *data; + uint32_t addr, mismatch = 0; + size_t len = 0; + int device, r; + + if (get_param(ctx, line, 1, dev_txt) < 0 || get_param(ctx, line, 2, addr_txt) < 0 || + get_param(ctx, line, 3, file) < 0) { + ctx->script_printf(ctx, MSG_ERROR, "Usage: flash_verify \n"); + return JTAG_CORE_BAD_PARAMETER; + } + device = (int)strtoul(dev_txt, NULL, 0); + addr = (uint32_t)strtoul(addr_txt, NULL, 0); + if ((r = flash_setup_detected(ctx, device, &sf, &pc)) != JTAG_CORE_NO_ERROR) return r; + + data = read_file(file, &len); + if (!data) { + ctx->script_printf(ctx, MSG_ERROR, "Can't read %s\n", file); + return JTAG_CORE_IO_ERROR; + } + r = spi_flash_verify(&sf, addr, data, len, &mismatch); + free(data); + if (r < 0) { + ctx->script_printf(ctx, MSG_ERROR, "spi_flash_verify failed\n"); + return JTAG_CORE_IO_ERROR; + } + ctx->last_data_value = r; /* 0 = match, 1 = mismatch */ + if (r == 1) { + ctx->script_printf(ctx, MSG_WARNING, + "Verify MISMATCH at offset 0x%X (flash 0x%.8X)\n", + (unsigned)mismatch, (unsigned)(addr + mismatch)); + return JTAG_CORE_NO_ERROR; + } + ctx->script_printf(ctx, MSG_INFO_0, "Verify OK (%lu bytes)\n", (unsigned long)len); + return JTAG_CORE_NO_ERROR; +} + cmd_list script_commands_list[] = { {"print", cmd_print, cmd_print_help}, @@ -3186,6 +3354,9 @@ cmd_list script_commands_list[] = {"bscan_jedec", cmd_bscan_jedec, cmd_bscan_jedec_help}, {"flash_detect", cmd_flash_detect, cmd_flash_detect_help}, {"flash_read", cmd_flash_read, cmd_flash_read_help}, + {"flash_erase", cmd_flash_erase, cmd_flash_erase_help}, + {"flash_write", cmd_flash_write, cmd_flash_write_help}, + {"flash_verify", cmd_flash_verify, cmd_flash_verify_help}, {0, 0}}; ///////////////////////////////////////////////////////////////////////////////