diff options
author | Sergii Dmytruk <sergii.dmytruk@3mdeb.com> | 2021-11-08 00:05:12 +0200 |
---|---|---|
committer | Anastasia Klimchuk <aklm@chromium.org> | 2022-05-12 02:56:07 +0000 |
commit | fa2cf255ec587f02baf987f21ab6d01de5db8c8e (patch) | |
tree | 00b1f34acf694f2912d7d5022acb12e1f31d64fc | |
parent | c829a48e198d723f0e6ae1ff6d6f820eb085711d (diff) | |
download | flashrom-fa2cf255ec587f02baf987f21ab6d01de5db8c8e.tar.gz flashrom-fa2cf255ec587f02baf987f21ab6d01de5db8c8e.tar.bz2 flashrom-fa2cf255ec587f02baf987f21ab6d01de5db8c8e.zip |
dummyflasher: add SR2 and SR3 emulation harness
Prepare everything for emulating SR2 and SR3 for chips that have it.
This is needed for accessing SRP1 and WPS bits which are involved in
write protection. The emulated register doesn't affect anything yet
and will be tested by write-protection tests.
TEST=check how input value affects status registers of emulated chip
flashrom -V -p dummy:emulate=W25Q128FV,spi_status=0x12 |
grep 'Initial status register'
flashrom -V -p dummy:emulate=W25Q128FV,spi_status=0x1234 |
grep 'Initial status register'
flashrom -V -p dummy:emulate=W25Q128FV,spi_status=0x123456 |
grep 'Initial status register'
Mind that at this point there are no chips that emulate more than one
status register.
Change-Id: I177ae3f068f03380f5b3941d9996a07205672e59
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/flashrom/+/59072
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Anastasia Klimchuk <aklm@chromium.org>
Reviewed-by: Thomas Heijligen <src@posteo.de>
-rw-r--r-- | dummyflasher.c | 122 | ||||
-rw-r--r-- | flashrom.8.tmpl | 5 |
2 files changed, 112 insertions, 15 deletions
diff --git a/dummyflasher.c b/dummyflasher.c index 23115764..fe2375fb 100644 --- a/dummyflasher.c +++ b/dummyflasher.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include <assert.h> #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -40,9 +41,14 @@ struct emu_data { enum emu_chip emu_chip; char *emu_persistent_image; unsigned int emu_chip_size; + /* Note: W25Q128FV doesn't change value of SR2 if it's not provided, but + * even its previous generations do, so don't forget to update + * WRSR code on enabling WRSR_EXT for more chips. */ + bool emu_wrsr_ext; int erase_to_zero; int emu_modified; /* is the image modified since reading it? */ - uint8_t emu_status; + uint8_t emu_status[3]; + uint8_t emu_status_len; /* number of emulated status registers */ /* If "freq" parameter is passed in from command line, commands will delay * for this period before returning. */ unsigned long int delay_us; @@ -158,6 +164,15 @@ static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const c return; } +static uint8_t get_reg_ro_bit_mask(enum flash_reg reg) +{ + /* Whoever adds a new register must not forget to update this function + or at least shouldn't use it incorrectly. */ + assert(reg == STATUS1 || reg == STATUS2 || reg == STATUS3); + + return reg == STATUS1 ? SPI_SR_WIP : 0; +} + static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, @@ -165,6 +180,8 @@ static int emulate_spi_chip_response(unsigned int writecnt, struct emu_data *data) { unsigned int offs, i, toread; + uint8_t ro_bits; + bool wrsr_ext; static int unsigned aai_offs; const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44}; const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a}; @@ -194,7 +211,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, } } - if (data->emu_max_aai_size && (data->emu_status & SPI_SR_AAI)) { + if (data->emu_max_aai_size && (data->emu_status[0] & SPI_SR_AAI)) { if (writearr[0] != JEDEC_AAI_WORD_PROGRAM && writearr[0] != JEDEC_WRDI && writearr[0] != JEDEC_RDSR) { @@ -304,21 +321,72 @@ static int emulate_spi_chip_response(unsigned int writecnt, } break; case JEDEC_RDSR: - memset(readarr, data->emu_status, readcnt); + memset(readarr, data->emu_status[0], readcnt); + break; + case JEDEC_RDSR2: + if (data->emu_status_len >= 2) + memset(readarr, data->emu_status[1], readcnt); + break; + case JEDEC_RDSR3: + if (data->emu_status_len >= 3) + memset(readarr, data->emu_status[2], readcnt); break; /* FIXME: this should be chip-specific. */ case JEDEC_EWSR: case JEDEC_WREN: - data->emu_status |= SPI_SR_WEL; + data->emu_status[0] |= SPI_SR_WEL; break; case JEDEC_WRSR: - if (!(data->emu_status & SPI_SR_WEL)) { + if (!(data->emu_status[0] & SPI_SR_WEL)) { msg_perr("WRSR attempted, but WEL is 0!\n"); break; } + + wrsr_ext = (writecnt == 3 && data->emu_wrsr_ext); + /* FIXME: add some reasonable simulation of the busy flag */ - data->emu_status = writearr[1] & ~SPI_SR_WIP; - msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status); + + ro_bits = get_reg_ro_bit_mask(STATUS1); + data->emu_status[0] &= ro_bits; + data->emu_status[0] |= writearr[1] & ~ro_bits; + if (wrsr_ext) { + ro_bits = get_reg_ro_bit_mask(STATUS2); + data->emu_status[1] &= ro_bits; + data->emu_status[1] |= writearr[2] & ~ro_bits; + } + + if (wrsr_ext) + 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]); + break; + case JEDEC_WRSR2: + if (data->emu_status_len < 2) + break; + if (!(data->emu_status[0] & SPI_SR_WEL)) { + msg_perr("WRSR2 attempted, but WEL is 0!\n"); + break; + } + + ro_bits = get_reg_ro_bit_mask(STATUS2); + data->emu_status[1] &= ro_bits; + data->emu_status[1] |= (writearr[1] & ~ro_bits); + + msg_pdbg2("WRSR2 wrote 0x%02x.\n", data->emu_status[1]); + break; + case JEDEC_WRSR3: + if (data->emu_status_len < 3) + break; + if (!(data->emu_status[0] & SPI_SR_WEL)) { + msg_perr("WRSR3 attempted, but WEL is 0!\n"); + break; + } + + ro_bits = get_reg_ro_bit_mask(STATUS3); + data->emu_status[2] &= ro_bits; + data->emu_status[2] |= (writearr[1] & ~ro_bits); + + msg_pdbg2("WRSR3 wrote 0x%02x.\n", data->emu_status[2]); break; case JEDEC_READ: offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; @@ -367,7 +435,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, case JEDEC_AAI_WORD_PROGRAM: if (!data->emu_max_aai_size) break; - if (!(data->emu_status & SPI_SR_AAI)) { + if (!(data->emu_status[0] & SPI_SR_AAI)) { if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) { msg_perr("Initial AAI WORD PROGRAM size too " "short!\n"); @@ -378,7 +446,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, "long!\n"); return 1; } - data->emu_status |= SPI_SR_AAI; + data->emu_status[0] |= SPI_SR_AAI; aai_offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; /* Truncate to emu_chip_size. */ @@ -403,7 +471,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, break; case JEDEC_WRDI: if (data->emu_max_aai_size) - data->emu_status &= ~SPI_SR_AAI; + data->emu_status[0] &= ~SPI_SR_AAI; break; case JEDEC_SE: if (!data->emu_jedec_se_size) @@ -531,7 +599,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, break; } if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR) - data->emu_status &= ~SPI_SR_WEL; + data->emu_status[0] &= ~SPI_SR_WEL; return 0; } @@ -811,6 +879,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_chip_size = 128 * 1024; data->emu_max_byteprogram_size = 128; data->emu_max_aai_size = 0; + data->emu_status_len = 1; data->emu_jedec_se_size = 0; data->emu_jedec_be_52_size = 0; data->emu_jedec_be_d8_size = 32 * 1024; @@ -824,6 +893,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_chip_size = 512 * 1024; data->emu_max_byteprogram_size = 1; data->emu_max_aai_size = 0; + data->emu_status_len = 1; data->emu_jedec_se_size = 4 * 1024; data->emu_jedec_be_52_size = 32 * 1024; data->emu_jedec_be_d8_size = 0; @@ -837,6 +907,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_chip_size = 4 * 1024 * 1024; data->emu_max_byteprogram_size = 1; data->emu_max_aai_size = 2; + data->emu_status_len = 1; data->emu_jedec_se_size = 4 * 1024; data->emu_jedec_be_52_size = 32 * 1024; data->emu_jedec_be_d8_size = 64 * 1024; @@ -850,6 +921,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_chip_size = 8 * 1024 * 1024; data->emu_max_byteprogram_size = 256; data->emu_max_aai_size = 0; + data->emu_status_len = 1; data->emu_jedec_se_size = 4 * 1024; data->emu_jedec_be_52_size = 32 * 1024; data->emu_jedec_be_d8_size = 64 * 1024; @@ -863,6 +935,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_chip_size = 16 * 1024 * 1024; data->emu_max_byteprogram_size = 256; data->emu_max_aai_size = 0; + data->emu_status_len = 1; data->emu_jedec_se_size = 4 * 1024; data->emu_jedec_be_52_size = 32 * 1024; data->emu_jedec_be_d8_size = 64 * 1024; @@ -884,6 +957,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_chip_size = size; data->emu_max_byteprogram_size = 256; data->emu_max_aai_size = 0; + data->emu_status_len = 1; data->emu_jedec_se_size = 4 * 1024; data->emu_jedec_be_52_size = 32 * 1024; data->emu_jedec_be_d8_size = 64 * 1024; @@ -918,8 +992,10 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor status = extract_programmer_param("spi_status"); if (status) { + unsigned int emu_status; + errno = 0; - data->emu_status = strtoul(status, &endptr, 0); + emu_status = strtoul(status, &endptr, 0); if (errno != 0 || status == endptr) { free(status); msg_perr("Error: initial status register specified, " @@ -927,8 +1003,26 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor return 1; } free(status); - msg_pdbg("Initial status register is set to 0x%02x.\n", - data->emu_status); + + data->emu_status[0] = emu_status; + data->emu_status[1] = emu_status >> 8; + data->emu_status[2] = emu_status >> 16; + + if (data->emu_status_len == 3) { + msg_pdbg("Initial status registers:\n" + "\tSR1 is set to 0x%02x\n" + "\tSR2 is set to 0x%02x\n" + "\tSR3 is set to 0x%02x\n", + data->emu_status[0], data->emu_status[1], data->emu_status[2]); + } else if (data->emu_status_len == 2) { + msg_pdbg("Initial status registers:\n" + "\tSR1 is set to 0x%02x\n" + "\tSR2 is set to 0x%02x\n", + data->emu_status[0], data->emu_status[1]); + } else { + msg_pdbg("Initial status register is set to 0x%02x.\n", + data->emu_status[0]); + } } data->flashchip_contents = malloc(data->emu_chip_size); diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 84e0fba3..0f7bc974 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -816,7 +816,10 @@ You can specify the initial content of the chip's status register with the .sp syntax where .B content -is an 8-bit hexadecimal value. +is a hexadecimal value of up to 24 bits. For example, 0x332211 assigns 0x11 to +SR1, 0x22 to SR2 and 0x33 to SR3. Shorter value is padded to 24 bits with +zeroes on the left. See datasheet for chosen chip for details about the +registers content. .SS .BR "nic3com" , " nicrealtek" , " nicnatsemi" , " nicintel", " nicintel_eeprom"\ , " nicintel_spi" , " gfxnvidia" , " ogp_spi" , " drkaiser" , " satasii"\ |