【转】【http://sbabic.github.io/swupdate/swupdate.html】
This project is thought to help to update an embedded system from a storage media or from network. However, it should be mainly considered as a framework, where further protocols or installers (in SWUpdate they are called handlers) can be easily added to the application.
One use case is to update from an external local media, as USB-Pen or SD-Card. In this case, the update is done without any intervention by an operator: it is thought as “one-key-update”, and the software is started at reset simply pressing a key (or in any way that can be recognized by the target), making all checks automatically. At the end, the updating process reports only the status to the operator (successful or failed).
The output can be displayed on a LCD using the frame-buffer device or directed to a serial line (Linux console).
It is generally used in the single copy approach, running in an initrd (recipes are provided to generate with Yocto). However, it is possible to use it in a double-copy approach by use of Software collections.
If started for a remote update, SWUpdate starts an embedded Web-server and waits for requests. The operator must upload a suitable image, that SWUpdate checks and then install. All output is notified to the operator’s browser via AJAX notifications.
Multiple interfaces for getting software
OTA / Remote
The main concept is that the manufacturer delivers a single big image. All single images are packed together (cpio was chosen for its simplicity and because can be streamed) together with an additional file (sw-description), that contains meta information about each single image.
The format of sw-description can be customized: SWUpdate can be configured to use its internal parser (based on libconfig), or calling an external parser in Lua.
Changing the rules to accept images with an external parser, let to extend to new image types and how they are installed. In fact, the scope of the parser is to retrieve which single images must be installed and how. SWUpdate implements “handlers” to install a single image: there are handlers to install images into UBI volumes, or to a SD card, a CFI Flash, and so on. It is then easy to add an own handler if a very special installer is required.
For example we can think at a project with a main processor and one or several micro-controllers. Let’s say for simplicity that the main processor communicates with the micro-controllers via UARTS using a proprietary protocol. The software on the micro-controllers can be updated using the proprietary protocol.
It is possible to extend SWUpdate writing a handler, that implements the part of the proprietary protocol to perform the upgrade on the micro-controller. The parser must recognize which image must be installed with the new handler, and SWUpdate will call the handler during the installation process.
SWUpdate is thought to be able to stream the received image directly into the target, without any temporary copy. In fact, the single installer (handler) receive as input the file descriptor set at the beginning of the image that must be installed.
The feature can be set on image basis, that means that a user can decide which partial images should be streamed. If not streamed (see installed-directly flag), files are temporary extracted into the directory pointed to by the environment variable TMPDIR
with /tmp
as fall-back if TMPDIR
is not set. Of course, by streaming it is not possible to make checks on the whole delivered software before installing. The temporary copy is done only when updated from network. When the image is stored on an external storage, there is no need of that copy.
In case of remote update, SWUpdate extracts relevant images from the stream and copies them into the directory pointed to by the environment variable TMPDIR
(if unset, to /tmp
) before calling the handlers. This guarantee that an update is initiated only if all parts are present and correct. However, on some systems with less resources, the amount of RAM to copy the images could be not enough, for example if the filesystem on an attached SD Card must be updated. In this case, it will help if the images are installed directly as stream by the corresponding handler, without temporary copies. Not all handlers support to stream directly into the target. Streaming with zero-copy is enabled by setting the flag “installed-directly” in the description of the single image.
There are only a few libraries that are required to compile SWUpdate.
New handlers can add some other libraries to the requirement list - check if you need all handlers in case you get build errors, and drop what you do not need.
A meta-swupdate layer is provided. It contains the required changes for mtd-utils and for generating Lua. Using meta-SWUpdate is a straightforward process.
Firstly, clone meta-SWUpdate.
git clone https://github.com/sbabic/meta-swupdate.git
Add meta-SWUpdate as usual to your bblayers.conf. You have also to add meta-oe to the list.
In meta-SWUpdate there is a recipe to generate an initrd with a rescue system with SWUpdate. Use:
MACHINE=bitbake swupdate-image
You will find the result in your tmp/deploy/
This is a common issue when SWUpdate is built. SWUpdate depends on this library, that is generated from the U-Boot’s sources. This library allows to safe modify the U-Boot environment. It is not required if U-Boot is not used as bootloader. If SWUpdate cannot be linked, you are using an old version of U-Boot (you need at least 2016.05). If this is the case, you can add your own recipe for the package u-boot-fw-utils, adding the code for the library.
It is important that the package u-boot-fw-utils is built with the same sources of the bootloader and for the same machine. In fact, the target can have a default environment linked together with U-Boot’s code, and it is not (yet) stored into a storage. SWUpdate should be aware of it, because it cannot read it: the default environment must be linked as well to SWUpdate’s code. This is done inside the libubootenv.
If you build for a different machine, SWUpdate will destroy the environment when it tries to change it the first time. In fact, a wrong default environment is taken, and your board won’t boot again.
SWUpdate is configurable via “make menuconfig”. The small footprint is reached using the internal parser and disabling the web server. Any option has a small help describing its usage. In the default configuration, many options are already activated.
To configure the options:
make menuconfig
make
The result is the binary “swupdate”. A second binary “progress” is built, but it is not strictly required. It is an example how to build your own interface to SWUpdate to show a progress bar or whatever you want on your HMI. The example simply prints on the console the current status of the update.
In the Yocto buildsystem,:
bitbake swupdate
This will build the package
bitbake swupdate-image
This builds a rescue image. The result is a Ramdisk that can be loaded directly by the bootloader. To use SWUpdate in the double-copy mode, put the package swupdate into your rootfs. Check your image recipe, and simply add it to the list of the installed packages.
For example, if we want to add it to the standard “core-image-full-cmdline” image, we can add a recipes-extended/images/core-image-full-cmdline.bbappend
IMAGE_INSTALL += " \ swupdate \ swupdate-www \ "
swupdate-www is the package with the website, that you can customize with your own logo, template ans style.
SWUpdate is thought for Embedded Systems and building in an embedded distribution is the first use case. But apart the most used buildsystems for embedded as Yocto or Buildroot, in some cases a standard Linux distro is used. Not only, a distro package allows to run SWUpdate on Linux PC for test purposes without having to fight with dependencies. Using the debhelper tools, it is possible to generate a debian package.
Steps for building a debian package
./debian/rules clean ./debian/rules build fakeroot debian/rules binary
The result is a “deb” package stored in the parent directory.
Alternative way signing source package
You can use dpkg-buildpackage:
dpkg-buildpackage -us -uc debsign -k
A run of SWUpdate consists mainly of the following steps:
The first step that fails, stops the entire procedure and an error is reported.
To start SWUpdate expecting the image from a file:
swupdate -i
To start with the embedded web server:
swupdate -w ""
The main important parameters for the web server are “document-root” and “port”.
swupdate -w "--document-root ./www --port 8080"
The embedded web server is taken from the Mongoose project.
The whole list of options will be retrieved with:
swupdate -h
This uses as website the pages delivered with the code. Of course, they can be customized and replaced. The website uses AJAX to communicate with SWUpdate, and to show the progress of the update to the operator.
The default port of the Web-server is 8080. You can then connect to the target with:
http://:8080
If it works, the start page should be displayed as in next figure.
If a correct image is downloaded, SWUpdate starts to process the received image. All notifications are sent back to the browser. SWUpdate provides a mechanism to send to a receiver the progress of the installation. In fact, SWUpdate takes a list of objects that registers itself with the application and they will be informed any time the application calls the notify() function. This allows also for self-written handlers to inform the upper layers about error conditions or simply return the status. It is then simply to add own receivers to implement customized way to display the results: displaying on a LCD (if the target has one), or sending back to another device via network. An example of the notifications sent back to the browser is in the next figure:
Software collections can be specified by passing –select command line option. Assuming sw-description file contains a collection named stable, with alt installation location, SWUpdate can be called like this:
swupdate --select stable,alt
Parameter | Type | Description |
---|---|---|
-f |
string | SWUpdate config file to use |
-b |
string | Active only if CONFIG_UBIATTACH is set It allows to blacklist MTDs when SWUpdate searches for UBI volumes. Example: U-Boot and environment in MTD0-1: swupdate -b “0 1” |
-e |
string | sel is in the format |
-h |
|
run usage with help |
-k | string | Active if CONFIG_SIGNED is set Filename with the public key |
-l |
int | Set loglevel |
-L |
|
Send LOG output to syslog(local) |
-i |
string | run SWUpdate with a local .swu file |
-n |
|
run SWUpdate in dry-run mode. |
-N | string | passed the current installed version of software. This will be checked with the version of new software and forbids downgrading. Version mconsists of 4 number: major.minor.rev.build each field is in the range 0..65535 |
-o |
string | saves the stream (SWU) on a file |
-v |
|
activate verbose output |
-w |
string | start internal webserver and pass to it a command line string. |
-u |
string | start internal suricatta client daemon and pass to it a command line string. see suricatta’s documentation for details. |
-H |
string | set board name and Hardware revision |
-c |
|
This will check *.swu file against internal tests. It ensures that files referenced in sw-description are present. Usage: swupdate -c -i |
-p | string | Execute post-update command. |
-d |
string | Active only if CONFIG_DOWNLOAD is set start internal downloader client and pass to it a command line string. See below the internal command line arguments for the downloader |
-u |
string | This is the URL where new software is pulled. URL is a link to a valid .swu image |
-r |
integer | Number of retries before a download is considered broken. With “-r 0”, SWUpdate will not stop until a valid software is loaded. |
-t |
integer | Timeout for connection lost when downloading |
-a |
string | Send user and password for Basic Auth |
SWUpdate has optional systemd support via the compile-time configuration switch CONFIG_SYSTEMD
. If enabled, SWUpdate signals systemd about start-up completion and can make optional use of systemd’s socket-based activation feature.
A sample systemd service unit file /etc/systemd/system/swupdate.service
may look like the following starting SWUpdate in suricatta daemon mode:
[Unit] Description=SWUpdate daemon Documentation=https://github.com/sbabic/swupdate Documentation=https://sbabic.github.io/swupdate [Service] Type=notify ExecStart=/usr/bin/swupdate -u '-t default -u http://localhost -i 25' [Install] WantedBy=multi-user.target
Started via systemctl start swupdate.service
, SWUpdate (re)creates its sockets on startup. For using socket-based activation, an accompanying systemd socket unit file/etc/systemd/system/swupdate.socket
is required:
[Unit] Description=SWUpdate socket listener Documentation=https://github.com/sbabic/swupdate Documentation=https://sbabic.github.io/swupdate [Socket] ListenStream=/tmp/sockinstctrl ListenStream=/tmp/swupdateprog [Install] WantedBy=sockets.target
On swupdate.socket
being started, systemd creates the socket files and hands them over to SWUpdate when it starts. So, for example, when talking to /tmp/swupdateprog
, systemd startsswupdate.service
and hands-over the socket files. The socket files are also handed over on a “regular” start of SWUpdate via systemctl start swupdate.service
.
Note that the socket paths in the two ListenStream=
directives have to match the socket paths CONFIG_SOCKET_CTRL_PATH
and CONFIG_SOCKET_PROGRESS_PATH
in SWUpdate’s configuration. Here, the default socket path configuration is depicted.
The SWUpdate consists of kernel and a root filesystem (image) that must be started by the boot-loader. In case using U-Boot, the following mechanism can be implemented:
Is it safe to change U-Boot environment ? Well, it is, but U-Boot must be configured correctly. U-Boot supports two copies of the environment to be power-off safe during an environment update. The board’s configuration file must have defined CONFIG_ENV_OFFSET_REDUND or CONFIG_ENV_ADDR_REDUND. Check in U-Boot documentation for these constants and how to use them.
There are a further enhancement that can be optionally integrated into U-boot to make the system safer. The most important I will suggest is to add support for boot counter in U-boot (documentation is in U-Boot docs). This allows U-Boot to track for attempts to successfully run the application, and if the boot counter is greater as a limit, can start automatically SWUpdate to replace a corrupt software.
GRUB by default does not support double copies of environment as in case of U-Boot. This means that there is possibility that environment block get’s corrupted when power-off occurs during environment update. To minimize the risk, we are not modifying original environment block. Variables are written into temporary file and after successful operation rename instruction is called.
cpio is used as container for its simplicity. The resulting image is very simple to be built. The file describing the images (“sw-description”, but the name can be configured) must be the first file in the cpio archive.
To produce an image, a script like this can be used:
CONTAINER_VER="1.0" PRODUCT_NAME="my-software" FILES="sw-description image1.ubifs \ image2.gz.u-boot uImage.bin myfile sdcard.img" for i in $FILES;do echo $i;done | cpio -ov -H crc > ${PRODUCT_NAME}_${CONTAINER_VER}.swu
The single images can be put in any order inside the cpio container, with the exception of sw-description, that must be the first one. To check your generated image you can run the following command:
swupdate -c -i my-software_1.0.swu
The single image can be built automatically inside Yocto. meta-swupdate extends the classes with the swupdate class. A recipe should inherit it, and add your own sw-description file to generate the image.
Next Previous