aboutsummaryrefslogtreecommitdiffstats
path: root/dummyflasher.c
diff options
context:
space:
mode:
authorSergii Dmytruk <sergii.dmytruk@3mdeb.com>2021-11-08 00:05:12 +0200
committerAnastasia Klimchuk <aklm@chromium.org>2022-05-12 02:56:07 +0000
commitfa2cf255ec587f02baf987f21ab6d01de5db8c8e (patch)
tree00b1f34acf694f2912d7d5022acb12e1f31d64fc /dummyflasher.c
parentc829a48e198d723f0e6ae1ff6d6f820eb085711d (diff)
downloadflashrom-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>
Diffstat (limited to 'dummyflasher.c')
-rw-r--r--dummyflasher.c122
1 files changed, 108 insertions, 14 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);