Un-bricking a MacBook

In my tinkering with EFI I attempted to flash some backdoored firmware to a test MacBook that was kindly donated to science by a friend of mine. This resulted in the bastard doing the S.O.S. beeps and not booting, and it didn’t seem to be recoverable using the Firmware Restore CDs from Apple. I decided that since it was dead anyway I might as well try and recover it by re-flashing the firmware manually using the nifty Bus Pirate that I impulse-bought not long ago, and a copy of flashrom.

First things first - an appropriate beer:

Beer

Next, I disassembled the MacBook with the help of the iFixit MacBook take apart guide (wasn’t exactly the right model, but close enough). Here’s the remains of the machine after I removed the logic board:

Gut shot

I had to hunt around on the board a bit to find the flash that contains the EFI firmware, but knowing the model number from when I bricked it helped. Found it!

Flash chip

Now that I’d found the flash I had to wire up the Bus Pirate and hope the chip would be programmable in-circuit without any hassles:

Wired

After a few false starts and some confusion with wiring between Bus Pirate versions, flashrom detected the chip:

# flashrom -V -p buspirate_spi:dev=/dev/tty.usbserial-A800KC47
flashrom v0.9.5.2-r1515 on Darwin 11.3.0 (x86_64), built with libpci 3.1.7, LLVM Clang 3.1 (tags/Apple/clang-318.0.58), little endian
flashrom is free software, get the source code at http://www.flashrom.org

Calibrating delay loop... OS timer resolution is 1 usecs, 1619M loops per second, 10 myus = 10 us, 100 myus = 101 us, 1000 myus = 1015 us, 10000 myus = 9863 us, 4 myus = 3 us, OK.
Initializing buspirate_spi programmer
SPI speed is 8MHz
Raw bitbang mode version 1
Raw SPI mode version 1
The following protocols are supported: SPI.
Probing for AMIC A25L05PT, 64 kB: RDID byte 0 parity violation. probe_spi_rdid_generic: id1 0x00, id2 0x00
<snip>
Probing for SST SST25VF016B, 2048 kB: probe_spi_rdid_generic: id1 0xbf, id2 0x2541
Chip status register is 1c
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 set
Chip status register: Bit 3 / Block Protect 1 (BP1) is set
Chip status register: Bit 2 / Block Protect 0 (BP0) is set
Chip status register: Write Enable Latch (WEL) is not set
Chip status register: Write In Progress (WIP/BUSY) is not set
Resulting block protection : all
Found SST flash chip "SST25VF016B" (2048 kB, SPI) on buspirate_spi.
Probing for SST SST25VF032B, 4096 kB: probe_spi_rdid_generic: id1 0xbf, id2 0x2541
Found SST flash chip "SST25VF016B" (2048 kB, SPI).
No operations were specified.
Raw bitbang mode version 1
Bus Pirate shutdown completed.

Looking good! So next I read back the dodgy firmware to make sure it looked like everything was working OK:

# flashrom -V -p buspirate_spi:dev=/dev/tty.usbserial-A800KC47,spispeed=8M -r macbook_buspirate.rom
<snip>
Found SST flash chip "SST25VF016B" (2048 kB, SPI).
Some block protection in effect, disabling
Missing status register write definition, assuming EWSR is needed
Reading flash... done.
Raw bitbang mode version 1
Bus Pirate shutdown completed.

This took a good half hour plus, maybe 45 minutes. Apparently there are some recent Bus Pirate speedups for flashrom but I didn’t wanna mess with it since it was working. A quick look at the firmware that was read back, and it looks OK compared to the original one that I read before flashing the dodgy one:

# hexdump macbook_buspirate.rom|head -5
0000000 00 00 00 00 00 00 00 00 bc e5 c8 87 00 00 00 00
0000010 d9 54 93 7a 68 04 4a 44 81 ce 0b f6 17 d8 90 df
0000020 00 00 19 00 00 00 00 00 5f 46 56 48 ff 8e ff ff
0000030 48 00 fd de 00 00 00 01 19 00 00 00 00 00 01 00
0000040 00 00 00 00 00 00 00 00 25 71 52 11 b2 78 3e 4d

# hexdump dump_from_macbook.fd|head -5
0000000 00 00 00 00 00 00 00 00 bc e5 c8 87 00 00 00 00
0000010 d9 54 93 7a 68 04 4a 44 81 ce 0b f6 17 d8 90 df
0000020 00 00 19 00 00 00 00 00 5f 46 56 48 ff 8e ff ff
0000030 48 00 fd de 00 00 00 01 19 00 00 00 00 00 01 00
0000040 00 00 00 00 00 00 00 00 25 71 52 11 b2 78 3e 4d

Time to write the original firmware back to the flash chip:

# flashrom -V -p buspirate_spi:dev=/dev/tty.usbserial-A800KC47,spispeed=8M -w dump_from_macbook.fd
flashrom v0.9.5.2-r1515 on Darwin 11.3.0 (x86_64), built with libpci 3.1.7, LLVM Clang 3.1 (tags/Apple/clang-318.0.58), little endian
flashrom is free software, get the source code at http://www.flashrom.org

Calibrating delay loop... OS timer resolution is 1 usecs, 1597M loops per second, 10 myus = 11 us, 100 myus = 100 us, 1000 myus = 1001 us, 10000 myus = 10081 us, 4 myus = 4 us, OK.
Initializing buspirate_spi programmer
SPI speed is 8MHz
Raw bitbang mode version 1
Raw SPI mode version 1
The following protocols are supported: SPI.
Probing for AMIC A25L05PT, 64 kB: RDID byte 0 parity violation. probe_spi_rdid_generic: id1 0x00, id2 0x00
<snip>
Found SST flash chip "SST25VF016B" (2048 kB, SPI).
Some block protection in effect, disabling
Missing status register write definition, assuming EWSR is needed
Reading old flash chip contents... done.
Erasing and writing flash chip... Trying erase function 0... 0x000000-0x000fff:S, 0x001000-0x001fff:S, 0x002000-0x002fff:S,
<snip>
0x1fe000-0x1fefff:S, 0x1ff000-0x1fffff:S
Erase/write done.
Verifying flash... VERIFIED.          
Raw bitbang mode version 1
Bus Pirate shutdown completed.

This took about 3 times as long as the read, as it had to read the flash back, erase the chip (which was pretty quick), write the new firmware, and then read the firmware back again to verify the write. After reassembling the machine:

Reassemble

It booted first go! I was honestly pretty surprised that I didn’t destroy something. Unfortunately the screen backlight is broken (which is why it was donated to science in the first place), so it’s a bit hard to see that it still works:

Boot

flashrom rules. Bus Pirate rules.