ping
On Tue, Oct 11, 2022 at 07:21:29PM +0300, Sergii Dmytruk wrote: > Hi again, > > As previously discussed on this ML, posting documentation inline for review. > > ================================================================================ > > # Firmware updates vs. SPI write-protection > > Enabling write-protection of any kind is meant to obstruct changing data, but > it > also limits what you can do to the part of firmware that's still writable. > This > document is meant to cover some of the origins of such limitations and > situations which might arise after part of a flash chip has been protected. > > ## Firmware updates after locking bootblock > > This section is primarily concerned with `coreboot`, but similar problems can > happen for any kind of firmware. > > ### Risks of partial updates > > Partial updates can produce an unbootable image if an old bootblock doesn't > work > with a more recent version of `coreboot`. This can be manifested in various > ways ranging from an old bootblock not being able to find new romstage to > system > booting successfully but data in `coreboot` tables being mangled or > incomplete. > > The incompatibilities might happen when switching version of firmware or even > when using the same version with a slightly different configuration. > > Another thing that can potentially cause trouble is CBFS layout. When > bootblock > is part of CBFS, it doesn't necessarily have a fixed address, moreover it can > change location as well if it depends on file size (when bootblock's last byte > must be the last byte of the image, which is the case on x86). If newer > bootblock is smaller such that an old WP range now covers bootblock and some > other file, this file won't be fully updated due to write-protection, > potentially resulting in a corrupt image. Luckily, when bootblock is the last > file it's normally preceded by a significant amount of empty space, which > won't > let this situation to occur. > > On top of that, last 4 bytes of the image contain offset to the master header > of > CBFS. Depending on the coreboot version this offset might be crucial for the > loading of romstage, in which case moving CBFS within the image without > updating > the offset (when it's locked by WP) can also prevent the system from booting. > > ### Recovering from a broken state > > Since broken flash won't let the system to boot, the way to fix it is to flash > the chip externally by connecting it to a different device. A possible > alternative could be to have a backup flash created beforehand and swapping it > for the broken one (mainly applicable if swapping doesn't require soldering). > > ## Flashing whole firmware image > > The function of the hardware protection mechanism (`W#` or `W/` pin of flash > chips) is to lock state of software protection thus preventing it from being > disabled. After the chip is physically unlocked by changing the state of the > pin, the state of the write protection doesn't change. However, in this state > the protection can be easily turned off programmatically, which is what > `flashrom` tries to do before performing an operation on a chip. > > In other words, changing state of the WP pin might be enough to be able to > flash the chip in full. If `flashrom` errors or you don't want to rely on the > automatic behaviour, you can try to explicitly disable the protection by > running > `flashrom` like this: > > ``` > flashrom --wp-disable > ``` > > If you need to pass extra parameters to flash your chip (e.g., programmer or > chip name), add them to the above command (order of such parameters shouldn't > matter). > > Mind that in `flashrom` the code for disabling protection automatically is > different from the code which handles `--wp-disable`. This means that they can > sometimes produce different results, this is why you should be aware of both > code paths that affect WP. > > ================================================================================ > > # Example of partial write-protection > > 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). > > ## `flashrom` version > > At the time of writing (11 October 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 > ``` > > ## 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, on Intel platforms *internal* programmer 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 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 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 troubles with future updates if that's some data or metadata which > changes with every release > > 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've happy with the configuration and changed state of WP pin, you can > try disabling WP using `flashrom` to make sure that it fails now. > > ================================================================================ > > Regards, > Sergii _______________________________________________ flashrom mailing list -- flashrom@flashrom.org To unsubscribe send an email to flashrom-le...@flashrom.org