Fallback mechanism: Difference between revisions

From coreboot
Jump to navigation Jump to search
(21 intermediate revisions by the same user not shown)
Line 22: Line 22:
If a certain threshold<ref>Defined by CONFIG_MAX_REBOOT_CNT, typically 3</ref> is attained at boot, coreboot will boot the fallback image.
If a certain threshold<ref>Defined by CONFIG_MAX_REBOOT_CNT, typically 3</ref> is attained at boot, coreboot will boot the fallback image.


== Building  ==
== Warnings ==
This scrpit takes an existing coreboot image path as argument.
Because we uses two images, it's easy to wrongly identify which image booted:
* [[Fallback mechanism/fallback.sh|fallback.sh]] build script
* If the user mistakenly thinks the normal image is booting...
* [[Fallback mechanism/normal.sh|normal.sh]] build script
* 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 "normal" in "CBFS prefix to use":
(fallback) CBFS prefix to use
Then near the bottom, make sure to have:
Bootblock behaviour (Switch to normal if CMOS says so)  --->
[*] Do not clear reboot count after successful boot
[*] Update existing coreboot.rom image
You can then build the fallback image with the [[Fallback mechanism/fallback.sh|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:
Bootblock behaviour (Switch to normal if CMOS says so)  --->
[*] Do not clear reboot count after successful boot
[*] Update existing coreboot.rom image
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.


== OS configuration ==
== OS configuration ==


==== Example scripts ====
=== The manual way ===
The most simple way to do it is to run some nvramtool commands, they are described in the scripts below.
An approach is to run switch-to-normal.sh before trying an image.
set-normal-0.sh has to be run:
It's however more error prone than the systemd approach because:
* After the boot is completed and is declared a success.
* you have to do it manually, each time, before testing an image.
* After the resuming is completed.
* If you then want to use that new image, you have to flash it, again, to fallback.


===== set-fallback-1.sh =====
==== switch-to-normal.sh ====
#!/bin/sh
nvramtool -w boot_option=Fallback
nvramtool -w last_boot=Fallback
nvramtool -w reboot_bits=1
===== set-normal-0.sh =====
  #!/bin/sh
  #!/bin/sh
  nvramtool -w boot_option=Normal
  nvramtool -w boot_option=Normal
nvramtool -w last_boot=Normal
  nvramtool -w reboot_bits=0
  nvramtool -w reboot_bits=0


===== get-nvram.sh =====
==== switch-to-fallback.sh ====
  #!/bin/sh
  #!/bin/sh
  nvramtool -a | grep -e boot_option -e last_boot -e reboot_bits
  nvramtool -w boot_option=Fallback
nvramtool -w reboot_bits=1
 
=== Systemd ===
Here we use systemd to automatically reset the boot counter after each successful boot (or resume).


==== With systemd ====
We are then supposed to use the normal image daily and only resort to fallback in case of issues.
===== Systemd setup =====
Requirements:
* nvramtool has to be in the path.


Limitations:
To install it, first install nvramtool (from coreboot sources):
* This setup doesn't needs to run that systemd unit when resuming from suspend to ram, but it's not described yet here.
$ cd util/nvramtool
$ make
$ sudo make install


The unit file below has to be activated with:
Then add the following systemd units at their respective paths:
systemctl enable coreboot-booted-ok
* [[Fallback_mechanism/coreboot@boot.service|/etc/systemd/system/coreboot@boot.service]]
systemctl start coreboot-booted-ok
* [[Fallback_mechanism/coreboot@resume.service|/etc/systemd/system/coreboot@resume.service]]


===== /etc/systemd/system/coreboot-booted-ok.service: =====
Then enable them with:
  #  This file is not part of systemd.
  $ sudo systemctl enable coreboot@boot.service
  #
  $ sudo systemctl start coreboot@boot.service
#  this file is free software; you can redistribute it and/or modify it
  $ sudo systemctl enable coreboot@resume.service
#  under the terms of the GNU Lesser General Public License as published by
  $ sudo systemctl start coreboot@resume.service
#  the Free Software Foundation; either version 2.1 of the License, or
  #  (at your option) any later version.
[Unit]
Description=Tell coreboot that the computer booted fine.
DefaultDependencies=no
Wants=display-manager.service
  After=display-manager.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/nvramtool -w boot_option=Normal
ExecStart=/usr/local/sbin/nvramtool -w last_boot=Normal
ExecStart=/usr/local/sbin/nvramtool -w reboot_bits=0
[Install]
WantedBy=multi-user.target


== Current limitations ==
== Current limitations ==
Line 96: Line 101:
** 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.
** 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
** 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.


== references ==
== references ==
<references/>
<references/>

Revision as of 01:15, 29 January 2016

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_bits 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 "normal" in "CBFS prefix to use":

(fallback) CBFS prefix to use

Then near the bottom, make sure to have:

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

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:

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

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_bits=0

switch-to-fallback.sh

#!/bin/sh
nvramtool -w boot_option=Fallback
nvramtool -w reboot_bits=1

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

  • 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.

references

<references/>