SPI Flash reader
Like ho.ax, I had been using a Dangerous Prototypes buspirate to read SPI flash boot ROMs, but it was too slow. So I built a dedicated one with a Teensy 2 or 3 and a 8-SOIC chip-clip. It can read/write the entire multi-megabit ROM in a minute. Sources are available from bitbucket.org/hudson/spiflash.
Spotting boot ROMs
These pins are large enough that it is easy to attach with a buspirate/logic-probe clips or using a dedicated chip clip that connects to all eight pins at once. On the bottom of the Teensy 2 there is a pad footprint for a 3.3 volt regulator -- I've cut the trace and soldered one in, as described here. For the Teensy 3, which runs at native 3.3V, no hardware modifications are required.
Most laptops and some servers use 8-pin chips in either SOIC or DIP packages:
+------+ (white) B0 !CE ---| o |---- +V 3v3 (red or brown) (brown) B3 SO ---| |---- !RST !WP ---| |---- SCK B1 (green) (black) GND GND ---| |---- SI B2 (blue) +------+
For the 16-pin chips typically found on server motherboards, the pinout is:
NC ---- 1 o 16 --- CLK Vcc (3v)- 2 W 15 --- DI NC ---- 3 I 14 --- NC NC ---- 4 N 13 --- NC NC ---- 5 B 12 --- NC NC ---- 6 O 11 --- NC /CS ---- 7 N 10 --- GND DO ---- 8 D 9 --- NC
Sometimes the SPI flash chip doesn't respond to the
i command -- the result comes back as all 0xFF. If I cycle power to the chip a few times it starts to respond. I'm not sure what the root cause is of this, but to make it easier I've put a separate jumper on the power pin from the teensy to the SOIC chip. This allows me to cycle the power until I get a good read of the chip ID.
Some MacBooks have debug ports on them that connect to the SPI flash ROM (and maybe other interesting debug signals?). I've probed the MacBookPro 10,1 and mapped the pinout for almost all of the SPI signals, with the exception of Power and !WP.
The reader should show up as a serial device on your computer. It has a the following simple commands:
i: Read chip ID; if all 0xFF or 0x00, then something is wrong. The format of the ID result is described in the data sheet and JEDEC standard:
r7f0000↵: read 16 bytes from 0x7f0000 and hex dump them.
e7f0000↵: erase a sector at address 7f0000. You shouldn't need to do this since the upload command will erase sectors as it crosses them.
u190000 1a0000↵: Upload (and erase) 0x1a0000 bytes to 0x190000. Typically I will then shell out from minicom and run pv; you could also use
catalthough it wouldn't give you any feedback on the transfer:
pv new-rom.section.rom > /dev/ttyACM0
The entire ROM can be read using xmodem. Shell out from minicom and run:
rx < /dev/ttyACM0 > /dev/ttyACM0 rom.bin
More details on reverse engineering a ROM are described in my Thunderstrike talk at 31c3.