From a721181a08430836352cb23a544e92fdc8d55b99 Mon Sep 17 00:00:00 2001 From: Anastasia Klimchuk Date: Thu, 19 May 2022 14:40:37 +1000 Subject: dummyflasher: Wire variable size feature via opaque infra Wire "variable size" feature in dummy programmer via opaque infra. This patch fixes the broken build with CONFIG_DUMMY=no. Dummyflasher registers opaque master for the case when it is initialised with EMULATE_VARIABLE_SIZE. Dummy opaque master emulates read/write/erase as simple memory operations over `data->flashchip_contents`. The feature works via "Opaque flash chip" in flashchips.c which has one block eraser at the moment. If this changes in future, each block eraser needs to be updated in `probe_variable_size`. Fixes: https://ticket.coreboot.org/issues/365 TEST=the following scenarious run successfully Testing build $ make clean && make CONFIG_DUMMY=no $ flashrom -h : dummy is not in the list $ make clean && make CONFIG_EVERYTHING=yes $ flashrom -h : dummy is in the list Testing "variable size" feature $ flashrom -p dummy:size=8388608,emulate=VARIABLE_SIZE -V $ flashrom -p dummy:size=8388608,emulate=VARIABLE_SIZE -r /tmp/dump.bin -V $ head -c 8388608 /tmp/image.bin $ flashrom -p dummy:image=/tmp/image.bin,size=8388608,emulate=VARIABLE_SIZE -w /tmp/dump.bin -V also same as above with erase_to_zero=yes Testing standard flow $ flashrom -p dummy:emulate=W25Q128FV -V $ flashrom -p dummy:emulate=W25Q128FV -r /tmp/dump.bin -V $ head -c 16777216 /tmp/image.bin $ flashrom -p dummy:image=/tmp/image.bin,emulate=W25Q128FV -w /tmp/dump.bin -V Testing invalid combination of programmer params (`init_data` fails and prints error message which is WAI) $ flashrom -p dummy:size=8388608 -V -> init_data: size parameter is only valid for VARIABLE_SIZE chip. $ flashrom -p dummy:emulate=VARIABLE_SIZE -V -> init_data: the size parameter is not given. $ flashrom -p dummy:emulate=W25Q128FV,erase_to_zero=yes -V -> init_data: erase_to_zero parameter is not valid for real chip. Change-Id: I76402bfdf8b1a75489e4509fec92c9a777d0cf58 Signed-off-by: Anastasia Klimchuk Reviewed-on: https://review.coreboot.org/c/flashrom/+/64488 Tested-by: build bot (Jenkins) Reviewed-by: Nico Huber Reviewed-by: Edward O'Callaghan --- dummyflasher.c | 140 ++++++++++++++++++++++++++++++++++---------------- flashchips.c | 22 -------- include/chipdrivers.h | 3 -- 3 files changed, 95 insertions(+), 70 deletions(-) diff --git a/dummyflasher.c b/dummyflasher.c index 50a84d46..0a2d9210 100644 --- a/dummyflasher.c +++ b/dummyflasher.c @@ -119,6 +119,72 @@ static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsig emu_data->spi_write_256_chunksize); } +static int probe_variable_size(struct flashctx *flash) +{ + const struct emu_data *emu_data = flash->mst->opaque.data; + + /* Skip the probing if we don't emulate "variable size" chip. */ + if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE) + return 0; + + flash->chip->total_size = emu_data->emu_chip_size / 1024; + msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__, + flash->chip->total_size); + + flash->chip->tested = TEST_OK_PREW; + + if (emu_data->erase_to_zero) + flash->chip->feature_bits |= FEATURE_ERASED_ZERO; + + /* + * Update the first count of the block_eraser. + * Opaque flash chip entry in flashchips.c has only one block eraser. + * + * If this changes in future, the code below needs to be adjusted + * to update all block erasers. + */ + struct block_eraser *eraser = &flash->chip->block_erasers[0]; + if (!eraser->block_erase) + return 1; + + eraser->eraseblocks[0].count = 1; + eraser->eraseblocks[0].size = emu_data->emu_chip_size; + msg_cdbg("%s: eraser.size=%d, .count=%d\n", + __func__, eraser->eraseblocks[0].size, + eraser->eraseblocks[0].count); + + return 1; +} + +static int dummy_opaque_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) +{ + const struct emu_data *emu_data = flash->mst->opaque.data; + + memcpy(buf, emu_data->flashchip_contents + start, len); + + return 0; +} + +static int dummy_opaque_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) +{ + struct emu_data *emu_data = flash->mst->opaque.data; + + memcpy(emu_data->flashchip_contents + start, buf, len); + emu_data->emu_modified = 1; + + return 0; +} + +static int dummy_opaque_erase(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ + struct emu_data *emu_data = flash->mst->opaque.data; + + memset(emu_data->flashchip_contents + blockaddr, emu_data->erase_to_zero ? 0x00 : 0xff, blocklen); + emu_data->emu_modified = 1; + + return 0; +} + static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr) { msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%02x\n", __func__, addr, val); @@ -270,7 +336,7 @@ static int erase_flash_data(struct emu_data *data, uint32_t start, uint32_t len) return 1; } - /* FIXME: take data->erase_to_zero into account. */ + /* FIXME: Maybe use ERASED_VALUE(flash) instead of 0xff ? */ memset(data->flashchip_contents + start, 0xff, len); data->emu_modified = 1; return 0; @@ -814,6 +880,13 @@ static const struct par_master par_master_dummyflasher = { .chip_writen = dummy_chip_writen, }; +static const struct opaque_master opaque_master_dummyflasher = { + .probe = probe_variable_size, + .read = dummy_opaque_read, + .write = dummy_opaque_write, + .erase = dummy_opaque_erase, +}; + static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_supported) { @@ -827,7 +900,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor bustext = extract_programmer_param("bus"); msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default"); if (!bustext) - bustext = strdup("parallel+lpc+fwh+spi"); + bustext = strdup("parallel+lpc+fwh+spi+prog"); /* Convert the parameters to lowercase. */ tolower_string(bustext); @@ -848,6 +921,10 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor *dummy_buses_supported |= BUS_SPI; msg_pdbg("Enabling support for %s flash.\n", "SPI"); } + if (strstr(bustext, "prog")) { + *dummy_buses_supported |= BUS_PROG; + msg_pdbg("Enabling support for %s flash.\n", "PROG"); + } if (*dummy_buses_supported == BUS_NONE) msg_pdbg("Support for all flash bus types disabled.\n"); free(bustext); @@ -1010,6 +1087,10 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor tmp = extract_programmer_param("emulate"); if (!tmp) { + if (size != -1) { + msg_perr("%s: size parameter is only valid for VARIABLE_SIZE chip.\n", __func__); + return 1; + } msg_pdbg("Not emulating any flash chip.\n"); /* Nothing else to do. */ return 0; @@ -1107,6 +1188,10 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor data->emu_jedec_ce_c7_size = data->emu_chip_size; msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n", data->emu_chip_size); + } else if (size != -1) { + msg_perr("%s: size parameter is only valid for VARIABLE_SIZE chip.\n", __func__); + free(tmp); + return 1; } if (data->emu_chip == EMULATE_NONE) { @@ -1119,6 +1204,11 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor /* Should emulated flash erase to zero (yes/no)? */ tmp = extract_programmer_param("erase_to_zero"); if (tmp) { + if (data->emu_chip != EMULATE_VARIABLE_SIZE) { + msg_perr("%s: erase_to_zero parameter is not valid for real chip.\n", __func__); + free(tmp); + return 1; + } if (!strcmp(tmp, "yes")) { msg_pdbg("Emulated chip will erase to 0x00\n"); data->erase_to_zero = 1; @@ -1241,6 +1331,9 @@ dummy_init_out: free(data); return 1; } + + if (dummy_buses_supported & BUS_PROG) + register_opaque_master(&opaque_master_dummyflasher, data); if (dummy_buses_supported & BUS_NONSPI) register_par_master(&par_master_dummyflasher, dummy_buses_supported & BUS_NONSPI, @@ -1251,49 +1344,6 @@ dummy_init_out: return 0; } -int probe_variable_size(struct flashctx *flash) -{ - unsigned int i; - const struct emu_data *emu_data = flash->mst->spi.data; - - /* Skip the probing if we don't emulate this chip. */ - if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE) - return 0; - - /* - * This will break if one day flashctx becomes read-only. - * Once that happens, we need to have special hacks in functions: - * - * erase_and_write_flash() in flashrom.c - * do_read() - * handle_romentries() - * ... - * - * Search "total_size * 1024" in code. - */ - flash->chip->total_size = emu_data->emu_chip_size / 1024; - msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__, - flash->chip->total_size); - - if (emu_data->erase_to_zero) - flash->chip->feature_bits |= FEATURE_ERASED_ZERO; - - /* Update the first count of each of the block_erasers. */ - for (i = 0; i < NUM_ERASEFUNCTIONS; i++) { - struct block_eraser *eraser = &flash->chip->block_erasers[i]; - if (!eraser->block_erase) - break; - - eraser->eraseblocks[0].count = 1; - eraser->eraseblocks[0].size = emu_data->emu_chip_size; - msg_cdbg("%s: eraser.size=%d, .count=%d\n", - __func__, eraser->eraseblocks[0].size, - eraser->eraseblocks[0].count); - } - - return 1; -} - const struct programmer_entry programmer_dummy = { .name = "dummy", .type = OTHER, diff --git a/flashchips.c b/flashchips.c index c333fd16..71a6bfbd 100644 --- a/flashchips.c +++ b/flashchips.c @@ -19962,28 +19962,6 @@ const struct flashchip flashchips[] = { .read = NULL, }, - { - .vendor = "Generic", - .name = "Variable Size SPI chip", - .bustype = BUS_SPI, - .manufacture_id = PROGMANUF_ID, - .model_id = PROGDEV_ID, - .total_size = 64, /* This size is set temporarily */ - .page_size = 256, - .feature_bits = FEATURE_4BA_READ | FEATURE_4BA_WRITE, - .tested = TEST_OK_PREW, - .probe = probe_variable_size, - .block_erasers = - { - { - .eraseblocks = { {64 * 1024, 1} }, - .block_erase = spi_block_erase_c7, - } - }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - { .vendor = "Generic", .name = "unknown SPI chip (RDID)", diff --git a/include/chipdrivers.h b/include/chipdrivers.h index 0695993a..33e2914a 100644 --- a/include/chipdrivers.h +++ b/include/chipdrivers.h @@ -201,9 +201,6 @@ int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int int probe_en29lv640b(struct flashctx *flash); int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); -/* dummyflasher.c */ -int probe_variable_size(struct flashctx *flash); - /* edi.c */ int edi_chip_block_erase(struct flashctx *flash, unsigned int page, unsigned int size); int edi_chip_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); -- cgit v1.2.3