[flashrom] [PATCH] SPI flash chip emulator

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Wed Oct 27 06:40:43 CEST 2010


Add SPI flash emulation capability to dummyflasher.
You have to choose at compile time between
- no emulation
- ST M25P10.RES SPI flash chip (RES, page write)
- SST SST25VF040.REMS SPI flash chip (REMS, byte write)
- SST SST25VF032B SPI flash chip (RDID, AAI write)

This code helped me find and fix various bugs in the SPI write code
(patches forthcoming).

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>

Index: flashrom-emulate_spi_flashchip/dummyflasher.c
===================================================================
--- flashrom-emulate_spi_flashchip/dummyflasher.c	(Revision 1216)
+++ flashrom-emulate_spi_flashchip/dummyflasher.c	(Arbeitskopie)
@@ -25,6 +25,45 @@
 #include "chipdrivers.h"
 #include "programmer.h"
 
+//#define EMULATE_ST_M25P10_RES 1
+//#define EMULATE_SST_SST25VF040_REMS 1
+//#define EMULATE_SST_SST25VF032B 1
+
+#if EMULATE_ST_M25P10_RES + EMULATE_SST_SST25VF040_REMS + EMULATE_SST_SST25VF032B > 1
+#error Only one chip can be emulated. Please decide which one you want.
+#endif
+
+#if EMULATE_ST_M25P10_RES || EMULATE_SST_SST25VF040_REMS || EMULATE_SST_SST25VF032B
+#define EMULATE_SPI_CHIP 1
+#endif
+
+#if EMULATE_SPI_CHIP
+#define EMULATE_CHIP 1
+#include "spi.h"
+#endif
+
+#if EMULATE_ST_M25P10_RES
+#define EMU_FLASHCHIP_SIZE 128 * 1024
+#define MAX_BYTEPROGRAM_SIZE 128
+#define MAX_AAI_SIZE 0
+#endif
+
+#if EMULATE_SST_SST25VF040_REMS
+#define EMU_FLASHCHIP_SIZE 512 * 1024
+#define MAX_BYTEPROGRAM_SIZE 1
+#define MAX_AAI_SIZE 0
+#endif
+
+#if EMULATE_SST_SST25VF032B
+#define EMU_FLASHCHIP_SIZE 4 * 1024 * 1024
+#define MAX_BYTEPROGRAM_SIZE 1
+#define MAX_AAI_SIZE 2
+#endif
+
+#if EMULATE_CHIP
+static uint8_t flashchip_contents[EMU_FLASHCHIP_SIZE];
+#endif
+
 static void tolower_string(char *str)
 {
 	for (; *str != '\0'; str++)
@@ -65,6 +104,25 @@
 	if (buses_supported == CHIP_BUSTYPE_NONE)
 		msg_pdbg("Support for all flash bus types disabled.\n");
 	free(bustext);
+
+#if EMULATE_ST_M25P10_RES
+	msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page write)\n");
+#endif
+#if EMULATE_SST_SST25VF040_REMS
+	msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, byte "
+		 "write)\n");
+#endif
+#if EMULATE_SST_SST25VF032B
+	msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
+		 "write)\n");
+#endif
+#if EMULATE_CHIP
+	msg_pdbg("Filling fake flash chip with 0xff, size %i\n",
+		 sizeof(flashchip_contents));
+	memset(flashchip_contents, 0xff, sizeof(flashchip_contents));
+#else
+	msg_pdbg("Not emulating any flash chip.\n");
+#endif
 	return 0;
 }
 
@@ -140,6 +198,123 @@
 	return;
 }
 
