Add optional SPI command blacklisting to the flash chip emulator in the dummy programmer.
Usage: flashrom -p dummy:spi_blacklist=hexstring
If hexstring is 0302, flashrom will blacklist command 0x03 (READ) and command 0x02 (WRITE). The hexstring can have up to 521 bytes (256 commands) length, and must not start with 0x.
TODO: Should 0x at the beginning of hexstring be tolerated?
Very useful for testing corner cases if you don't own a locked down Intel chipset and want to simulate such a thing.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c =================================================================== --- flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c (Revision 1224) +++ flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c (Arbeitskopie) @@ -19,6 +19,7 @@
#include <string.h> #include <stdlib.h> +#include <stdio.h> #include <ctype.h> #include "flash.h" #include "chipdrivers.h" @@ -56,6 +57,8 @@ static int emu_jedec_be_d8_size = 0; static int emu_jedec_ce_60_size = 0; static int emu_jedec_ce_c7_size = 0; +unsigned char spi_blacklist[256]; +int spi_blacklist_size = 0; #endif #endif
@@ -71,6 +74,7 @@ { char *bustext = NULL; char *tmp = NULL; + int i; #if EMULATE_CHIP struct stat image_stat; #endif @@ -116,6 +120,31 @@ } }
+ tmp = extract_programmer_param("spi_blacklist"); + if (tmp) { + i = strlen(tmp); + if (i % 2) { + msg_perr("Invalid SPI command blacklist\n"); + free(tmp); + return 1; + } + tolower_string(tmp); + if (strspn(tmp, "0123456789abcdef") != i) { + msg_perr("Invalid SPI command blacklist\n"); + free(tmp); + return 1; + } + spi_blacklist_size = i / 2; + for (i = 0; i < spi_blacklist_size; i++) { + sscanf(tmp, "%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); + #if EMULATE_CHIP tmp = extract_programmer_param("emulate"); if (!tmp) { @@ -285,7 +314,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { - int offs; + int offs, i; static int aai_offs; static int aai_active = 0;
@@ -293,7 +322,16 @@ msg_perr("No command sent to the chip!\n"); return 1; } - /* TODO: Implement command blacklists here. */ + for (i = 0; i < spi_blacklist_size; i++) { + if (writearr[0] == spi_blacklist[i]) { + msg_perr("Refusing blacklisted SPI command 0x%02x\n", + spi_blacklist[i]); + /* FIXME: Do we want a separate return code for + * command unavailable? + */ + return 1; + } + } switch (writearr[0]) { case JEDEC_RES: if (emu_chip != EMULATE_ST_M25P10_RES)
New version with additional bugfixes and man page. The man page formatting is broken, I'd appreciate help from someone who knows how to fix the formatting.
Add optional SPI command blacklisting to the flash chip emulator in the dummy programmer.
Usage: flashrom -p dummy:spi_blacklist=hexstring
If hexstring is 0302, flashrom will blacklist command 0x03 (READ) and command 0x02 (WRITE). The hexstring can have up to 521 bytes (256 commands) length, and must not start with 0x.
TODO: Should 0x at the beginning of hexstring be tolerated?
Very useful for testing corner cases if you don't own a locked down Intel chipset and want to simulate such a thing.
Fix out-of-bounds access in the simulator command checking code.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c =================================================================== --- flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c (Revision 1252) +++ flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c (Arbeitskopie) @@ -19,6 +19,7 @@
#include <string.h> #include <stdlib.h> +#include <stdio.h> #include "flash.h" #include "chipdrivers.h" #include "programmer.h" @@ -55,6 +56,8 @@ static int emu_jedec_be_d8_size = 0; static int emu_jedec_ce_60_size = 0; static int emu_jedec_ce_c7_size = 0; +unsigned char spi_blacklist[256]; +int spi_blacklist_size = 0; #endif #endif
@@ -64,6 +67,8 @@ { char *bustext = NULL; char *tmp = NULL; + char *tmp2 = NULL; + int i; #if EMULATE_CHIP struct stat image_stat; #endif @@ -109,6 +114,35 @@ } }
+ tmp = extract_programmer_param("spi_blacklist"); + if (tmp) { + tolower_string(tmp); + tmp2 = tmp; + if (!strncmp(tmp2, "0x", 2)) { + tmp2 += 2; + } + i = strlen(tmp2); + if ((i > 512) || (i % 2)) { + msg_perr("Invalid SPI command blacklist length\n"); + free(tmp); + return 1; + } + if (strspn(tmp2, "0123456789abcdef") != i) { + msg_perr("Invalid chars in SPI command blacklist\n"); + free(tmp); + return 1; + } + spi_blacklist_size = i / 2; + for (i = 0; i < spi_blacklist_size; i++) { + sscanf(tmp2 + 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); + #if EMULATE_CHIP tmp = extract_programmer_param("emulate"); if (!tmp) { @@ -278,7 +312,7 @@ static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { - int offs; + int offs, i; static int aai_offs; static int aai_active = 0;
@@ -286,7 +320,16 @@ msg_perr("No command sent to the chip!\n"); return 1; } - /* TODO: Implement command blacklists here. */ + for (i = 0; i < spi_blacklist_size; i++) { + if (writearr[0] == spi_blacklist[i]) { + msg_perr("Refusing blacklisted SPI command 0x%02x\n", + spi_blacklist[i]); + /* FIXME: Do we want a separate return code for + * command unavailable? + */ + return 1; + } + } switch (writearr[0]) { case JEDEC_RES: if (emu_chip != EMULATE_ST_M25P10_RES) @@ -395,7 +438,7 @@ } offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; if (offs & (emu_jedec_se_size - 1)) - msg_pdbg("Unaligned SECTOR ERASE 0x20\n"); + msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs); offs &= ~(emu_jedec_se_size - 1); memset(flashchip_contents + offs, 0xff, emu_jedec_se_size); break; @@ -412,7 +455,7 @@ } offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; if (offs & (emu_jedec_be_52_size - 1)) - msg_pdbg("Unaligned BLOCK ERASE 0x52\n"); + msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs); offs &= ~(emu_jedec_be_52_size - 1); memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size); break; @@ -429,7 +472,7 @@ } offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; if (offs & (emu_jedec_be_d8_size - 1)) - msg_pdbg("Unaligned BLOCK ERASE 0xd8\n"); + msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs); offs &= ~(emu_jedec_be_d8_size - 1); memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size); break; @@ -444,12 +487,9 @@ msg_perr("CHIP ERASE 0x60 insize invalid!\n"); return 1; } - offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; - if (offs & (emu_jedec_ce_60_size - 1)) - msg_pdbg("Unaligned CHIP ERASE 0x60\n"); - offs &= ~(emu_jedec_ce_60_size - 1); + /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */ /* emu_jedec_ce_60_size is emu_chip_size. */ - memset(flashchip_contents + offs, 0xff, emu_jedec_ce_60_size); + memset(flashchip_contents, 0xff, emu_jedec_ce_60_size); break; case JEDEC_CE_C7: if (!emu_jedec_ce_c7_size) @@ -462,10 +502,7 @@ msg_perr("CHIP ERASE 0xc7 insize invalid!\n"); return 1; } - offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; - if (offs & (emu_jedec_ce_c7_size - 1)) - msg_pdbg("Unaligned CHIP ERASE 0xc7\n"); - offs &= ~(emu_jedec_ce_c7_size - 1); + /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */ /* emu_jedec_ce_c7_size is emu_chip_size. */ memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size); break; Index: flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8 =================================================================== --- flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8 (Revision 1252) +++ flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8 (Arbeitskopie) @@ -161,7 +161,7 @@ .sp .BR "* internal" " (default, for in-system flashing in the mainboard)" .sp -.BR "* dummy" " (just prints all operations and accesses)" +.BR "* dummy" " (prints all operations and accesses, can emulate flash chips)" .sp .BR "* nic3com" " (for flash ROMs on 3COM network cards)" .sp @@ -320,6 +320,38 @@ .sp Example: .B "flashrom -p dummy:bus=lpc+fwh" +.sp +The dummy programmer supports flash chip emulation for automated self-tests +without hardware access. You have to choose between +.sp +* no emulation +.sp +* ST M25P10.RES SPI flash chip (RES, page write) +.sp +* SST SST25VF040.REMS SPI flash chip (REMS, byte write) +.sp +* SST SST25VF032B SPI flash chip (RDID, AAI write) +.sp + +Example usage: flashrom -p dummy:emulate=SST25VF032B + +Flash image persistence is available as well. +Example usage: flashrom -p dummy:image=dummy_simulator.rom + +Allow setting the max chunksize for page write with the dummy +programmer. +Example usage: flashrom -p dummy:spi_write_256_chunksize=5 + +optional SPI command blacklisting to the flash chip emulator in the +dummy programmer. + +Usage: +flashrom -p dummy:spi_blacklist=hexstring + +If hexstring is 0302, flashrom will blacklist command 0x03 (READ) and +command 0x02 (WRITE). The hexstring can have up to 512 characters (256 +commands) length, and must not start with 0x. + .TP .BR "nic3com" , " nicrealtek" , " nicsmc1211" , " nicnatsemi" , " gfxnvidia\ " , " satasii " and " atahpt " programmers
On Wed, 19 Jan 2011, Carl-Daniel Hailfinger wrote:
New version with additional bugfixes and man page. The man page formatting is broken, I'd appreciate help from someone who knows how to fix the formatting.
What is wrong with manpage formatting, of course besides content, few parts could use some work.
Add optional SPI command blacklisting to the flash chip emulator in the dummy programmer.
Usage: flashrom -p dummy:spi_blacklist=hexstring
If hexstring is 0302, flashrom will blacklist command 0x03 (READ) and command 0x02 (WRITE). The hexstring can have up to 521 bytes (256 commands) length, and must not start with 0x.
TODO: Should 0x at the beginning of hexstring be tolerated?
Above remark seems to be inaccurate or outdated, as code skips 0x if its on start of string.
Very useful for testing corner cases if you don't own a locked down Intel chipset and want to simulate such a thing.
Fix out-of-bounds access in the simulator command checking code.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c
- tmp = extract_programmer_param("spi_blacklist");
- if (tmp) {
Is there any reason why tmp is declared for whole function instead as variable used only in this block? Also i would rather name 'tmp' variable 'blacklist_param' or something similar, it isnt reused after as anything else and would be easier to read code knowing for what it is used for. Also other parameters have more meaningfull variable names.
tolower_string(tmp);
tmp2 = tmp;
if (!strncmp(tmp2, "0x", 2)) {
tmp2 += 2;
}
i = strlen(tmp2);
if ((i > 512) || (i % 2)) {
msg_perr("Invalid SPI command blacklist length\n");
free(tmp);
return 1;
}
if (strspn(tmp2, "0123456789abcdef") != i) {
msg_perr("Invalid chars in SPI command blacklist\n");
free(tmp);
return 1;
}
spi_blacklist_size = i / 2;
for (i = 0; i < spi_blacklist_size; i++) {
sscanf(tmp2 + 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);
- /* TODO: Implement command blacklists here. */
- for (i = 0; i < spi_blacklist_size; i++) {
if (writearr[0] == spi_blacklist[i]) {
msg_perr("Refusing blacklisted SPI command 0x%02x\n",
spi_blacklist[i]);
/* FIXME: Do we want a separate return code for
* command unavailable?
*/
I think, only if non-emulated write may return command unavailable response.
@@ -444,12 +487,9 @@ msg_perr("CHIP ERASE 0x60 insize invalid!\n"); return 1; }
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
if (offs & (emu_jedec_ce_60_size - 1))
msg_pdbg("Unaligned CHIP ERASE 0x60\n");
@@ -462,10 +502,7 @@ msg_perr("CHIP ERASE 0xc7 insize invalid!\n"); return 1; }
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
if (offs & (emu_jedec_ce_c7_size - 1))
msg_pdbg("Unaligned CHIP ERASE 0xc7\n");
Any word of explain why those two debug messages above are removed?
Index: flashrom-emulate_spi_flashchip_command_blacklist/flashrom.8
+If hexstring is 0302, flashrom will blacklist command 0x03 (READ) and +command 0x02 (WRITE). The hexstring can have up to 512 characters (256 +commands) length, and must not start with 0x.
and should contain 0-9a-fA-F characters only? (0x on begin of whole string is ignored anyway).
I think, along with more options for dummy, manpage could get example how to pass both, blacklist and something else as parameters for dummy programmer.
sth like -pdummy=SST25VF032B,spi_blacklist=ffeeaa
A bit changed manpage part of patch is in attachment.
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
Minor comments below, though I would be satisfied if the code were committed as-is.
On Thu, Jan 20, 2011 at 5:36 PM, Maciej Pijanka maciej.pijanka@gmail.comwrote:
Index: flashrom-emulate_spi_flashchip_command_blacklist/dummyflasher.c
tmp = extract_programmer_param("spi_blacklist");
if (tmp) {
Is there any reason why tmp is declared for whole function instead as variable used only in this block?
tmp is used several times in this function, but tmp2 could trivially be placed within a tighter scope.
On Thu, Jan 20, 2011 at 5:36 PM, Maciej Pijanka maciej.pijanka@gmail.com wrote:
if (strspn(tmp2, "0123456789abcdef") != i) {
msg_perr("Invalid chars in SPI command
blacklist\n");
free(tmp);
return 1;
}
ABCDEF should probably be included in that set. Alternatively, maybe replace the if statement with a loop that checks each character in tmp2 using isxdigit(). The advantage with that approach is that you could tell the user which character(s) are invalid.
Hi,
I noticed that mixing two related patches is not a really good idea and decided to split them. David, I have reused your ack for this part. The other part (blacklist) will be changed to use isxdigit() and I'll resend it soon.
Auf 04.02.2011 01:42, David Hendricks schrieb:
Acked-by: David Hendricks dhendrix@google.com
Improve debugging for unaligned erase in the flash chip emulator. Fix out-of-bounds access for chip erase in the flash chip emulator.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net Acked-by: David Hendricks dhendrix@google.com
Index: flashrom-emulate_spi_flashchip_outofbounds/dummyflasher.c =================================================================== --- flashrom-emulate_spi_flashchip_outofbounds/dummyflasher.c (Revision 1258) +++ flashrom-emulate_spi_flashchip_outofbounds/dummyflasher.c (Arbeitskopie) @@ -395,7 +395,7 @@ } offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; if (offs & (emu_jedec_se_size - 1)) - msg_pdbg("Unaligned SECTOR ERASE 0x20\n"); + msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs); offs &= ~(emu_jedec_se_size - 1); memset(flashchip_contents + offs, 0xff, emu_jedec_se_size); break; @@ -412,7 +412,7 @@ } offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; if (offs & (emu_jedec_be_52_size - 1)) - msg_pdbg("Unaligned BLOCK ERASE 0x52\n"); + msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs); offs &= ~(emu_jedec_be_52_size - 1); memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size); break; @@ -429,7 +429,7 @@ } offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; if (offs & (emu_jedec_be_d8_size - 1)) - msg_pdbg("Unaligned BLOCK ERASE 0xd8\n"); + msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs); offs &= ~(emu_jedec_be_d8_size - 1); memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size); break; @@ -444,12 +444,9 @@ msg_perr("CHIP ERASE 0x60 insize invalid!\n"); return 1; } - offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; - if (offs & (emu_jedec_ce_60_size - 1)) - msg_pdbg("Unaligned CHIP ERASE 0x60\n"); - offs &= ~(emu_jedec_ce_60_size - 1); + /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */ /* emu_jedec_ce_60_size is emu_chip_size. */ - memset(flashchip_contents + offs, 0xff, emu_jedec_ce_60_size); + memset(flashchip_contents, 0xff, emu_jedec_ce_60_size); break; case JEDEC_CE_C7: if (!emu_jedec_ce_c7_size) @@ -462,10 +459,7 @@ msg_perr("CHIP ERASE 0xc7 insize invalid!\n"); return 1; } - offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3]; - if (offs & (emu_jedec_ce_c7_size - 1)) - msg_pdbg("Unaligned CHIP ERASE 0xc7\n"); - offs &= ~(emu_jedec_ce_c7_size - 1); + /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */ /* emu_jedec_ce_c7_size is emu_chip_size. */ memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size); break;
Auf 04.02.2011 23:48, Carl-Daniel Hailfinger schrieb:
Improve debugging for unaligned erase in the flash chip emulator. Fix out-of-bounds access for chip erase in the flash chip emulator.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net Acked-by: David Hendricks dhendrix@google.com
Committed in r1259.
Regards, Carl-Daniel
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\
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\
Looks good to me.
Acked-by: David Hendricks dhendrix@google.com