Skip to content

Commit d05e485

Browse files
committed
Documentation/bootblock-protection.md: add
Change-Id: Iaad1014fad5a60e78bef55c5f3aceaed782b66d6 Signed-off-by: Sergii Dmytruk <[email protected]>
1 parent 9c3ba8d commit d05e485

File tree

1 file changed

+218
-0
lines changed

1 file changed

+218
-0
lines changed

Documentation/bootblock-protection.md

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
This document provides demonstration of how one can protect part of a flash
2+
chip from writing using `flashrom` and its support for manipulating SPI write
3+
protection (WP). This kind of protection requires changing connection of WP
4+
pin of a chip to prevent any attempt of disabling the protection by software
5+
alone.
6+
7+
**Not to be confused** with protection by flash controller of your
8+
motherboard (PCH protection).
9+
10+
## `flashrom` version
11+
12+
At the time of writing (5 August 2022) there hasn't been a `flashrom` release
13+
that includes WP manipulation facilities. You might have to build one from
14+
scratch (assuming you've already installed build dependencies):
15+
16+
```
17+
git clone --depth 1 https://github.com/flashrom/flashrom
18+
cd flashrom
19+
make
20+
# flashrom executable will appear in current directory
21+
```
22+
23+
## Programmer support of WP
24+
25+
Not all programmers support manipulating WP configuration. A suitable
26+
programmer must either provide a dedicated API for working with WP or give
27+
sufficiently comprehensive access to the interface of the flash chip.
28+
29+
In particular, on Intel platforms internal programmer can allow only limited
30+
access to WP feature of chips or effectively deny it. Read "Intel chipsets"
31+
section of `flashrom`'s manpage for details on how you can try choosing
32+
sequencing type to possibly make WP work for you.
33+
34+
In some cases external flashing might be the only option and you need to
35+
unscrew your device, find the chip, connect it to another device through a
36+
suitable adapter and finally be able to configure it as you wish.
37+
38+
## Chip support by `flashrom`
39+
40+
There is a great variety of chips with some not supporting write protection at
41+
all and others doing it in their own peculiar way of which `flashrom` has no
42+
idea. So the first thing to do is to make sure that `flashrom` knows how WP
43+
works for your combination of chip and chipset doesn't get in the way. Run a
44+
command like (adjust this and similar commands below if you're not using
45+
internal programmer or need other options):
46+
47+
```
48+
flashrom --programmer internal --wp-status
49+
```
50+
51+
Seeing this output line would mean that `flashrom` doesn't know how to use WP
52+
feature of the chip you have:
53+
54+
```
55+
Failed to get WP status: WP operations are not implemented for this chip
56+
```
57+
58+
Otherwise the output might contain something similar to this:
59+
60+
```
61+
Protection range: start=0x00000000 length=0x00000000 (none)
62+
Protection mode: disabled
63+
```
64+
65+
If so, you can continue with the rest of the instructions.
66+
67+
## Collecting information about the range
68+
69+
You need to know where the area you want to protect starts and ends. The example
70+
below will assume you're trying to protect bootblock stored in CBFS at the end
71+
of some coreboot firmware. In other cases it might be a separate file which is
72+
put at the beginning of a chip. You need to have an idea of what you're doing
73+
here or have some reliable instructions to follow.
74+
75+
In this case `cbfstool` can be used to list information about bootblock like
76+
this:
77+
78+
```
79+
$ cbfstool rom print | sed -n '2p; /bootblock/p'
80+
Name Offset Type Size Comp
81+
bootblock 0x3ef100 bootblock 36544 none
82+
```
83+
84+
However, the offset is relative to the start of CBFS region, so we also need to
85+
find out offset of CBFS:
86+
87+
```
88+
$ cbfstool rom layout | grep CBFS
89+
'COREBOOT' (CBFS, size 4161536, offset 12615680)
90+
```
91+
92+
Now we can calculate:
93+
94+
* start offset (CBFS offset + 64 + bootblock offset): \
95+
`12615680 + 64 + 0x3ef100 = 0xff7140` \
96+
(`printf "%#x\n" $(( 12615680 + 64 + 0x3ef100 ))`)
97+
* end offset (start offset + bootblock size - 1): \
98+
`0xff7140 + 36544 - 1 = 0xffffff` \
99+
(`printf "%#x\n" $(( 0xff7140 + 36544 - 1 ))`)
100+
101+
Thus we need to write-protect the smallest area that covers the range from
102+
`0xff7140` to `0xffffff` (both bounds are inclusive).
103+
104+
"64" in the computation of start offset is offset of booblock data.
105+
Unfortunately, current tooling doesn't provide a reliable way of determining
106+
actual offset, but 64 is the typical "extra offset" one needs to add to account
107+
for file metadata of CBFS (otherwise it can be its multiple 128 or bigger).
108+
Bootblock should normally end at the last byte of ROM on x86 systems, giving you
109+
a way to test the result.
110+
111+
## Finding a matching range
112+
113+
In most chips, the list of supported ranges is fixed and you can't specify an
114+
arbitrary one. Some others allow more fine-grained control, but that feature is
115+
not supported by `flashrom` as of now.
116+
117+
Obtain list of supported ranges from which we'll pick the best match:
118+
119+
```
120+
$ flashrom --programmer internal --wp-list
121+
...
122+
Available protection ranges:
123+
start=0x00000000 length=0x00000000 (none)
124+
start=0x00000000 length=0x00001000 (lower 1/4096)
125+
start=0x00fff000 length=0x00001000 (upper 1/4096)
126+
start=0x00000000 length=0x00002000 (lower 1/2048)
127+
start=0x00ffe000 length=0x00002000 (upper 1/2048)
128+
start=0x00000000 length=0x00004000 (lower 1/1024)
129+
start=0x00ffc000 length=0x00004000 (upper 1/1024)
130+
start=0x00000000 length=0x00008000 (lower 1/512)
131+
start=0x00ff8000 length=0x00008000 (upper 1/512)
132+
start=0x00000000 length=0x00040000 (lower 1/64)
133+
start=0x00fc0000 length=0x00040000 (upper 1/64)
134+
start=0x00000000 length=0x00080000 (lower 1/32)
135+
start=0x00f80000 length=0x00080000 (upper 1/32)
136+
start=0x00000000 length=0x00100000 (lower 1/16)
137+
start=0x00f00000 length=0x00100000 (upper 1/16)
138+
start=0x00000000 length=0x00200000 (lower 1/8)
139+
start=0x00e00000 length=0x00200000 (upper 1/8)
140+
start=0x00000000 length=0x00400000 (lower 1/4)
141+
start=0x00c00000 length=0x00400000 (upper 1/4)
142+
start=0x00000000 length=0x00800000 (lower 1/2)
143+
start=0x00800000 length=0x00800000 (upper 1/2)
144+
start=0x00000000 length=0x00c00000 (lower 3/4)
145+
start=0x00400000 length=0x00c00000 (upper 3/4)
146+
start=0x00000000 length=0x00e00000 (lower 7/8)
147+
start=0x00200000 length=0x00e00000 (upper 7/8)
148+
start=0x00000000 length=0x00f00000 (lower 15/16)
149+
start=0x00100000 length=0x00f00000 (upper 15/16)
150+
start=0x00000000 length=0x00f80000 (lower 31/32)
151+
start=0x00080000 length=0x00f80000 (upper 31/32)
152+
start=0x00000000 length=0x00fc0000 (lower 63/64)
153+
start=0x00040000 length=0x00fc0000 (upper 63/64)
154+
start=0x00000000 length=0x00ff8000 (lower 511/512)
155+
start=0x00008000 length=0x00ff8000 (upper 511/512)
156+
start=0x00000000 length=0x00ffc000 (lower 1023/1024)
157+
start=0x00004000 length=0x00ffc000 (upper 1023/1024)
158+
start=0x00000000 length=0x00ffe000 (lower 2047/2048)
159+
start=0x00002000 length=0x00ffe000 (upper 2047/2048)
160+
start=0x00000000 length=0x00fff000 (lower 4095/4096)
161+
start=0x00001000 length=0x00fff000 (upper 4095/4096)
162+
start=0x00000000 length=0x01000000 (all)
163+
```
164+
165+
Pick a range by scanning the list in the top down order (because the smaller
166+
ranges come first):
167+
168+
- if bootblock is at the start of a chip, look for the first lower range whose
169+
length is greater than the end offset
170+
- if bootblock is at the end of a chip, look for the first upper range which
171+
starts before the start offset
172+
- mind that you're unlikely to find an ideal match and will probably protect
173+
more than you need; this is fine if that's just an empty space, but can
174+
cause troubles with future updates if that's some data or metadata which
175+
changes with every release
176+
177+
This is the first upper range starting before `0xff7140`:
178+
179+
```
180+
start=0x00fc0000 length=0x00040000 (upper 1/64)
181+
```
182+
183+
It covers `0x00fc0000 -- 0x00ffffff` which includes our bootblock. This area
184+
takes up 256 KiB, about 7 times bigger than our bootblock, but there is no better
185+
choice in this case and output of `cbfstool rom layout` shows that we
186+
additionally include a part of 876 KiB empty space which will hopefully remain
187+
there in future firmware versions (it's a good idea to check before a firmware
188+
update).
189+
190+
## Protection setup
191+
192+
The following command sets the range and enables WP at the same time, the values
193+
are taken from the chosen range above:
194+
195+
```
196+
flashrom --programmer internal --wp-range=0x00fc0000,0x00040000 --wp-enable
197+
```
198+
199+
You can set the range and change WP status independently as well if needed
200+
(just specify one `--wp-*` option at a time). No need to disable protection for
201+
changing the range (via `--wp-disable`), just make sure that hardware
202+
protection is off (state of `W#`/`W/` pin of the chip).
203+
204+
On success, the output of the above command will include such lines:
205+
206+
```
207+
Enabled hardware protection
208+
Activated protection range: start=0x00fc0000 length=0x00040000 (upper 1/64)
209+
```
210+
211+
**Caveat**: `flashrom` automatically tries to disable WP before any operation
212+
on a chip (read, write, erase, verify), so double-check status of WP before
213+
changing state of WP pin on your chip!
214+
215+
## Verifying hardware protection
216+
217+
Once you've happy with the configuration and changed state of WP pin, you can
218+
try disabling WP using `flashrom` to make sure that it the operation now fails.

0 commit comments

Comments
 (0)