On Mon, Feb 6, 2012 at 6:46 PM, Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> wrote:
Repost... code cleaned, man page fixed.

Add optional SPI command blacklisting and ingorelisting to the flash
chip emulator in the dummy programmer.

Usage:
flashrom -p dummy:spi_blacklist=commandlist
flashrom -p dummy:spi_ignorelist=commandlist

If commandlist is 0302, flashrom will refuse (blacklist) or ignore
(ignorelist) command 0x03 (READ) and command 0x02 (WRITE). The
commandlist can be up to 512 bytes (256 commands) long.
Specifying flash chip emulation is a good idea to get useful results.

Very useful for testing corner cases if you don't own a locked down
Intel chipset and want to simulate such a thing.

Example usage:
dd if=/dev/zeros bs=1024k count=4 of=dummy_simulator.rom
dd if=/dev/urandom bs=1024k count=4 of=randomimage.rom
flashrom -p dummy:emulate=SST25VF032B,image=dummy_simulator.rom,spi_blacklist=20,spi_ignorelist=52 -w randomimage.rom -V

The example output looks like this:
flashrom v0.9.4-r1488 on Linux 2.6.34.10-0.6-default (i686), built with libpci 3.1.7, GCC 4.5.0 20100604 [gcc-4_5-branch revision 160292], little endian
[...]
Initializing dummy programmer
Requested buses are: default
Enabling support for parallel flash.
Enabling support for LPC flash.
Enabling support for FWH flash.
Enabling support for SPI flash.
SPI blacklist is 20 , size 1
SPI ignorelist is 52 , size 1
Emulating SST SST25VF032B SPI flash chip (RDID, AAI write)
Filling fake flash chip with 0xff, size 4194304
Found persistent image dummy_simulator.rom, size 4194304 matches.
Reading dummy_simulator.rom
The following protocols are supported: Parallel, LPC, FWH, SPI.
[...]
Probing for SST SST25VF032B, 4096 kB: probe_spi_rdid_generic: id1 0xbf, id2 0x254a
Chip status register is 00
Chip status register: Block Protect Write Disable (BPL) is not set
Chip status register: Auto Address Increment Programming (AAI) is not set
Chip status register: Bit 5 / Block Protect 3 (BP3) is not set
Chip status register: Bit 4 / Block Protect 2 (BP2) is not set
Chip status register: Bit 3 / Block Protect 1 (BP1) is not set
Chip status register: Bit 2 / Block Protect 0 (BP0) is not set
Chip status register: Write Enable Latch (WEL) is not set
Chip status register: Write In Progress (WIP/BUSY) is not set
Found SST flash chip "SST25VF032B" (4096 kB, SPI) on dummy.
[...]
Found SST flash chip "SST25VF032B" (4096 kB, SPI).
Reading old flash chip contents... done.
Erasing and writing flash chip... Trying erase function 0... 0x000000-0x000fff:ERefusing blacklisted SPI command 0x20
Invalid command sent to flash chip!
spi_block_erase_20 failed during command execution at address 0x0
Reading current flash chip contents... done. Looking for another erase function.
Trying erase function 1... 0x000000-0x007fff:EIgnoring ignorelisted SPI command 0x52
ERASE FAILED at 0x00000000! Expected=0xff, Read=0x00, failed byte count from 0x00000000-0x00007fff: 0x8000
ERASE FAILED!
Reading current flash chip contents... done. Looking for another erase function.
Trying erase function 2... 0x000000-0x00ffff:EW, 0x010000-0x01ffff:EW, 0x020000-0x02ffff:EW, 0x030000-0x03ffff:EW, 0x040000-0x04ffff:EW, 0x050000-0x05ffff:EW, 0x060000-0x06ffff:EW, 0x070000-0x07ffff:EW, 0x080000-0x08ffff:EW, 0x090000-0x09ffff:EW, 0x0a0000-0x0affff:EW, 0x0b0000-0x0bffff:EW, 0x0c0000-0x0cffff:EW, 0x0d0000-0x0dffff:EW, 0x0e0000-0x0effff:EW, 0x0f0000-0x0fffff:EW, 0x100000-0x10ffff:EW, 0x110000-0x11ffff:EW, 0x120000-0x12ffff:EW, 0x130000-0x13ffff:EW, 0x140000-0x14ffff:EW, 0x150000-0x15ffff:EW, 0x160000-0x16ffff:EW, 0x170000-0x17ffff:EW, 0x180000-0x18ffff:EW, 0x190000-0x19ffff:EW, 0x1a0000-0x1affff:EW, 0x1b0000-0x1bffff:EW, 0x1c0000-0x1cffff:EW, 0x1d0000-0x1dffff:EW, 0x1e0000-0x1effff:EW, 0x1f0000-0x1fffff:EW, 0x200000-0x20ffff:EW, 0x210000-0x21ffff:EW, 0x220000-0x22ffff:EW, 0x230000-0x23ffff:EW, 0x240000-0x24ffff:EW, 0x250000-0x25ffff:EW, 0x260000-0x26ffff:EW, 0x270000-0x27ffff:EW, 0x280000-0x28ffff:EW, 0x290000-0x29ffff:EW, 0x2a0000-0x2affff:EW, 0x2b0000-0x2bffff:EW, 0x2c0000-0x2cffff:EW, 0x2d0000-0x2dffff:EW, 0x2e0000-0x2effff:EW, 0x2f0000-0x2fffff:EW, 0x300000-0x30ffff:EW, 0x310000-0x31ffff:EW, 0x320000-0x32ffff:EW, 0x330000-0x33ffff:EW, 0x340000-0x34ffff:EW, 0x350000-0x35ffff:EW, 0x360000-0x36ffff:EW, 0x370000-0x37ffff:EW, 0x380000-0x38ffff:EW, 0x390000-0x39ffff:EW, 0x3a0000-0x3affff:EW, 0x3b0000-0x3bffff:EW, 0x3c0000-0x3cffff:EW, 0x3d0000-0x3dffff:EW, 0x3e0000-0x3effff:EW, 0x3f0000-0x3fffff:EW
Erase/write done.
Verifying flash... VERIFIED.
Writing dummy_simulator.rom


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

