Software Update¶
Welma integrates a solution for remotely updating software partitions after the device has been brought into operation, with 2 possible modes.
A/B mode: This is a reliable solution that is resilient to uncontrolled shutdown or reset of the machine, and that provides rollback.
In this mode, the system has 2 copies (A and B) of a partition, one being active (ie: its files are being used by the running system), and the other being inactive. The system can only update the inactive partition, which will become active after a reboot.
This mode is typically used for the kernel, rootfs, applicative partitions, ...
Single mode: This enables the updating of partitions that do not have a second copy, and that are not used at the time of the installation of a new version.
In this mode, the system is not resilient to uncontrolled shutdown or reset, and rollback is not available.
This mode is typically used for the bootloader.
Different partitions of a system can have different update modes.
Yocto Build¶
In order to activate the software update feature, you need:
- In your image recipe:
inherit welma-image
- select the underlying mechanism:
WELMA_UPDATE = "swupdate"
(this is the default)- or
WELMA_UPDATE = "mender"
- or
WELMA_UPDATE = "mender-connected"
- In your project Yocto layer, in your
.part
file, set:update=ab
- or
update=single
(see Generic Partitioning)
The generated output files will be:
- A SD card image with the whole partitioning (with extensions
.wic
or.wic.gz
) suitable for the very first installation of the device. - Module files (with extensions
.swu
or.mender
) for remote updates.
Secure Update¶
Optionally, it is possible to have SW modules authenticated before they are installed. The authentication is done by verifying a cryptographic signature.
For this mechanism to work, 2 things are needed:
- Embedded software must be provisionned with a public key used for the verification of the signature.
- The module to be installed must have the appropriate signature.
These can be achieved with the following Yocto parameters:
WELMA_SECURE_UPDATE = "1"
inlocal.conf
(this is the default value)WELMA_KEY_SWK1_PUB
/PRIV
orWELMA_KEY_SWK2_PUB
/PRIV
: defines SWK1 or SWK2. Either one of them can be used. If both are defined, only SWK2 is used.
Updating Software at Runtime¶
To deploy a new software version on your device:
-
Have your embedded application retrieve the modules to be installed (via network, USB, etc.).
-
Have your application request the system to make the installation, via the command
updatectl install
or via the D-Bus API (see below). -
Have your application reboot the device
-
After reboot, the device should be running the new version.
- If you have updated at least one module in A/B mode, have your
application check that the device is operational and confirm the update
via the
updatectl confirm
API or via the D-Bus API (see below). - If only single mode modules were updated, there is nothing to confirm.
- If you have updated at least one module in A/B mode, have your
application check that the device is operational and confirm the update
via the
Notes
The Welma software update mechanism lets you update any combination of modules (all at once, only one of them, ...), but you should ensure the compatibility between them.
When things go wrong when updating A/B modules:
-
If the application does not confirm the installation, then:
- other software updates will be rejected;
- at next reboot the device will rollback to the initial system;
- after 2 minutes a watchdog will force rebooting.
-
If the installation is interrupted (eg: by a power outage), then the initial state remains unchanged and the device remains operational.
-
If the new version installed has defects and does not boot, the HW watchdog will make the device reboot and come back to the initial state.
-
If the application does not confirm within the allocated time, then the device reboots, and comes back to the initial state.
updatectl
API¶
Usage: updatectl install FILE [FILE ...]
updatectl confirm
updatectl abort
updatectl status [PROPERTY]
updatectl clearance-request REASON
updatectl clearance-notify RESPONSE
Commands:
confirm Confirm a software update under test
install Install a software update and schedule it for next reboot as under test
abort Abort a pending software update (scheduled or under test)
status Print update status
clearance-notify
Send the clearance response.
clearance-request
Send a request for clearance.
Arguments:
FILE A software module to be installed.
PROPERTY A single property for which the status is needed
REASON download | install
RESPONSE ready | rejected | retry-later
Example of a manual installation scenario:
# updatectl status
state normal
partitions-active /dev/mmcblk2p1 /dev/mmcblk2p3 /dev/mmcblk2p5
partitions-inactive /dev/mmcblk2p2 /dev/mmcblk2p4 /dev/mmcblk2p6
# updatectl install /tmp/appro-v1.1.swu
# reboot
...
# updatectl status
state under-test
partitions-active /dev/mmcblk2p1 /dev/mmcblk2p3 /dev/mmcblk2p6
partitions-inactive /dev/mmcblk2p2 /dev/mmcblk2p4 /dev/mmcblk2p5
# updatectl confirm
Update Daemon D-Bus API¶
node /com/witekio/update1 {
interface com.witekio.update1.Manager {
methods:
AbortUpdate();
BeginUpdate();
ConfirmUpdate();
InstallLocalFile(in s file_path);
MarkSlotUpdated(in s slot_name);
SubmitUpdate();
RequestClearance(in s reason, out s response);
NotifyClearance(in s status);
signals:
ClearanceRequested(in s reason);
properties:
readonly s State;
}
}
BeginUpdate()
starts an update transaction, that shall be followed by:
- Installing modules, via
InstallLocalFile()
- Submitting the update to the bootloader, via
SubmitUpdate()
- Rebooting
- Confirming the update of A/B modules, via
ConfirmUpdate()
AbortUpdate()
aborts a started update transaction, before or after reboot.
Aborting an update after reboot leads to reboot and a rollback to the
initial software system.
InstallLocalFile()
installs a module onto its inactive partition. Cannot be
used in mode mender-connected
(see MarkSlotUpdated()
).
MarkSlotUpdated()
marks a slot (partition) as updated, when the installation
was not made using InstallLocalFile()
. This is typically used in mode
mender-connected
. slot_name
must be a valid partition name of
/etc/welma-partitions.conf
.
SubmitUpdate()
submits the update to bootflags, that tells the bootloader
to do next boot on the newly installed partitions.
ConfirmUpdate()
makes the update persistent. Rollback cannot be performed
after this. Not applicable when only single mode modules were installed.
RequestClearance()
requests that the embedded system prepares itself for a
significant update operation such as downloading or installing modules.
It is typically called by a program in charge of downloading and installing
modules when another program (application, GUI,...) is in charge of granting
clearance (by calling NotifyClearance()
).
reason
must be one of:download
,install
.response
is the status given byNotifyClearance()
, ortimeout
if no response is received after 5 minutes.
Only one clearance request is allowed at a time.
NotifyClearance()
informs the update subsystem about the status of the
clearance request. status
must be one of: ready
, rejected
, retry-later
.
It is given as a response to RequestClearance()
.
ClearanceRequested()
is sent out each time a clearance request is done.
reason
is the reason given in the clearance request.
State
contains the state of the update daemon, one of:
normal
: Regular operational state, a new update procedure may be initiated byBeginUpdate()
.normal,ongoing-install
: A module is being installed byInstallLocalFile()
. Other installation or submit requests will be rejected.normal,aborting
: An installation procedure is being aborted byAbortUpdate()
. Other requests will be rejected.normal,test-scheduled
: An update procedure has been submitted bySubmitUpdate()
and awaits a reboot for taking effect.under-test
: The system is running on modules that just got installed before the latest reboot, and the update daemon is waiting for a call toConfirmUpdate()
.
How to Determine if the Device is Operational¶
This paragraph is only advisory.
Before validating that a new installed software version is operational a few project-specific verifications shall be performed by the application.
The purpose is to prevent:
- The device from being locked out of remote control.
- Retrieving physically the device and recommissioning.
Example of what could be verified:
- Network is reachable (this can verify network parameters, URL, TLS certificates,...).
- Data stores in SYSRW are correctly loaded (this can verify incompatible files formats, databases).
Configuration¶
The update daemon can be configured in /etc/updated.conf
.
[core]
# Confirm Timeout in seconds: when booting on newly installed partitions, if
# ConfirmUpdate is not received within this delay, then a rollback is
# triggered. This behaviour is disabled if the value is negative or null.
confirm-timeout=120
Using Production Keys (Secure Update)¶
The key used for secure update can be changed (without being in the Yocto
build), with tools of welma-signing-tools
.
Inject SWK1 in the bootloader¶
See page Secure Boot on IMX with HABv4 or Secure Boot on STM32MP25x
Inject SWK2 in the kernel FIT image¶
- Extract
fitImage
from the BOOT module (eg: usingmcopy
) -
Inject the certificate into the ramdisk at path
/etc/swk/swk2.crt
-
Rebuild the BOOT module with the updated
fitImage
(eg: usingmcopy
)
Inject SWK2 in the UEFI Comboapp¶
The comboapp is located in the BOOT module with .efi
suffix (eg: bootx86.efi
).
- Extract the comboapp from the BOOT module
- Inject the certificate into the ramdisk at path
/etc/swk/swk2.crt
welma-signing-tools/common/inject-file-comboapp-ramdisk \
bootx86.efi \
CERTIFICATE \
/etc/swk/swk2.crt
- Rebuild the BOOT module with the updated
bootx86.efi
Sign¶
-
When using mechanism
swupdate
: -
When using mechanism
mender
ormender-connected
, use mender-artifact
Internal Architecture¶
This paragraph describes how things are internally organized.
This is how the system handles A/B updates:
The underlying mechanism for installing software updates is either:
Linux Userspace¶
At boot time:
- The initramfs mounts the filesystems as declared in
/etc/welma-partitions.conf
- udev: creates links
/dev/disk/partitions/{active,inactive,single}/*
, based on the bootflags and/etc/welma-partitions.conf
- systemd: starts
updated
Swupdate¶
Installation: Simplified message sequence chart (not all D-Bus exchanges are shown):
Application updated daemon SWUpdate daemon
(user) (root) (root)
│ │ │
├── updatectl install SWU-1 SWU-2 │ │
│ │ │ │
│ │ (D-Bus) │ │
│ ├─────────InstallLocalFile ──────>│ │
│ │ SWU-1 ├── swupdate-client │
│ │ │ │ │
│ │ │ │ (socket) │
│ │ │ └───────────────────>│
│ │ │ ├── install
│ │ (D-Bus) │ │ to disk
│ ├─────────InstallLocalFile ──────>│ │
│ │ SWU-2 ├── swupdate-client │
│ │ │ │ │
│ │ │ │ (socket) │
│ │ │ └───────────────────>│
│ │ (D-Bus) │ ├── install
│ ├──────────SubmitUpdate──────────>│ │ to disk
│<─────┘ ├── write bootflags │
│ │ │
................... reboot ...........................................
│ │
├── updatectl confirm │
│ │ │
│ └────────────ConfirmUpdate───────>│
SWU modules generated at build time:
These are CPIO archives with:
- a
sw-description
file (see https://sbabic.github.io/swupdate/sw-description.html for the syntax). - a file system image (vfat, ext4 or verity)
A SWU module for Welma should comply with the following:
- Images shall have a target device under these paths:
/dev/disk/partitions/inactive/
/dev/disk/partitions/single/
The template of the sw-description
file contained in the SWU module looks
like this:
software =
{
version = "1.0"
hardware-compatibility = [ "1.0" ]
images = (
{
device = "/dev/disk/partitions/inactive/$partname"
filename = "$image_file"
installed-directly = true
}
)
}
($partname
being replaced at build-time with the appropriate destination
partition name)
Mender¶
In the diagrams below, /u/s/m/m/v3
is a shorthand for
/usr/share/mender/modules/v3
.
Installation in standalone mode: Simplified message sequence chart (not all D-Bus exchanges are shown):
Application updated daemon
(user) (root)
│ │
├── updatectl install MENDER1 MENDER2 │
│ │ │
│ ├────────────InstallLocalFile───────────>│
│ │ MENDER1 ├── mender install MENDER1
│ │ │ └── /u/s/m/m/v3/welma
│ │ │ └── write to disk
│ ├────────────InstallLocalFile───────────>│
│ │ MENDER2 ├── mender install MENDER2
│ │ │ └── /u/s/m/m/v3/welma
│ │ │ └── write to disk
│ ├─────────────SubmitUpdate──────────────>│
│<─────┘ ├── write bootflags
│ │
└── reboot │
................... reboot ......................
│ │
├── updatectl confirm │
│ │ │
│ └────────────ConfirmUpdate──────────────>│
Installation in connected mode: Simplified message sequence chart (not all D-Bus exchanges are shown):
Mender daemon updated daemon
(root) (root)
│ │
├── download artifact │
├── /u/s/m/m/v3/welma ArtifactInstall │
│ │ │
│ ├── write to disk BOOT │
│ ├───────────── MarkSlotUpdated BOOT ────────────>│
│ │ │
│ ├── write to disk SYSRO │
│ ├────────────── MarkSlotUpdated SYSRO ──────────>│
│ │ │
│ ├── write to disk APPRO │
│ ├────────────── MarkSlotUpdated APPRO ──────────>│
│ │ │
│ └────────────────SubmitUpdate───────────────────>│
└── reboot │
........................ reboot .............................
│ │
├── /u/s/m/m/v3/welma ArtifactVerifyReboot │
│ │
├── /u/s/m/m/v3/welma ArtifactCommit │
│ └───────────────ConfirmUpdate───────────────────>│
│ │
How an application can control downloads and installation in connected mode:
Mender daemon updated daemon application
│ │ │
detects that a module │ │
is ready for download │ │
│ │ │
├── Download_Enter_01 │ │
│ │ │ │
│ ├── RequestClearance ─────>│ │
│ │ "download" ├─ ClearanceRequested ──>│
│ │ │ "download" │
│ │ │ │
│ │ │<─── NotifyClearance ───┤
│ │ │ "ready" │
│ │<──── reply "ready" ──────┤ │
│ │ │ │
│<──┘ exit code 0 │ │
│ │ │
installation sequence │ │
(same as before) │ │
│ │ │
Here is a summary of what a Mender artifact looks like:
├── header
├── payload 0000
│ └──files
│ └── ...
├── payload 0001
│ └── files
│ └── ...
└── ...
To be compatible with Welma update, a Mender artifact for Welma should comply with the following:
- Have exactly one payload of type
welma
- The payload shall have:
- One file for each module to be installed:
- The file name indicates the name of the partition where it should installed
- The content indicates the name of the image file to be installed
- The image file(s) referenced by the above
- One file for each module to be installed:
Notes
- Be sure to have enough disk space in /var/lib as Mender extracts payloads into this directory before installing to the target partition.
See also: