Fallback mechanism: Difference between revisions

From coreboot
Jump to navigation Jump to search
(some options moved to the `Chipset` menu)
 
(127 intermediate revisions by 3 users not shown)
Line 1: Line 1:
== Introduction ==
== Introduction ==
The fallback mecanism permits to have 2 different romstage,ramstage,payload in the same images under a different prefix.
This mechanism permits to test and recover from certain non-booting coreboot images.
The switch between both can be governed by an nvram configuration parameter.


== New Howto (depends on code that is not yet merged) ==
This works by having two coreboot images in the same flash chip:
* One fallback/ image: The working image.
* One normal/ image: The image to be tested.


* The code dependencies  can be found [http://review.coreboot.org/#/q/status:open+project:coreboot+branch:master+topic:falback-patches-v2,n,z in gerrit]
This feature is not widely tested on all boards. It also requires it to have a reboot_counter exported in the CMOS layout.


=== Mandatory configuration (in make menuconfig) ===
This also doesn't protect against human errors when using such feature, or bugs in the code responsible for switching between the two images.
You will have to make two configurations:
* one for the fallback image
* one for the normal image
==== First image ====
start configuring the first image with:
make menuconfig
Then configure it like that:


Go in the following menu:
== Uses cases ==
Architecture (x86)  --->
* Test new images way faster: if the image doesn't boot it will fallback on the old known-working image and save a long reflashing procedure. Handy for bisecting faster.
And then select that:
* Test new images more safely: Despite of the recommendations of having a way to externally reflash, many new user don't. Still, this method is not totally foolproof.
Bootblock behaviour (Switch to normal if CMOS says so)  --->
* More compact testing setup: Since reflashing tools are not mandatory anymore, the tests can be done with less hardware, very useful when traveling.
Which will bring that menu:
 
( ) Always load fallback
== How it works ==
(X) Switch to normal if CMOS says so
Coreboot increments a reboot count at each boot but never clears it. What runs after coreboot is responsible for that.
Select the "Switch to normal if CMOS says so" line like described above.
 
That way, the count can be cleared by the OS once it's fully booted.
 
If a certain threshold<ref>Defined by CONFIG_MAX_REBOOT_CNT, typically 3</ref> is attained at boot, coreboot will boot the fallback image.


In order to know if your computer booted correctly the last time, coreboot reads it in the nvram.
== Warnings ==
There are two ways to make it know that it booted fine the last time:
Because we uses two images, it's easy to wrongly identify which image booted:
* The automatic way, which happens inside the ramstage of coreboot.
* If the user mistakenly thinks the normal image is booting...
* The manual way, which happens when you want after the ramstage.
* But the fallback image always boots...
* And the normal image doesn't work...
* And the user flashes the normal in fallback because she thinks it boots fine...
* Then the user bricked her device and has to reflash it externally.


If you want it to happen after the ramstage Select the following menu:
== Fallback build  ==
  General setup  --->
To configure it for fallback, do:
And inside select the following if you want the manual way:
  $ make menuconfig
[*] Keep boot count
Then in "General setup  --->", near the top use "fallback" in "CBFS prefix to use":
Or don't select it if you want the automatic way:
[ ] Keep boot count
In any case, make sure that you have:
(fallback-mode) Local version string
  (fallback) CBFS prefix to use
  (fallback) CBFS prefix to use
Then near the bottom, make sure to have:
[ ] Update existing coreboot.rom image
And in the "Chipset  --->" menu at the bottom:
Bootblock behaviour (Switch to normal if CMOS says so)  --->
[*] Do not clear reboot count after successful boot


Verify that you have the following in .config (that make menuconfig just generated if you followed the previous instructions correctly)
You can then build the fallback image with the [[Fallback mechanism/fallback.sh|fallback.sh]] script.
CONFIG_X86_BOOTBLOCK_NORMAL=y
CONFIG_BOOTBLOCK_SOURCE="bootblock_normal.c"
And that you have:
CONFIG_LOCALVERSION="fallback-mode"
CONFIG_CBFS_PREFIX="fallback"
 
If you selected "Keep boot count", also verify that you have:
CONFIG_KEEP_BOOT_COUNT=y


At the end copy the .config to defconfig-fallback (that will erase the file named defconfig-fallback if there was one):
== Normal build ==
cp .config defconfig-fallback
To configure it for normal, do:
==== Second image ====
  $ make menuconfig
After configuring the first image, you should configure the second one.
Then in "General setup  --->", near the top use "normal" in "CBFS prefix to use":
use "make menuconfig" again to change the current configuration in .config (you already copied it to defconfig-fallback, so you will only modify a copy of it).
  make menuconfig
Then go in "General setup"
General setup  --->
And modify the prefix and the version string to look like that:
(normal-mode) Local version string
  (normal) CBFS prefix to use
  (normal) CBFS prefix to use
So that the second image that we will build later will be put in the "normal/" prefix and not in the "fallback/" one.
Then near the bottom, make sure to have:
 
Then go in Architecture:
Architecture (x86)  --->
And enable the "Update existing coreboot.rom image" option:
  [*] Update existing coreboot.rom image
  [*] Update existing coreboot.rom image
And in the "Chipset  --->" menu at the bottom:
Bootblock behaviour (Switch to normal if CMOS says so)  --->
[*] Do not clear reboot count after successful boot


At the end copy the .config to defconfig-normal (that will erase the file named defconfig-normal if there was one):
You can then build with the normal part with the [[Fallback mechanism/normal.sh|normal.sh]] script. It takes an existing coreboot image as argument.
cp .config defconfig-normal


==== Pseudo-diff ====
== OS configuration ==
Then compare the two resulting configurations to be sure of what you did:
$ diff -u defconfig-fallback defconfig-normal


The output should look a bit like that but with more context lines(the lines not starting with a "+" or a "-"):
=== The manual way ===
--- defconfig-fallback 2013-10-26 22:27:19.471326092 +0200
An approach is to run switch-to-normal.sh before trying an image.
+++ defconfig-normal 2013-10-26 22:26:44.471328732 +0200
It's however more error prone than the systemd approach because:
-CONFIG_LOCALVERSION="fallback-mode"
* you have to do it manually, each time, before testing an image.
-CONFIG_CBFS_PREFIX="fallback"
* If you then want to use that new image, you have to flash it, again, to fallback.
+CONFIG_LOCALVERSION="normal-mode"
+CONFIG_CBFS_PREFIX="normal"
-# CONFIG_UPDATE_IMAGE is not set
+CONFIG_UPDATE_IMAGE=y


=== Compilation ===
==== switch-to-normal.sh ====
==== Build script ====
  #!/bin/sh
  #!/bin/sh
  # In the cases where this work is copyrightable, it falls under the GPLv2
  nvramtool -w boot_option=Normal
# or later license that is available here:
  nvramtool -w reboot_counter=0
# https://www.gnu.org/licenses/gpl-2.0.txt
die() {
echo
echo "!!!! Compilation failed !!!!"
exit 1
}
success() {
echo
echo "!!!! Compilation finished !!!!"
echo
}
separator() {
echo
echo "!!!! First prefix compilation finished !!!!"
echo
}
make clean || die
#fallback image
cp defconfig-fallback .config  || die
make  || die
./build/cbfstool ./build/coreboot.rom add -f .config -n config-fallback -t raw  || die
#because it will be re-included it in the second build...
#./build/cbfstool ./build/coreboot.rom remove -n etc/ps2-keyboard-spinup  || die
./build/cbfstool ./build/coreboot.rom remove -n pci8086,109a.rom  || die
cp ./build/coreboot.rom ./build-save/coreboot.rom.fallback || die
make clean || die
mkdir -p build/
cp ./build-save/coreboot.rom.fallback ./build/coreboot.rom || die
separator
#second prefix's build.
#normal image
  cp defconfig-normal .config  || die
make  || die
./build/cbfstool ./build/coreboot.rom add -f .config -n config-normal -t raw  || die
success
 
=== Use it ===
If you chose the following option:
  [*] Keep boot count
Then you or something will need to tell coreboot that the computer booted correctly.
Here are some example scripts.


==== set-fallback-1.sh ====
==== switch-to-fallback.sh ====
  #!/bin/sh
  #!/bin/sh
  nvramtool -w boot_option=Fallback
  nvramtool -w boot_option=Fallback
  nvramtool -w last_boot=Fallback
  nvramtool -w reboot_counter=15
nvramtool -w reboot_bits=1
 
==== set-normal-0.sh ====
(Assuming that 15 is the maximum that can be stored in reboot_counter.)
#!/bin/sh
 
nvramtool -w boot_option=Normal
=== Systemd ===
nvramtool -w last_boot=Normal
Here we use systemd to automatically reset the boot counter after each successful boot (or resume).
nvramtool -w reboot_bits=0
 
We are then supposed to use the normal image daily and only resort to fallback in case of issues.
 
To install it, first install nvramtool (from coreboot sources):
$ cd util/nvramtool
$ make
$ sudo make install
 
Then add the following systemd units at their respective paths:
* [[Fallback_mechanism/coreboot@boot.service|/etc/systemd/system/coreboot@boot.service]]
* [[Fallback_mechanism/coreboot@resume.service|/etc/systemd/system/coreboot@resume.service]]
 
Then enable them with:
$ sudo systemctl enable coreboot@boot.service
$ sudo systemctl start coreboot@boot.service
$ sudo systemctl enable coreboot@resume.service
$ sudo systemctl start coreboot@resume.service
 
== Current limitations ==
* '''Use of the same cmos.layout in fallback and normal !'''
* The user may wrongly identify which image booted, and because of that, end up reflashing a non-working image.
* Some issues can arrise when the nvram layout is not the same between normal/ and fallback/
* The number of failed boot is fixed at compilation time.
* In order to fully boot, some boards do reset conditionally during the boot process resulting in a non-predictable increment of the boot count.
* Example script exist only for systemd. Still, they are trivial to adapt to other init systems.
* Payloads sometime have fixed default locations when loading things from cbfs:
** When using grub as a payload, grub.cfg is at etc/grub.cfg by default, so if you want to test grub as a payload, remember to change grub.cfg's path not to interfer with the fallback's grub configuration.
** Changing the path of what SeaBIOS loads from cbfs is probably configurable with SeaBIOS cbfs symlinks but not yet tested/documented with the use of the fallback mecanism
* Tested boards need to be listed somewhere.


==== get-nvram.sh ====
== Issues ==
#!/bin/sh
=== thinkpad_acpi ===
nvramtool -a | grep -e boot_option -e last_boot -e reboot_bits
This linux driver can have some bad interactions with the fallback/normal mecanism: when using it with the volume_control=1 option, volume_mode=1 is required, otherwise after shutting down the computer, it will always boot from fallback.


== Old Howto (will be replaced) ==
This might be because as the default settings of volume_mode touches the nvram, it probably corrupts it at shutdown when saving the alsa state of the volume buttons "sound card" (called EC Mixer). Then at boot, coreboot will detects a corrupted nvram and restore its valid defaults.
* build the coreboot image as usual, it will produce an image in build/coreboot.rom
* After the first build run:
make menuconfig
* Optionally change the payload.
* Go in
General setup  --->
* Change:
(fallback) CBFS prefix to use
To:
(normal) CBFS prefix to use
* Go back to the main menu and select:
Architecture (x86)  --->
select the following option:
[*] Update existing coreboot.rom image
Exit and save and rebuild...


The image will then have fallback and normal:
== references ==
Name                          Offset    Type        Size
<references/>
cmos_layout.bin                0x0        cmos_layout  1776
pci1002,9710.rom              0x740      optionrom    60928
fallback/romstage              0xf580    stage        92823
fallback/coreboot_ram          0x26080    stage        66639
fallback/payload              0x36540    payload      54976
config                        0x43c40    raw          4455
normal/romstage                0x44e00    stage        92823
normal/coreboot_ram            0x5b8c0    stage        68820
normal/payload                0x6c600    payload      159949
(empty)                        0x93700    null        442136

Latest revision as of 20:59, 25 February 2018

Introduction

This mechanism permits to test and recover from certain non-booting coreboot images.

This works by having two coreboot images in the same flash chip:

  • One fallback/ image: The working image.
  • One normal/ image: The image to be tested.

This feature is not widely tested on all boards. It also requires it to have a reboot_counter exported in the CMOS layout.

This also doesn't protect against human errors when using such feature, or bugs in the code responsible for switching between the two images.

Uses cases

  • Test new images way faster: if the image doesn't boot it will fallback on the old known-working image and save a long reflashing procedure. Handy for bisecting faster.
  • Test new images more safely: Despite of the recommendations of having a way to externally reflash, many new user don't. Still, this method is not totally foolproof.
  • More compact testing setup: Since reflashing tools are not mandatory anymore, the tests can be done with less hardware, very useful when traveling.

How it works

Coreboot increments a reboot count at each boot but never clears it. What runs after coreboot is responsible for that.

That way, the count can be cleared by the OS once it's fully booted.

If a certain threshold<ref>Defined by CONFIG_MAX_REBOOT_CNT, typically 3</ref> is attained at boot, coreboot will boot the fallback image.

Warnings

Because we uses two images, it's easy to wrongly identify which image booted:

  • If the user mistakenly thinks the normal image is booting...
  • But the fallback image always boots...
  • And the normal image doesn't work...
  • And the user flashes the normal in fallback because she thinks it boots fine...
  • Then the user bricked her device and has to reflash it externally.

Fallback build

To configure it for fallback, do:

$ make menuconfig

Then in "General setup --->", near the top use "fallback" in "CBFS prefix to use":

(fallback) CBFS prefix to use

Then near the bottom, make sure to have:

[ ] Update existing coreboot.rom image

And in the "Chipset --->" menu at the bottom:

Bootblock behaviour (Switch to normal if CMOS says so)  --->
[*] Do not clear reboot count after successful boot

You can then build the fallback image with the fallback.sh script.

Normal build

To configure it for normal, do:

$ make menuconfig

Then in "General setup --->", near the top use "normal" in "CBFS prefix to use":

(normal) CBFS prefix to use

Then near the bottom, make sure to have:

[*] Update existing coreboot.rom image

And in the "Chipset --->" menu at the bottom:

Bootblock behaviour (Switch to normal if CMOS says so)  --->
[*] Do not clear reboot count after successful boot

You can then build with the normal part with the normal.sh script. It takes an existing coreboot image as argument.

OS configuration

The manual way

An approach is to run switch-to-normal.sh before trying an image. It's however more error prone than the systemd approach because:

  • you have to do it manually, each time, before testing an image.
  • If you then want to use that new image, you have to flash it, again, to fallback.

switch-to-normal.sh

#!/bin/sh
nvramtool -w boot_option=Normal
nvramtool -w reboot_counter=0

switch-to-fallback.sh

#!/bin/sh
nvramtool -w boot_option=Fallback
nvramtool -w reboot_counter=15

(Assuming that 15 is the maximum that can be stored in reboot_counter.)

Systemd

Here we use systemd to automatically reset the boot counter after each successful boot (or resume).

We are then supposed to use the normal image daily and only resort to fallback in case of issues.

To install it, first install nvramtool (from coreboot sources):

$ cd util/nvramtool
$ make
$ sudo make install

Then add the following systemd units at their respective paths:

Then enable them with:

$ sudo systemctl enable coreboot@boot.service
$ sudo systemctl start coreboot@boot.service
$ sudo systemctl enable coreboot@resume.service
$ sudo systemctl start coreboot@resume.service

Current limitations

  • Use of the same cmos.layout in fallback and normal !
  • The user may wrongly identify which image booted, and because of that, end up reflashing a non-working image.
  • Some issues can arrise when the nvram layout is not the same between normal/ and fallback/
  • The number of failed boot is fixed at compilation time.
  • In order to fully boot, some boards do reset conditionally during the boot process resulting in a non-predictable increment of the boot count.
  • Example script exist only for systemd. Still, they are trivial to adapt to other init systems.
  • Payloads sometime have fixed default locations when loading things from cbfs:
    • When using grub as a payload, grub.cfg is at etc/grub.cfg by default, so if you want to test grub as a payload, remember to change grub.cfg's path not to interfer with the fallback's grub configuration.
    • Changing the path of what SeaBIOS loads from cbfs is probably configurable with SeaBIOS cbfs symlinks but not yet tested/documented with the use of the fallback mecanism
  • Tested boards need to be listed somewhere.

Issues

thinkpad_acpi

This linux driver can have some bad interactions with the fallback/normal mecanism: when using it with the volume_control=1 option, volume_mode=1 is required, otherwise after shutting down the computer, it will always boot from fallback.

This might be because as the default settings of volume_mode touches the nvram, it probably corrupts it at shutdown when saving the alsa state of the volume buttons "sound card" (called EC Mixer). Then at boot, coreboot will detects a corrupted nvram and restore its valid defaults.

references

<references/>