1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-27 07:02:34 +02:00

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>
This commit is contained in:
Sergii Dmytruk 2021-11-08 00:05:12 +02:00 committed by Anastasia Klimchuk
parent c829a48e19
commit fa2cf255ec
2 changed files with 112 additions and 15 deletions

View File

@ -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);

View File

@ -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"\