Example of partial write-protection: Difference between revisions
(→Finding a matching range: Formatting and minor updates) |
(→Verifying hardware protection: Fix a typo) |
||
Line 206: | Line 206: | ||
Once you're happy with the configuration and changed state of WP pin, you can | Once you're happy with the configuration and changed state of WP pin, you can | ||
try disabling WP using <code>flashrom -- | try disabling WP using <code>flashrom --wp-disable</code> to make sure that it | ||
fails now. | fails now. |
Revision as of 15:45, 4 November 2022
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 the chip to prevent any attempt of disabling the protection by
software alone.
Not to be confused with protection by flash controller of your motherboard (PCH protection).
Version of flashrom
At the time of writing (4 November 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 # the simplest case of building using GNU make make # flashrom executable will appear in current directory
Alternatively, your operating system might provide development version of
flashrom
as a package.
Programmer support of WP
Not all programmers support manipulating WP configuration. A suitable programmer must either provide a dedicated API for working with WP or give sufficiently comprehensive access to the interface of the flash chip.
In particular, internal programmer on Intel platforms might allow only
limited access to WP feature of chips or effectively deny it. Read "Intel
chipsets" section of flashrom
's manpage for details on how you can
try choosing sequencing type to possibly make WP work for you.
In some cases external flashing might be the only option and you need to unscrew your device, find the chip, connect it to another device through a suitable adapter and finally be able to configure it as you wish.
Chip support in 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 for your chip and chipset doesn't get in the way. Run a
command like (adjust this and similar commands below if you're not using
internal programmer or need to specify 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 assumes 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 + 64 + bootblock offset):
12615680 + 64 + 0x3ef100 = 0xff7140
(printf "%#x\n" $(( 12615680 + 64 + 0x3ef100 ))
)
- end offset (start offset + bootblock size - 1):
0xff7140 + 36544 - 1 = 0xffffff
(printf "%#x\n" $(( 0xff7140 + 36544 - 1 ))
)
Thus we need to write-protect the smallest area that covers the range from
0xff7140
to 0xffffff
(both bounds are inclusive).
“64” in the computation of start offset is offset of booblock data. Unfortunately, current tooling doesn't provide a reliable way of determining actual offset, but 64 is the typical “extra offset” one needs to add to account for file metadata of CBFS (otherwise it can be its multiple 128 or bigger). Bootblock should normally end at the last byte of ROM on x86 systems, giving you a way to test the result of computations.
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 even by development version of flashrom
as of now
(4 November 2022).
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 or at 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 trouble with future updates if that's some data or metadata which changes with every release (see Firmware updates vs. SPI write-protection for more on this)
This is the first upper range starting before 0xff7140
:
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). Make sure that hardware
protection is off (state of W#
/W/
pin of the chip) or
you won't be able to change WP configuration.
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're happy with the configuration and changed state of WP pin, you can
try disabling WP using flashrom --wp-disable
to make sure that it
fails now.