An earlier version of this patch (wthout ignorelisting) got the
following response:

Am 04.02.2011 01:42 schrieb David Hendricks:
> Overall looks good to me. I tested it out by blacklisting read, rdid, write,
> wren, and the chip erase commands in various combinations and it seems to
> work reasonably well. SPI opcode parsing seemed to work fine as well.
>
> For others interested in giving this a try, here is another example of
> syntax (courtesy of Carl-Danial on IRC) for us laymen: flashrom -p
> dummy:emulate=SST25VF032B,image=dummy_simulator.rom,spi_blacklist=0x03
>
> I don't know man page formatting well, so I didn't review that part. As far
> as the code, I say:
> Acked-by: David Hendricks <dhendrix@google.com>

David: Given that your review was based on a pretty different version of
the code, I'm not including your ack unless you're OK with the new code
as well.

Index: flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c
===================================================================
--- flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c     (Revision 1488)
+++ flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c     (Arbeitskopie)
@@ -19,6 +19,8 @@

 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
 #include "flash.h"
 #include "chipdrivers.h"
 #include "programmer.h"
@@ -55,6 +57,10 @@
 static unsigned int emu_jedec_be_d8_size = 0;
 static unsigned int emu_jedec_ce_60_size = 0;
 static unsigned int emu_jedec_ce_c7_size = 0;
+unsigned char spi_blacklist[256];
+unsigned char spi_ignorelist[256];
+int spi_blacklist_size = 0;
+int spi_ignorelist_size = 0;
 #endif
 #endif

@@ -126,6 +132,7 @@
 {
       char *bustext = NULL;
       char *tmp = NULL;
+       int i;
 #if EMULATE_CHIP
       struct stat image_stat;
 #endif
@@ -170,6 +177,68 @@
               }
       }