+#if EMULATE_SPI_CHIP
+static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt,
+		      const unsigned char *writearr, unsigned char *readarr)
+{
+	int offs;
+#if EMULATE_SST_SST25VF032B
+	static int aai_offs;
+	static int aai_active = 0;
+#endif
+	if (writecnt == 0) {
+		msg_cerr("No command sent to the chip!\n");
+		return 1;
+	}
+	switch (writearr[0]) {
+#if EMULATE_ST_M25P10_RES
+	case JEDEC_RES:
+		/* Respond with ST_M25P10_RES. */
+		if (readcnt > 0)
+			readarr[0] = 0x10;
+		break;
+#endif
+#if EMULATE_SST_SST25VF040_REMS
+	case JEDEC_REMS:
+		/* Respond with SST_SST25VF040_REMS. */
+		if (readcnt > 0)
+			readarr[0] = 0xbf;
+		if (readcnt > 1)
+			readarr[1] = 0x44;
+		break;
+#endif
+#if EMULATE_SST_SST25VF032B
+	case JEDEC_RDID:
+		/* Respond with SST_SST25VF032B. */
+		if (readcnt > 0)
+			readarr[0] = 0xbf;
+		if (readcnt > 1)
+			readarr[1] = 0x25;
+		if (readcnt > 2)
+			readarr[2] = 0x4a;
+		break;
+#endif
+	case JEDEC_RDSR:
+		memset(readarr, 0, readcnt);
+#if EMULATE_SST_SST25VF032B
+		if (aai_active)
+			memset(readarr, 1 << 6, readcnt);
+#endif
+		break;
+	case JEDEC_READ:
+		offs = writearr[1] << 16 | writearr[2] << 8 |
+		       writearr[3];
+		/* Truncate to EMU_FLASHCHIP_SIZE. */
+		offs %= EMU_FLASHCHIP_SIZE;
+		if (readcnt > 0)
+			memcpy(readarr, flashchip_contents + offs, readcnt);
+		break;
+	case JEDEC_BYTE_PROGRAM:
+		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+		/* Truncate to EMU_FLASHCHIP_SIZE. */
+		offs %= EMU_FLASHCHIP_SIZE;
+		if (writecnt < 5) {
+			msg_cerr("BYTE PROGRAM size too short!\n");
+			return 1;
+		}
+		if (writecnt - 4 > MAX_BYTEPROGRAM_SIZE) {
+			msg_cerr("Max BYTE PROGRAM size exceeded!\n");
+			return 1;
+		}
+		memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
+		break;
+#if EMULATE_SST_SST25VF032B
+	case JEDEC_AAI_WORD_PROGRAM:
+		if (!aai_active) {
+			if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
+				msg_cerr("Initial AAI WORD PROGRAM size too "
+					 "short!\n");
+				return 1;
+			}
+			if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
+				msg_cerr("Initial AAI WORD PROGRAM size too "
+					 "long!\n");
+				return 1;
+			}
+			aai_active = 1;
+			aai_offs = writearr[1] << 16 | writearr[2] << 8 |
+				   writearr[3];
+			/* Truncate to EMU_FLASHCHIP_SIZE. */
+			aai_offs %= EMU_FLASHCHIP_SIZE;
+			memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
+			aai_offs += 2;
+		} else {
+			if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
+				msg_cerr("Continuation AAI WORD PROGRAM size "
+					 "too short!\n");
+				return 1;
+			}
+			if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
+				msg_cerr("Continuation AAI WORD PROGRAM size "
+					 "too long!\n");
+				return 1;
+			}
+			memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
+			aai_offs += 2;
+		}
+		break;
+	case JEDEC_WRDI:
+		aai_active = 0;
+		break;
+#endif
+	default:
+		/* No special response. */
+		break;
+	}
+	return 0;
+}
+#endif
+
 int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		      const unsigned char *writearr, unsigned char *readarr)
 {
@@ -157,6 +332,9 @@
 		readarr[i] = 0xff;
 	}
 
+#if EMULATE_SPI_CHIP
+	emulate_spi_chip_response(writecnt, readcnt, writearr, readarr);
+#endif
 	msg_pspew("\n");
 	return 0;
 }


-- 
http://www.hailfinger.org/





More information about the flashrom mailing list