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.