+       tmp = extract_programmer_param("spi_blacklist");
+       if (tmp) {
+               i = strlen(tmp);
+               if (!strncmp(tmp, "0x", 2)) {
+                       i -= 2;
+                       memmove(tmp, tmp + 2, i + 1);
+               }
+               if ((i > 512) || (i % 2)) {
+                       msg_perr("Invalid SPI command blacklist length\n");
+                       free(tmp);
+                       return 1;
+               }
+               spi_blacklist_size = i / 2;
+               for (i = 0; i < spi_blacklist_size * 2; i++) {
+                       if (!isxdigit((unsigned char)tmp[i])) {
+                               msg_perr("Invalid char \"%c\" in SPI command "
+                                        "blacklist\n", tmp[i]);
+                               free(tmp);
+                               return 1;
+                       }
+               }
+               for (i = 0; i < spi_blacklist_size; i++) {
+                       sscanf(tmp + i * 2, "%2hhx", &spi_blacklist[i]);
+               }
+               msg_pdbg("SPI blacklist is ");
+               for (i = 0; i < spi_blacklist_size; i++)
+                       msg_pdbg("%02x ", spi_blacklist[i]);
+               msg_pdbg(", size %i\n", spi_blacklist_size);
+       }
+       free(tmp);
+
+       tmp = extract_programmer_param("spi_ignorelist");
+       if (tmp) {
+               i = strlen(tmp);
+               if (!strncmp(tmp, "0x", 2)) {
+                       i -= 2;
+                       memmove(tmp, tmp + 2, i + 1);
+               }
+               if ((i > 512) || (i % 2)) {
+                       msg_perr("Invalid SPI command ignorelist length\n");
+                       free(tmp);
+                       return 1;
+               }
+               spi_ignorelist_size = i / 2;
+               for (i = 0; i < spi_ignorelist_size * 2; i++) {
+                       if (!isxdigit((unsigned char)tmp[i])) {
+                               msg_perr("Invalid char \"%c\" in SPI command "
+                                        "ignorelist\n", tmp[i]);
+                               free(tmp);
+                               return 1;
+                       }
+               }
+               for (i = 0; i < spi_ignorelist_size; i++) {
+                       sscanf(tmp + i * 2, "%2hhx", &spi_ignorelist[i]);
+               }
+               msg_pdbg("SPI ignorelist is ");
+               for (i = 0; i < spi_ignorelist_size; i++)
+                       msg_pdbg("%02x ", spi_ignorelist[i]);
+               msg_pdbg(", size %i\n", spi_ignorelist_size);
+       }
+       free(tmp);
+
 #if EMULATE_CHIP
       tmp = extract_programmer_param("emulate");
       if (!tmp) {
@@ -348,7 +417,7 @@
                                    const unsigned char *writearr,
                                    unsigned char *readarr)
 {
-       unsigned int offs;
+       unsigned int offs, i;
       static int unsigned aai_offs;
       static int aai_active = 0;

@@ -356,7 +425,24 @@
               msg_perr("No command sent to the chip!\n");
               return 1;
       }
-       /* TODO: Implement command blacklists here. */
+       /* spi_blacklist has precedence before spi_ignorelist. */
+       for (i = 0; i < spi_blacklist_size; i++) {
+               if (writearr[0] == spi_blacklist[i]) {
+                       msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
+                                spi_blacklist[i]);
+                       return SPI_INVALID_OPCODE;
+               }
+       }
+       for (i = 0; i < spi_ignorelist_size; i++) {
+               if (writearr[0] == spi_ignorelist[i]) {
+                       msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
+                                spi_ignorelist[i]);
+                       /* Return success because the command does not fail,
+                        * it is simply ignored.
+                        */
+                       return 0;
+               }
+       }
       switch (writearr[0]) {
       case JEDEC_RES:
               if (emu_chip != EMULATE_ST_M25P10_RES)
@@ -563,7 +649,7 @@
       case EMULATE_SST_SST25VF032B:
               if (emulate_spi_chip_response(writecnt, readcnt, writearr,
                                             readarr)) {
-                       msg_perr("Invalid command sent to flash chip!\n");
+                       msg_pdbg("Invalid command sent to flash chip!\n");
                       return 1;
               }
               break;
Index: flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8
===================================================================
--- flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8 (Revision 1488)
+++ flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8 (Arbeitskopie)
@@ -421,6 +421,28 @@
 Example:
 .sp
 .B "  flashrom -p dummy:emulate=M25P10.RES,spi_write_256_chunksize=5"
+.sp
+To simulate a programmer which refuses to send certain SPI commands to the
+flash chip, you can specify a blacklist of SPI commands with the
+.sp
+.B "  flashrom -p dummy:spi_blacklist=commandlist"
+.sp
+syntax where commandlist is a list of two-digit hexadecimal representations of
+SPI commands. If commandlist is e.g. 0302, flashrom will behave as if the SPI
+controller refuses to run command 0x03 (READ) and command 0x02 (WRITE).
+commandlist may be up to 512 characters (256 commands) long.
+Implementation note: flashrom will detect an error during command execution.
+.sp
+To simulate a flash chip which ignores (doesn't support) certain SPI commands,
+you can specify an ignorelist of SPI commands with the
+.sp
+.B "  flashrom -p dummy:spi_ignorelist=commandlist"
+.sp
+syntax where commandlist is a list of two-digit hexadecimal representations of
+SPI commands. If commandlist is e.g. 0302, the emulated flash chip will ignore
+command 0x03 (READ) and command 0x02 (WRITE).  commandlist may be up to 512
+characters (256 commands) long.
+Implementation note: flashrom won't detect an error during command execution.
 .TP
 .BR "nic3com" , " nicrealtek" , " nicsmc1211" , " nicnatsemi" , " nicintel\
 " , " nicintel_spi" , " gfxnvidia" , " ogp_spi" , " drkaiser" , " satasii\


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



Looks good to me.

Acked-by: David Hendricks <dhendrix@google.com>



--
David Hendricks (dhendrix)
Systems Software Engineer, Google Inc.