forked from flashrom/flashrom
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Documentation/bootblock-protection.md: add
Change-Id: Iaad1014fad5a60e78bef55c5f3aceaed782b66d6 Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
- Loading branch information
1 parent
cf23702
commit 7861129
Showing
1 changed file
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
This document provides demonstration of how one can protect part of a flash | ||
chip from writing using `flashrom` and its support for manipulating SPI write | ||
protection (WP). This kind of protection requires changing connection of WP | ||
pin of a chip to prevent any attempt of disabling the protection by software | ||
alone. To not be confused with protection by flash controller of your | ||
motherboard (PCH protection). | ||
|
||
## `flashrom` version | ||
|
||
At the time of writing (5 August 2022) there hasn't been a `flashrom` release | ||
that includes WP manipulation facilities. You might have to build one from | ||
scratch (assuming you've already installed build dependencies): | ||
|
||
``` | ||
git clone --depth 1 https://github.com/flashrom/flashrom | ||
cd flashrom | ||
make | ||
# flashrom executable will appear in current directory | ||
``` | ||
|
||
## Chip support by `flashrom` | ||
|
||
There is a great variety of chips with some not supporting write protection at | ||
all and others doing it in their own peculiar way of which `flashrom` has no | ||
idea. So the first thing to do is to make sure that `flashrom` knows how WP | ||
works in your particular chip. Run a command like (adjust this and similar | ||
commands below if you're not using internal programmer or need other options): | ||
|
||
``` | ||
flashrom --programmer internal --wp-status | ||
``` | ||
|
||
Seeing this output line would mean that `flashrom` doesn't know how to use WP | ||
feature of the chip you have: | ||
|
||
``` | ||
Failed to get WP status: WP operations are not implemented for this chip | ||
``` | ||
|
||
Otherwise the output might contain something similar to this: | ||
|
||
``` | ||
Protection range: start=0x00000000 length=0x00000000 (none) | ||
Protection mode: disabled | ||
``` | ||
|
||
If so, you can continue with the rest of the instructions. | ||
|
||
## Collecting information about the range | ||
|
||
You need to know where the area you want to protect starts and ends. The example | ||
below will assume you're trying to protect bootblock stored in CBFS at the end | ||
of some coreboot firmware. In other cases it might be a separate file which is | ||
put at the beginning of a chip. You need to have an idea of what you're doing | ||
here or have some reliable instructions to follow. | ||
|
||
In this case `cbfstool` can be used to list information about bootblock like | ||
this: | ||
|
||
``` | ||
$ cbfstool rom print | sed -n '2p; /bootblock/p' | ||
Name Offset Type Size Comp | ||
bootblock 0x3ef100 bootblock 36544 none | ||
``` | ||
|
||
However, the offset is relative to the start of CBFS region, so we also need to | ||
find out offset of CBFS: | ||
|
||
``` | ||
$ cbfstool rom layout | grep CBFS | ||
'COREBOOT' (CBFS, size 4161536, offset 12615680) | ||
``` | ||
|
||
Now we can calculate: | ||
|
||
* start offset (CBFS offset + bootblock offset): \ | ||
`12615680 + 0x3ef100 = 0xff7100` \ | ||
(`printf "%#x\n" $(( 12615680 + 0x3ef100 ))`) | ||
* end offset (start offset + bootblock size - 1): \ | ||
`0xff7100 + 36544 - 1 = 0xffffbf` \ | ||
(`printf "%#x\n" $(( 0xff7100 + 36544 - 1 ))`) | ||
|
||
Thus we need to write-protect the smallest area that covers the range from | ||
`0xff7100` to `0xffffbf` (both bounds are inclusive). | ||
|
||
## Finding a matching range | ||
|
||
In most chips, the list of supported ranges is fixed and you can't specify an | ||
arbitrary one. Some others allow more fine-grained control, but that feature is | ||
not supported by `flashrom` as of now. | ||
|
||
Obtain list of supported ranges from which we'll pick the best match: | ||
|
||
``` | ||
$ flashrom --programmer internal --wp-list | ||
... | ||
Available protection ranges: | ||
start=0x00000000 length=0x00000000 (none) | ||
start=0x00000000 length=0x00001000 (lower 1/4096) | ||
start=0x00fff000 length=0x00001000 (upper 1/4096) | ||
start=0x00000000 length=0x00002000 (lower 1/2048) | ||
start=0x00ffe000 length=0x00002000 (upper 1/2048) | ||
start=0x00000000 length=0x00004000 (lower 1/1024) | ||
start=0x00ffc000 length=0x00004000 (upper 1/1024) | ||
start=0x00000000 length=0x00008000 (lower 1/512) | ||
start=0x00ff8000 length=0x00008000 (upper 1/512) | ||
start=0x00000000 length=0x00040000 (lower 1/64) | ||
start=0x00fc0000 length=0x00040000 (upper 1/64) | ||
start=0x00000000 length=0x00080000 (lower 1/32) | ||
start=0x00f80000 length=0x00080000 (upper 1/32) | ||
start=0x00000000 length=0x00100000 (lower 1/16) | ||
start=0x00f00000 length=0x00100000 (upper 1/16) | ||
start=0x00000000 length=0x00200000 (lower 1/8) | ||
start=0x00e00000 length=0x00200000 (upper 1/8) | ||
start=0x00000000 length=0x00400000 (lower 1/4) | ||
start=0x00c00000 length=0x00400000 (upper 1/4) | ||
start=0x00000000 length=0x00800000 (lower 1/2) | ||
start=0x00800000 length=0x00800000 (upper 1/2) | ||
start=0x00000000 length=0x00c00000 (lower 3/4) | ||
start=0x00400000 length=0x00c00000 (upper 3/4) | ||
start=0x00000000 length=0x00e00000 (lower 7/8) | ||
start=0x00200000 length=0x00e00000 (upper 7/8) | ||
start=0x00000000 length=0x00f00000 (lower 15/16) | ||
start=0x00100000 length=0x00f00000 (upper 15/16) | ||
start=0x00000000 length=0x00f80000 (lower 31/32) | ||
start=0x00080000 length=0x00f80000 (upper 31/32) | ||
start=0x00000000 length=0x00fc0000 (lower 63/64) | ||
start=0x00040000 length=0x00fc0000 (upper 63/64) | ||
start=0x00000000 length=0x00ff8000 (lower 511/512) | ||
start=0x00008000 length=0x00ff8000 (upper 511/512) | ||
start=0x00000000 length=0x00ffc000 (lower 1023/1024) | ||
start=0x00004000 length=0x00ffc000 (upper 1023/1024) | ||
start=0x00000000 length=0x00ffe000 (lower 2047/2048) | ||
start=0x00002000 length=0x00ffe000 (upper 2047/2048) | ||
start=0x00000000 length=0x00fff000 (lower 4095/4096) | ||
start=0x00001000 length=0x00fff000 (upper 4095/4096) | ||
start=0x00000000 length=0x01000000 (all) | ||
``` | ||
|
||
Pick a range by scanning the list in the top down order (because the smaller | ||
ranges come first): | ||
|
||
- if bootblock is at the start of a chip, look for the first lower range whose | ||
length is greater than the end offset | ||
- if bootblock is at the end of a chip, look for the first upper range which | ||
starts before the start offset | ||
- mind that you're unlikely to find an ideal match and will probably protect | ||
more than you need; this is fine if that's just an empty space, but can | ||
cause troubles with future updates if that's some data or metadata which | ||
changes with every release | ||
|
||
This is the first upper range starting before `0xff7100`: | ||
|
||
``` | ||
start=0x00fc0000 length=0x00040000 (upper 1/64) | ||
``` | ||
|
||
It covers `0x00fc0000 -- 0x00ffffff` which includes our bootblock. This area | ||
takes up 256 KiB, about 7 times bigger than our bootblock, but there is no better | ||
choice in this case and output of `cbfstool rom layout` shows that we | ||
additionally include a part of 876 KiB empty space which will hopefully remain | ||
there in future firmware versions (it's a good idea to check before a firmware | ||
update). | ||
|
||
## Protection setup | ||
|
||
The following command sets the range and enables WP at the same time, the values | ||
are taken from the chosen range above: | ||
|
||
``` | ||
flashrom --programmer internal --wp-range=0x00fc0000,0x00040000 --wp-enable | ||
``` | ||
|
||
You can set the range and change WP status independently as well if needed | ||
(just specify one `--wp-*` option at a time). No need to disable protection for | ||
changing the range (via `--wp-disable`), just make sure that hardware | ||
protection is off (state of `W#`/`W/` pin of the chip). | ||
|
||
On success, the output of the above command will include such lines: | ||
|
||
``` | ||
Enabled hardware protection | ||
Activated protection range: start=0x00fc0000 length=0x00040000 (upper 1/64) | ||
``` | ||
|
||
**Caveat**: `flashrom` automatically tries to disable WP before any operation | ||
on a chip (read, write, erase, verify), so double-check status of WP before | ||
changing state of WP pin on your chip! | ||
|
||
## Verifying hardware protection | ||
|
||
Once you've happy with the configuration and changed state of WP pin, you can | ||
try disabling WP using `flashrom` to make sure that it the operation now fails. |