Removing SPI chip protection on xx20 ThinkPads

In order to be able to flash BIOS on SandyBridge Lenovo ThinkPads (X220, T420, T520), all SPI Protected Range registers (SPIBAR+0x74) must have WP bit set to 0 (or they must protect something else, but not the bios region). Other security measures, such as BLE and SMM_BWP are not enabled on these machines.

Lenovo BIOS uses PR0 register correctly and write-protects 0x00780000-0x01FFFFFF:

$ sudo python chipsec_main.py -m chipsec.modules.common.bios_wp
[*] BIOS Region: Base = 0x00500000, Limit = 0x007FFFFF
SPI Protected Ranges
------------------------------------------------------------
PRx (offset) | Value    | Base     | Limit    | WP? | RP?
------------------------------------------------------------
PR0 (74)     | 9FFF0780 | 00780000 | 01FFFFFF | 1   | 0 
PR1 (78)     | 00000000 | 00000000 | 00000000 | 0   | 0 
PR2 (7C)     | 00000000 | 00000000 | 00000000 | 0   | 0 
PR3 (80)     | 00000000 | 00000000 | 00000000 | 0   | 0 
PR4 (84)     | 00000000 | 00000000 | 00000000 | 0   | 0 

You may want to patch the BIOS to disable this protection. One reason that comes to mind, as to why would you ever want that, is that if you're a coreboot developer and want to switch between stock BIOS and coreboot quickly and internally.

Open the BIOS dump in UEFITool, find the LenovoFlashProtectPei.efi module and extract the PE32 image body:

Disassemble the extracted file. You can use r2, but even objdump is enough in this case:

$ objdump -d LenovoFlashProtectPei.efi

Find the place where PR0 is set:

...
fffcc3e6:       a1 f0 80 0f f8          mov    0xf80f80f0,%eax
fffcc3eb:       c1 e9 0c                shr    $0xc,%ecx
fffcc3ee:       56                      push   %esi
fffcc3ef:       81 e1 ff 1f 00 00       and    $0x1fff,%ecx
fffcc3f5:       81 c9 00 00 ff 9f       or     $0x9fff0000,%ecx   ; Here the WP bit is set
fffcc3fb:       6a fe                   push   $0xfffffffe
fffcc3fd:       8b d1                   mov    %ecx,%edx
fffcc3ff:       59                      pop    %ecx
fffcc400:       23 c1                   and    %ecx,%eax
fffcc402:       66 8b 80 04 38 00 00    mov    0x3804(%eax),%ax   ; 0x3804 is the offset of HSFS
fffcc409:       8b 35 f0 80 0f f8       mov    0xf80f80f0,%esi
fffcc40f:       23 f1                   and    %ecx,%esi
fffcc411:       8b b6 74 38 00 00       mov    0x3874(%esi),%esi  ; 0x3874 is the offset of PR0 
fffcc417:       66 85 c0                test   %ax,%ax
fffcc41a:       b8 74 38 00 00          mov    $0x3874,%eax
fffcc41f:       79 63                   jns    0xfffcc484
...

You just need to change 0x9fff0000 to 0x0fff0000. So find this place in hex editor:

81 c9 00 00 ff 9f 6a fe

and make it:

81 c9 00 00 ff 0f 6a fe

Replace the module:

Save updated image (File -> Save image file).

Now you can flash it using external SPI programmer and the PR0 region will not be write protected.

If you have any comments, contact me by email.
powered by OpenBSD
© ch1p 2019