diff options
Diffstat (limited to 'dummyflasher.c')
-rw-r--r-- | dummyflasher.c | 160 |
1 files changed, 142 insertions, 18 deletions
diff --git a/dummyflasher.c b/dummyflasher.c index 63231392..1ee9d3ea 100644 --- a/dummyflasher.c +++ b/dummyflasher.c @@ -26,6 +26,7 @@ #include "programmer.h" #include "flashchips.h" #include "spi.h" +#include "writeprotect.h" enum emu_chip { EMULATE_NONE, @@ -64,6 +65,11 @@ struct emu_data { unsigned int spi_blacklist_size; unsigned int spi_ignorelist_size; + bool hwwp; /* state of hardware write protection */ + /* wp_start == wp_end when write-protection is disabled */ + uint32_t wp_start; + uint32_t wp_end; + unsigned int spi_write_256_chunksize; uint8_t *flashchip_contents; }; @@ -173,7 +179,14 @@ static uint8_t get_reg_ro_bit_mask(const struct emu_data *data, enum flash_reg r uint8_t ro_bits = reg == STATUS1 ? SPI_SR_WIP : 0; if (data->emu_chip == EMULATE_WINBOND_W25Q128FV) { - if (reg == STATUS2) { + const bool srp0 = (data->emu_status[0] >> 7); + const bool srp1 = (data->emu_status[1] & 1); + + const bool wp_active = (srp1 || (srp0 && data->hwwp)); + + if (wp_active) { + ro_bits = 0xff; + } else if (reg == STATUS2) { /* SUS (bit_7) and (R) (bit_2). */ ro_bits = 0x84; /* Once any of the lock bits (LB[1..3]) are set, they @@ -190,6 +203,79 @@ static uint8_t get_reg_ro_bit_mask(const struct emu_data *data, enum flash_reg r return ro_bits; } +static void update_write_protection(struct emu_data *data) +{ + if (data->emu_chip != EMULATE_WINBOND_W25Q128FV) + return; + + const struct wp_bits bits = { + .srp = data->emu_status[0] >> 7, + .srl = data->emu_status[1] & 1, + + .bp_bit_count = 3, + .bp = + { + (data->emu_status[0] >> 2) & 1, + (data->emu_status[0] >> 3) & 1, + (data->emu_status[0] >> 4) & 1 + }, + + .tb_bit_present = true, + .tb = (data->emu_status[0] >> 5) & 1, + + .sec_bit_present = true, + .sec = (data->emu_status[0] >> 6) & 1, + + .cmp_bit_present = true, + .cmp = (data->emu_status[1] >> 6) & 1, + }; + + size_t start; + size_t len; + decode_range_spi25(&start, &len, &bits, data->emu_chip_size); + + data->wp_start = start; + data->wp_end = start + len; +} + +/* Checks whether range intersects a write-protected area of the flash if one is + * defined. */ +static bool is_write_protected(const struct emu_data *data, uint32_t start, uint32_t len) +{ + if (len == 0) + return false; + + const uint32_t last = start + len - 1; + return (start < data->wp_end && last >= data->wp_start); +} + +/* Returns non-zero on error. */ +static int write_flash_data(struct emu_data *data, uint32_t start, uint32_t len, const uint8_t *buf) +{ + if (is_write_protected(data, start, len)) { + msg_perr("At least part of the write range is write protected!\n"); + return 1; + } + + memcpy(data->flashchip_contents + start, buf, len); + data->emu_modified = 1; + return 0; +} + +/* Returns non-zero on error. */ +static int erase_flash_data(struct emu_data *data, uint32_t start, uint32_t len) +{ + if (is_write_protected(data, start, len)) { + msg_perr("At least part of the erase range is write protected!\n"); + return 1; + } + + /* FIXME: take data->erase_to_zero into account. */ + memset(data->flashchip_contents + start, 0xff, len); + data->emu_modified = 1; + return 0; +} + static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, @@ -376,6 +462,8 @@ static int emulate_spi_chip_response(unsigned int writecnt, msg_pdbg2("WRSR wrote 0x%02x%02x.\n", data->emu_status[1], data->emu_status[0]); else msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status[0]); + + update_write_protection(data); break; case JEDEC_WRSR2: if (data->emu_status_len < 2) @@ -390,6 +478,8 @@ static int emulate_spi_chip_response(unsigned int writecnt, data->emu_status[1] |= (writearr[1] & ~ro_bits); msg_pdbg2("WRSR2 wrote 0x%02x.\n", data->emu_status[1]); + + update_write_protection(data); break; case JEDEC_WRSR3: if (data->emu_status_len < 3) @@ -431,8 +521,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, msg_perr("Max BYTE PROGRAM size exceeded!\n"); return 1; } - memcpy(data->flashchip_contents + offs, writearr + 4, writecnt - 4); - data->emu_modified = 1; + if (write_flash_data(data, offs, writecnt - 4, writearr + 4)) { + msg_perr("Failed to program flash!\n"); + return 1; + } break; case JEDEC_BYTE_PROGRAM_4BA: offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4]; @@ -446,8 +538,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, msg_perr("Max BYTE PROGRAM size exceeded!\n"); return 1; } - memcpy(data->flashchip_contents + offs, writearr + 5, writecnt - 5); - data->emu_modified = 1; + if (write_flash_data(data, offs, writecnt - 5, writearr + 5)) { + msg_perr("Failed to program flash!\n"); + return 1; + } break; case JEDEC_AAI_WORD_PROGRAM: if (!data->emu_max_aai_size) @@ -468,7 +562,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, writearr[3]; /* Truncate to emu_chip_size. */ aai_offs %= data->emu_chip_size; - memcpy(data->flashchip_contents + aai_offs, writearr + 4, 2); + if (write_flash_data(data, aai_offs, 2, writearr + 4)) { + msg_perr("Failed to program flash!\n"); + return 1; + } aai_offs += 2; } else { if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) { @@ -481,10 +578,12 @@ static int emulate_spi_chip_response(unsigned int writecnt, "too long!\n"); return 1; } - memcpy(data->flashchip_contents + aai_offs, writearr + 1, 2); + if (write_flash_data(data, aai_offs, 2, writearr + 1)) { + msg_perr("Failed to program flash!\n"); + return 1; + } aai_offs += 2; } - data->emu_modified = 1; break; case JEDEC_WRDI: if (data->emu_max_aai_size) @@ -505,8 +604,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, if (offs & (data->emu_jedec_se_size - 1)) msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs); offs &= ~(data->emu_jedec_se_size - 1); - memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_se_size); - data->emu_modified = 1; + if (erase_flash_data(data, offs, data->emu_jedec_se_size)) { + msg_perr("Failed to erase flash!\n"); + return 1; + } break; case JEDEC_BE_52: if (!data->emu_jedec_be_52_size) @@ -523,8 +624,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, if (offs & (data->emu_jedec_be_52_size - 1)) msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs); offs &= ~(data->emu_jedec_be_52_size - 1); - memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size); - data->emu_modified = 1; + if (erase_flash_data(data, offs, data->emu_jedec_be_52_size)) { + msg_perr("Failed to erase flash!\n"); + return 1; + } break; case JEDEC_BE_D8: if (!data->emu_jedec_be_d8_size) @@ -541,8 +644,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, if (offs & (data->emu_jedec_be_d8_size - 1)) msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs); offs &= ~(data->emu_jedec_be_d8_size - 1); - memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size); - data->emu_modified = 1; + if (erase_flash_data(data, offs, data->emu_jedec_be_d8_size)) { + msg_perr("Failed to erase flash!\n"); + return 1; + } break; case JEDEC_CE_60: if (!data->emu_jedec_ce_60_size) @@ -557,8 +662,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, } /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */ /* emu_jedec_ce_60_size is emu_chip_size. */ - memset(data->flashchip_contents, 0xff, data->emu_jedec_ce_60_size); - data->emu_modified = 1; + if (erase_flash_data(data, 0, data->emu_jedec_ce_60_size)) { + msg_perr("Failed to erase flash!\n"); + return 1; + } break; case JEDEC_CE_C7: if (!data->emu_jedec_ce_c7_size) @@ -573,8 +680,10 @@ static int emulate_spi_chip_response(unsigned int writecnt, } /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */ /* emu_jedec_ce_c7_size is emu_chip_size. */ - memset(data->flashchip_contents, 0xff, data->emu_jedec_ce_c7_size); - data->emu_modified = 1; + if (erase_flash_data(data, 0, data->emu_jedec_ce_c7_size)) { + msg_perr("Failed to erase flash!\n"); + return 1; + } break; case JEDEC_SFDP: if (data->emu_chip != EMULATE_MACRONIX_MX25L6436) @@ -884,6 +993,21 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor free(tmp); } + tmp = extract_programmer_param("hwwp"); + if (tmp) { + if (!strcmp(tmp, "yes")) { + msg_pdbg("Emulated chip will have hardware WP enabled\n"); + data->hwwp = true; + } else if (!strcmp(tmp, "no")) { + msg_pdbg("Emulated chip will have hardware WP disabled\n"); + } else { + msg_perr("hwwp can be \"yes\" or \"no\"\n"); + free(tmp); + return 1; + } + free(tmp); + } + tmp = extract_programmer_param("emulate"); if (!tmp) { msg_pdbg("Not emulating any flash chip.\n"); |