Support variable-size SPI chip for dummy programmer.
flashrom -p dummy:emulate=VARIABLE_SIZE,image=image_file,size=4M
This is designed for firmware updater to preserve partitions easily. For example, the use case to keep VPDs when upgrading from H2O to H2C.
Change-Id: I84e1a793639cc33b769f6db41be0a0f0b1eacc78
R=dhendrix@chromium.org,hungte@chromiumg.org,reinauer@chromium.org
BUG=Not a bug
TEST=Tested on Z600 and target.
# a H2C file is ready to write.
% flashrom -r H2O # read existing content from BIOS, including VPDs.
% flashrom -p dummy:emulate=VARIABLE_SIZE,image=H2C,size=4M \
-i RO_VPD -i RW_VPD -w H2O # overwrite VPDs from H2O to H2C.
% flashrom -w H2C # write it down, with VPDs from H2O.
Review URL: http://codereview.chromium.org/6791015
diff --git a/chipdrivers.h b/chipdrivers.h
index fb251fe..7e9fe8b 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -137,4 +137,7 @@
int erase_chip_stm50flw0x0x(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
int unlock_stm50flw0x0x(struct flashchip *flash);
+/* dummyflasher.c */
+int probe_variable_size(struct flashchip *flash);
+
#endif /* !__CHIPDRIVERS_H__ */
diff --git a/dummyflasher.c b/dummyflasher.c
index 473e45e..91fbc88 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -22,6 +22,7 @@
#include "flash.h"
#include "chipdrivers.h"
#include "programmer.h"
+#include "flashchips.h"
/* Remove the #define below if you don't want SPI flash chip emulation. */
#define EMULATE_SPI_CHIP 1
@@ -34,6 +35,13 @@
#if EMULATE_CHIP
#include <sys/types.h>
#include <sys/stat.h>
+
+#if EMULATE_SPI_CHIP
+/* The name of variable-size virtual chip. A 4MB flash example:
+ * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
+ */
+#define VARIABLE_SIZE_CHIP_NAME "VARIABLE_SIZE"
+#endif
#endif
#if EMULATE_CHIP
@@ -43,6 +51,7 @@
EMULATE_ST_M25P10_RES,
EMULATE_SST_SST25VF040_REMS,
EMULATE_SST_SST25VF032B,
+ EMULATE_VARIABLE_SIZE,
};
static enum emu_chip emu_chip = EMULATE_NONE;
static char *emu_persistent_image = NULL;
@@ -66,6 +75,9 @@
char *tmp = NULL;
#if EMULATE_CHIP
struct stat image_stat;
+#if EMULATE_SPI_CHIP
+ int size = -1; /* size for generic chip */
+#endif
#endif
msg_pspew("%s\n", __func__);
@@ -110,6 +122,29 @@
}
#if EMULATE_CHIP
+#if EMULATE_SPI_CHIP
+ tmp = extract_programmer_param("size");
+ if (tmp) {
+ int multiplier = 1;
+ if (strlen(tmp)) {
+ int remove_last_char = 1;
+ switch (tmp[strlen(tmp) - 1]) {
+ case 'k': case 'K':
+ multiplier = 1024;
+ break;
+ case 'm': case 'M':
+ multiplier = 1024 * 1024;
+ break;
+ default:
+ remove_last_char = 0;
+ break;
+ }
+ if (remove_last_char) tmp[strlen(tmp) - 1] = '\0';
+ }
+ size = atoi(tmp) * multiplier;
+ }
+#endif
+
tmp = extract_programmer_param("emulate");
if (!tmp) {
msg_pdbg("Not emulating any flash chip.\n");
@@ -156,6 +191,26 @@
msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
"write)\n");
}
+ if (!strncmp(tmp, VARIABLE_SIZE_CHIP_NAME,
+ strlen(VARIABLE_SIZE_CHIP_NAME))) {
+ if (size == -1) {
+ msg_perr("%s: the size parameter is not given.\n",
+ __func__);
+ free(tmp);
+ return 1;
+ }
+ emu_chip = EMULATE_VARIABLE_SIZE;
+ emu_chip_size = size;
+ emu_max_byteprogram_size = 256;
+ emu_max_aai_size = 0;
+ emu_jedec_se_size = 4 * 1024;
+ emu_jedec_be_52_size = 32 * 1024;
+ emu_jedec_be_d8_size = 64 * 1024;
+ emu_jedec_ce_60_size = emu_chip_size;
+ emu_jedec_ce_c7_size = emu_chip_size;
+ msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
+ emu_chip_size);
+ }
#endif
if (emu_chip == EMULATE_NONE) {
msg_perr("Invalid chip specified for emulation: %s\n", tmp);
@@ -305,15 +360,22 @@
readarr[1] = 0x44;
break;
case JEDEC_RDID:
- if (emu_chip != EMULATE_SST_SST25VF032B)
- break;
- /* Respond with SST_SST25VF032B. */
- if (readcnt > 0)
- readarr[0] = 0xbf;
- if (readcnt > 1)
- readarr[1] = 0x25;
- if (readcnt > 2)
- readarr[2] = 0x4a;
+ if (emu_chip == EMULATE_SST_SST25VF032B) {
+ /* Respond with SST_SST25VF032B. */
+ if (readcnt > 0)
+ readarr[0] = 0xbf;
+ if (readcnt > 1)
+ readarr[1] = 0x25;
+ if (readcnt > 2)
+ readarr[2] = 0x4a;
+ } else if (emu_chip == EMULATE_VARIABLE_SIZE) {
+ const uint16_t man_id = VARIABLE_SIZE_MANUF_ID;
+ const uint16_t dev_id = VARIABLE_SIZE_DEVICE_ID;
+ if (readcnt > 0) readarr[0] = man_id >> 8;
+ if (readcnt > 1) readarr[1] = man_id & 0xff;
+ if (readcnt > 2) readarr[2] = dev_id >> 8;
+ if (readcnt > 3) readarr[3] = dev_id & 0xff;
+ }
break;
case JEDEC_RDSR:
memset(readarr, 0, readcnt);
@@ -495,6 +557,7 @@
case EMULATE_ST_M25P10_RES:
case EMULATE_SST_SST25VF040_REMS:
case EMULATE_SST_SST25VF032B:
+ case EMULATE_VARIABLE_SIZE:
if (emulate_spi_chip_response(writecnt, readcnt, writearr,
readarr)) {
msg_perr("Invalid command sent to flash chip!\n");
@@ -524,3 +587,47 @@
return spi_write_chunked(flash, buf, start, len,
spi_write_256_chunksize);
}
+
+#if EMULATE_CHIP && EMULATE_SPI_CHIP
+int probe_variable_size(struct flashchip *flash)
+{
+ int i;
+
+ /* Skip the probing if we don't emulate this chip. */
+ if (emu_chip != EMULATE_VARIABLE_SIZE)
+ return 0;
+
+ /*
+ * This will break if one day flashchip becomes read-only.
+ * Once that happens, we need to have special hacks in functions:
+ *
+ * erase_and_write_flash() in flashrom.c
+ * read_flash_to_file()
+ * handle_romentries()
+ * ...
+ *
+ * Search "total_size * 1024" in code.
+ */
+ if (emu_chip_size % 1024)
+ msg_perr("%s: emu_chip_size is not multipler of 1024.\n",
+ __func__);
+ flash->total_size = emu_chip_size / 1024;
+ msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
+ flash->total_size);
+
+ /* Update eraser count */
+ for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
+ struct block_eraser *eraser = &flash->block_erasers[i];
+ if (eraser->block_erase == NULL)
+ break;
+
+ eraser->eraseblocks[0].count = emu_chip_size /
+ eraser->eraseblocks[0].size;
+ msg_cdbg("%s: eraser.size=%d, .count=%d\n",
+ __func__, eraser->eraseblocks[0].size,
+ eraser->eraseblocks[0].count);
+ }
+
+ return 1;
+}
+#endif
diff --git a/flashchips.c b/flashchips.c
index dca01a2..4b921b5 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -8075,6 +8075,30 @@
{
.vendor = "Generic",
+ .name = "Variable Size SPI chip",
+ .bustype = CHIP_BUSTYPE_SPI,
+ .manufacture_id = VARIABLE_SIZE_MANUF_ID,
+ .model_id = VARIABLE_SIZE_DEVICE_ID,
+ .total_size = 64, /* This size is set temporarily */
+ .page_size = 256,
+ .tested = TEST_OK_PREW,
+ .probe = probe_variable_size,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 16} },
+ .block_erase = spi_block_erase_20,
+ }, {
+ .eraseblocks = { {64 * 1024, 1} },
+ .block_erase = spi_block_erase_d8,
+ }
+ },
+ .write = spi_chip_write_256,
+ .read = spi_chip_read,
+ },
+
+ {
+ .vendor = "Generic",
.name = "unknown SPI chip (RDID)",
.bustype = CHIP_BUSTYPE_SPI,
.manufacture_id = GENERIC_MANUF_ID,
diff --git a/flashchips.h b/flashchips.h
index 95481f4..e211a46 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -37,6 +37,9 @@
#define GENERIC_MANUF_ID 0xffff /* Check if there is a vendor ID */
#define GENERIC_DEVICE_ID 0xffff /* Only match the vendor ID */
+#define VARIABLE_SIZE_MANUF_ID 0x3eaf
+#define VARIABLE_SIZE_DEVICE_ID 0x10af
+
#define ALLIANCE_ID 0x52 /* Alliance Semiconductor */
#define ALLIANCE_AS29F002B 0x34
#define ALLIANCE_AS29F002T 0xB0