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