blob: 5e4595d9c2a2c1c5a47fd3d1bae35ee007bc8577 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- This is broken by doc revisioning.
-->
<link rel="shortcut icon" href="../../../../img/favicon.ico">
<title>toc - Apache Mynewt</title>
<link href="../../../../css/bootstrap-3.0.3.min.css" rel="stylesheet">
<link rel="stylesheet" href="../../../../css/highlight.css">
<link href="../../../../css/base.css" rel="stylesheet">
<link href="../../../../css/custom.css" rel="stylesheet">
<link href="../../../../css/v2.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
<script>
(function(i, s, o, g, r, a, m) {
i["GoogleAnalyticsObject"] = r;
(i[r] =
i[r] ||
function() {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, "script", "//www.google-analytics.com/analytics.js", "ga");
ga("create", "UA-72162311-1", "auto");
ga("send", "pageview");
</script>
</head>
<body class="toc">
<div class="container">
<div class="row v2-main-banner">
<a class="logo-cell" href="/">
<img class="logo" src="/img/logo.png">
</a>
<div class="tagline-cell">
<h4 class="tagline">An OS to build, deploy and securely manage billions of devices</h4>
</div>
<div class="news-cell">
<div class="well">
<h4>Latest News:</h4> <a href="/download">Apache Mynewt 1.12.0, Apache NimBLE 1.7.0 </a> released (April 4, 2024)
</div>
</div>
</div>
</div>
<nav id="navbar" class="navbar navbar-inverse affix-top" data-spy="affix" data-offset-top="150" role="navigation">
<div class="container">
<!-- Collapsed navigation -->
<div class="navbar-header">
<!-- Expander button -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Expanded navigation -->
<div class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav navbar-right">
<li
class=""
>
<a href="/"><i class="fa fa-home" style="font-size: larger;"></i></a>
</li>
<li
class="important"
>
<a href="/quick-start/">Quick Start</a>
</li>
<li
class=""
>
<a href="/about/">About</a>
</li>
<li
class=""
>
<a href="/talks/">Talks</a>
</li>
<li
class="active"
>
<a href="/documentation/">Documentation</a>
</li>
<li
class=""
>
<a href="/download/">Download</a>
</li>
<li
class=""
>
<a href="/community/">Community</a>
</li>
<li
class=""
>
<a href="/events/">Events</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-3 v2-sidebar sidebar-container"><div id="docSidebar" class="hidden-print" role="complementary">
<div class="top">
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../../search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search documentation" />
</div>
</form>
</div>
</div>
<ul class="toc-nav">
<li class="doc-version"><select class="form-control" onchange="if (this.value) window.location.href=this.value">
<option value="/latest">
Version: master
</option>
<option value="/v1_12_0/" >
Version: 1.12.0
</option>
<option value="/v1_11_0/" >
Version: 1.11.0
</option>
<option value="/v1_10_0/" >
Version: 1.10.0
</option>
<option value="/v1_9_0/" >
Version: 1.9.0
</option>
<option value="/v1_8_0/" >
Version: 1.8.0
</option>
<option value="/v1_7_0/" >
Version: 1.7.0
</option>
<option value="/v1_6_0/" >
Version: 1.6.0
</option>
<option value="/v1_5_0/" >
Version: 1.5.0
</option>
<option value="/v1_4_0/" >
Version: 1.4.0
</option>
<option value="/v1_3_0/os/introduction" >
Version: 1.3.0
</option>
<option value="/v1_2_0/os/introduction" >
Version: 1.2.0
</option>
<option value="/v1_1_0/os/introduction" >
Version: 1.1.0
</option>
<option value="/v1_0_0/os/introduction" selected="selected" >
Version: 1.0.0
</option>
<option value="/v0_9_0/os/introduction" >
Version: 0.9.0
</option>
</select></li>
<li ><a href="../../../introduction/">Mynewt Documentation</a>
<ul>
<li ><a href="../../../get_started/get_started/">Basic Setup</a>
</li>
<li >
<a href="../../../get_started/vocabulary/">Concepts</a>
</li>
<li ><a href="../../../tutorials/tutorials/">Tutorials</a>
</li>
<li ><a href="../../../os_user_guide/">OS User Guide</a>
<ul>
<li ><a href="../../../core_os/mynewt_os/">OS Core</a>
</li>
<li ><a href="../../../core_os/porting/port_os/">Porting to your Platform</a>
</li>
<li ><a href="../../console/console/">Console</a>
</li>
<li ><a href="../../shell/shell/">Shell</a>
</li>
<li ><a href="../../split/split/">Split Images</a>
</li>
<li class="active"><a href="./">Bootloader</a>
<ul>
<li><a href="
../boot_build_status/
">Functions</a>
</li>
</ul>
</li>
<li><a href="
../../fs/fs/fs/
">File System</a>
</li>
<li ><a href="../../hal/hal/">Hardware Abstraction Layer</a>
</li>
<li ><a href="../../drivers/driver/">Drivers</a>
</li>
<li ><a href="../../testutil/testutil/">Test Utilities</a>
</li>
<li ><a href="../../devmgmt/newtmgr/">Device Management with Newt Manager</a>
</li>
<li ><a href="../../imgmgr/imgmgr/">Image Manager</a>
</li>
<li >
<a href="../../baselibc/">Baselibc library</a>
</li>
<li ><a href="../../json/json/">JSON</a>
</li>
<li ><a href="../../fcb/fcb/">Flash Circular Buffer</a>
</li>
<li ><a href="../../stats/stats/">Stats</a>
</li>
<li ><a href="../../logs/logs/">Logs</a>
</li>
<li ><a href="../../sysinitconfig/sysinitconfig/">System Configuration And Initialization</a>
</li>
</ul>
</li>
<li><a href="
../../../../network/ble/ble_intro/
">BLE User Guide</a>
</li>
<li ><a href="../../../../newt/newt_intro/">Newt Tool Guide</a>
</li>
<li ><a href="../../../../newtmgr/overview/">Newt Manager Guide</a>
</li>
<li >
<a href="../../../../known_issues/">Known Issues</a>
</li>
</ul>
</li>
<li><a href="
../../../../faq/go_env/
">Appendix</a>
</li>
</ul>
</div></div>
<div class="col-md-9" role="main">
<div class="doc-header">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="/documentation/">Docs</a></li>
<li>&raquo; Bootloader</li>
<li>&raquo; <a href="os/os_user_guide/">OS User Guide</a></li>
<li>&raquo; <a href="os/introduction/">Mynewt Documentation</a></li>
</ul>
</div>
</div>
<div class="alert alert-warning">
<p>
Version 1.0.0 is not the most recent version of the Apache Mynewt
documentation. Click <a href="/latest">here</a> to read the latest
version.
</p>
</div>
<h1 id="bootloader">Bootloader</h1>
<p>The "bootloader" is the code that loads the Mynewt OS image into memory and conducts some checks before allowing the OS to be run. It manages images for the embedded system and upgrades of those images using protocols over various interfaces (e.g. serial, BLE, etc.). Typically, systems with bootloaders have at least two program images coexisting on the same microcontroller, and hence must include branch code that performs a check to see if an attempt to update software is already underway and manage the progress of the process.</p>
<p>The bootloader in the Apache Mynewt project verifies the cryptographic signature of the firmware image before running it. It maintains a detailed status log for each stage of the boot process. For verification of the authenticity of the OS image, it:</p>
<ul>
<li>Calculates hash of the image.</li>
<li>Uses public key to uncover hash value from included signature. </li>
<li>Compares the calculated and uncovered hashes for a match.</li>
</ul>
<p>The "secure bootloader" should be placed in protected memory on a given microcontroller.</p>
<p>The Mynewt bootloader comprises two packages:</p>
<ul>
<li>The bootutil library (boot/bootutil)</li>
<li>The boot application (apps/boot)</li>
</ul>
<p>The Mynewt code is thus structured so that the generic bootutil library performs most of the functions of a boot loader. The final step of actually jumping to the main image is kept out of the bootutil library. This last step should instead be implemented in an
architecture-specific project. Boot loader functionality is separated in this
manner for the following two reasons:</p>
<ol>
<li>By keeping architecture-dependent code separate, the bootutil library can be
reused among several boot loaders.</li>
<li>By excluding the last boot step from the library, the bootloader can be unit tested since a library can be unit tested but an applicant can't.</li>
</ol>
<h3 id="limitations">Limitations</h3>
<p>The boot loader currently only supports images with the following
characteristics:</p>
<ul>
<li>Built to run from flash.</li>
<li>Build to run from a fixed location (i.e., position-independent).</li>
</ul>
<h3 id="image-format">Image Format</h3>
<p>The following definitions describe the image header format.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#define IMAGE_MAGIC 0x96f3b83c</span>
<span style="color: #633820">#define IMAGE_MAGIC_NONE 0xffffffff</span>
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">image_version</span> {
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">iv_major</span>;
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">iv_minor</span>;
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">iv_revision</span>;
<span style="color: #A90D91">uint32_t</span> <span style="color: #000000">iv_build_num</span>;
};
<span style="color: #177500">/** Image header. All fields are in little endian byte order. */</span>
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">image_header</span> {
<span style="color: #A90D91">uint32_t</span> <span style="color: #000000">ih_magic</span>;
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">ih_tlv_size</span>; <span style="color: #177500">/* Trailing TLVs */</span>
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">ih_key_id</span>;
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">_pad1</span>;
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">ih_hdr_size</span>;
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">_pad2</span>;
<span style="color: #A90D91">uint32_t</span> <span style="color: #000000">ih_img_size</span>; <span style="color: #177500">/* Does not include header. */</span>
<span style="color: #A90D91">uint32_t</span> <span style="color: #000000">ih_flags</span>;
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">image_version</span> <span style="color: #000000">ih_ver</span>;
<span style="color: #A90D91">uint32_t</span> <span style="color: #000000">_pad3</span>;
};
</code></pre></div>
<p>The <code>ih_hdr_size</code> field indicates the length of the header, and therefore the
offset of the image itself. This field provides for backwards compatibility in
case of changes to the format of the image header.</p>
<p>The following are the image header flags available.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#define IMAGE_F_PIC 0x00000001</span>
<span style="color: #633820">#define IMAGE_F_SHA256 0x00000002 </span><span style="color: #177500">/* Image contains hash TLV */</span>
<span style="color: #633820">#define IMAGE_F_PKCS15_RSA2048_SHA256 0x00000004 </span><span style="color: #177500">/* PKCS15 w/RSA and SHA */</span>
<span style="color: #633820">#define IMAGE_F_ECDSA224_SHA256 0x00000008 </span><span style="color: #177500">/* ECDSA256 over SHA256 */</span>
<span style="color: #633820">#define IMAGE_F_NON_BOOTABLE 0x00000010</span>
<span style="color: #633820">#define IMAGE_HEADER_SIZE 32</span>
</code></pre></div>
<p>Optional type-length-value records (TLVs) containing image metadata are placed
after the end of the image. For example, security data gets added as a footer at the end of the image.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #177500">/** Image trailer TLV format. All fields in little endian. */</span>
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">image_tlv</span> {
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">it_type</span>; <span style="color: #177500">/* IMAGE_TLV_[...]. */</span>
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">_pad</span>;
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">it_len</span> <span style="color: #177500">/* Data length (not including TLV header). */</span>
};
<span style="color: #177500">/*</span>
<span style="color: #177500"> * Image trailer TLV types.</span>
<span style="color: #177500"> */</span>
<span style="color: #633820">#define IMAGE_TLV_SHA256 1 </span><span style="color: #177500">/* SHA256 of image hdr and body */</span>
<span style="color: #633820">#define IMAGE_TLV_RSA2048 2 </span><span style="color: #177500">/* RSA2048 of hash output */</span>
<span style="color: #633820">#define IMAGE_TLV_ECDSA224 3 </span><span style="color: #177500">/* ECDSA of hash output */</span>
</code></pre></div>
<h3 id="flash-map">Flash Map</h3>
<p>A Mynewt device's flash is partitioned according to its <em>flash map</em>. At a high
level, the flash map maps numeric IDs to <em>flash areas</em>. A flash area is a
region of disk with the following properties:</p>
<ol>
<li>An area can be fully erased without affecting any other areas.</li>
<li>A write to one area does not restrict writes to other areas.</li>
</ol>
<p>The boot loader uses the following flash areas:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#define FLASH_AREA_BOOTLOADER 0</span>
<span style="color: #633820">#define FLASH_AREA_IMAGE_0 1</span>
<span style="color: #633820">#define FLASH_AREA_IMAGE_1 2</span>
<span style="color: #633820">#define FLASH_AREA_IMAGE_SCRATCH 3</span>
</code></pre></div>
<h3 id="image-slots">Image Slots</h3>
<p>A portion of the flash memory is partitioned into two image slots: a primary
slot and a secondary slot. The boot loader will only run an image from the
primary slot, so images must be built such that they can run from that fixed
location in flash. If the boot loader needs to run the image resident in the
secondary slot, it must swap the two images in flash prior to booting.</p>
<p>In addition to the two image slots, the boot loader requires a scratch area to
allow for reliable image swapping.</p>
<h3 id="boot-states">Boot States</h3>
<p>Logically, you can think of a pair of flags associated with each image slot:
pending and confirmed. On startup, the boot loader determines the state of the
device by inspecting each pair of flags. These flags have the following
meanings:</p>
<ul>
<li>pending: image gets tested on next reboot; absent subsequent confirm command,
revert to original image on second reboot.</li>
<li>confirmed: always use image unless excluded by a test image.</li>
</ul>
<p>In English, when the user wants to run the secondary image, they set the
pending flag for the second slot and reboot the device. On startup, the boot
loader will swap the two images in flash, clear the secondary slot's pending
flag, and run the newly-copied image in slot 0. This is a temporary state; if
the device reboots again, the boot loader swaps the images back to their
original slots and boots into the original image. If the user doesn't want to
revert to the original state, they can make the current state permanent by
setting the confirmed flag in slot 0.</p>
<p>Switching to an alternate image is a two-step process (set + confirm) to
prevent a device from becoming "bricked" by bad firmware. If the device
crashes immediately upon booting the second image, the boot loader reverts to
the working image, rather than repeatedly rebooting into the bad image.</p>
<p>The following set of tables illustrate the three possible states that the
device can be in:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> | slot-0 | slot-1 |
---------------+--------+--------|
pending | | |
confirmed | X | |
---------------+--------+--------&#39;
Image 0 confirmed; |
No change on reboot |
---------------------------------&#39;
| slot-0 | slot-1 |
---------------+--------+--------|
pending | | X |
confirmed | X | |
---------------+--------+--------&#39;
Image 0 confirmed; |
Test image 1 on next reboot |
---------------------------------&#39;
| slot-0 | slot-1 |
---------------+--------+--------|
pending | | |
confirmed | | X |
---------------+--------+--------&#39;
Testing image 0; |
Revert to image 1 on next reboot |
---------------------------------&#39;
</code></pre></div>
<h3 id="boot-vector">Boot Vector</h3>
<p>At startup, the boot loader determines which of the above three boot states a device is in by inspecting the boot vector. The boot vector consists of two
records (called "image trailers"), one written at the end of each image slot.
An image trailer has the following structure:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ MAGIC (16 octets) ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ ~
~ Swap status (128 * min-write-size * 3) ~
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Copy done | 0xff padding (up to min-write-sz - 1) ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Image OK | 0xff padding (up to min-write-sz - 1) ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</code></pre></div>
<p>These records are at the end of each image slot. The offset immediately
following such a record represents the start of the next flash area.</p>
<p>Note: <code>min-write-size</code> is a property of the flash hardware. If the hardware
allows individual bytes to be written at arbitrary addresses, then
<code>min-write-size</code> is 1. If the hardware only allows writes at even addresses,
then <code>min-write-size</code> is 2, and so on.</p>
<p>The fields are defined as follows:</p>
<ol>
<li>
<p>MAGIC: The following 16 bytes, written in host-byte-order:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>const uint32_t boot_img_magic[4] = {
0xf395c277,
0x7fefd260,
0x0f505235,
0x8079b62c,
};
</code></pre></div>
</li>
<li>
<p>Swap status: A series of single-byte records. Each record corresponds to a
flash sector in an image slot. A swap status byte indicate the location of
the corresponding sector data. During an image swap, image data is moved one
sector at a time. The swap status is necessary for resuming a swap operation
if the device rebooted before a swap operation completed.</p>
</li>
<li>
<p>Copy done: A single byte indicating whether the image in this slot is
complete (<code>0x01=done, 0xff=not done</code>).</p>
</li>
<li>
<p>Image OK: A single byte indicating whether the image in this slot has been
confirmed as good by the user (<code>0x01=confirmed; 0xff=not confirmed</code>).</p>
</li>
</ol>
<p>The boot vector records are structured around the limitations imposed by flash
hardware. As a consequence, they do not have a very intuitive design, and it
is difficult to get a sense of the state of the device just by looking at the
boot vector. It is better to map all the possible vector states to the swap types
(None, Test, Revert) via a set of tables. These tables are reproduced below.
In these tables, the "pending" and "confirmed" flags are shown for illustrative
purposes; they are not actually present in the boot vector.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>State I
| slot-0 | slot-1 |
-----------------+--------+--------|
magic | Unset | Unset |
image-ok | Any | N/A |
-----------------+--------+--------&#39;
pending | | |
confirmed | X | |
-----------------+--------+--------&#39;
swap: none |
-----------------------------------&#39;
State II
| slot-0 | slot-1 |
-----------------+--------+--------|
magic | Any | Good |
image-ok | Any | N/A |
-----------------+--------+--------&#39;
pending | | X |
confirmed | X | |
-----------------+--------+--------&#39;
swap: test |
-----------------------------------&#39;
State III
| slot-0 | slot-1 |
-----------------+--------+--------|
magic | Good | Unset |
image-ok | 0xff | N/A |
-----------------+--------+--------&#39;
pending | | |
confirmed | | X |
-----------------+--------+--------&#39;
swap: revert (test image running) |
-----------------------------------&#39;
State IV
| slot-0 | slot-1 |
-----------------+--------+--------|
magic | Good | Unset |
image-ok | 0x01 | N/A |
-----------------+--------+--------&#39;
pending | | |
confirmed | X | |
-----------------+--------+--------&#39;
swap: none (confirmed test image) |
-----------------------------------&#39;
</code></pre></div>
<h3 id="high-level-operation">High-level Operation</h3>
<p>With the terms defined, we can now explore the boot loader's operation. First,
a high-level overview of the boot process is presented. Then, the following
sections describe each step of the process in more detail.</p>
<p>Procedure:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>A. Inspect swap status region; is an interrupted swap is being resumed?
Yes: Complete the partial swap operation; skip to step C.
No: Proceed to step B.
B. Inspect boot vector; is a swap requested?
Yes.
1. Is the requested image valid (integrity and security check)?
Yes.
a. Perform swap operation.
b. Persist completion of swap procedure to boot vector.
c. Proceed to step C.
No.
a. Erase invalid image.
b. Persist failure of swap procedure to boot vector.
c. Proceed to step C.
No: Proceed to step C.
C. Boot into image in slot 0.
</code></pre></div>
<h3 id="image-swapping">Image Swapping</h3>
<p>The boot loader swaps the contents of the two image slots for two reasons:</p>
<ul>
<li>User has issued an "image test" operation; the image in slot-1 should be
run once (state II).</li>
<li>Test image rebooted without being confirmed; the boot loader should
revert to the original image currently in slot-1 (state III).</li>
</ul>
<p>If the boot vector indicates that the image in the secondary slot should be
run, the boot loader needs to copy it to the primary slot. The image currently
in the primary slot also needs to be retained in flash so that it can be used
later. Furthermore, both images need to be recoverable if the boot loader
resets in the middle of the swap operation. The two images are swapped
according to the following procedure:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>1. Determine how many flash sectors each image slot consists of. This
number must be the same for both slots.
2. Iterate the list of sector indices in descending order (i.e., starting
with the greatest index); current element = &quot;index&quot;.
b. Erase scratch area.
c. Copy slot0[index] to scratch area.
d. Write updated swap status (i).
e. Erase slot1[index]
f. Copy slot0[index] to slot1[index]
- If these are the last sectors (i.e., first swap being perfomed),
copy the full sector *except* the image trailer.
- Else, copy entire sector contents.
g. Write updated swap status (ii).
h. Erase slot0[index].
i. Copy scratch area slot0[index].
j. Write updated swap status (iii).
3. Persist completion of swap procedure to slot 0 image trailer.
</code></pre></div>
<p>The additional caveats in step 2f are necessary so that the slot 1 image trailer
can be written by the user at a later time. With the image trailer unwritten,
the user can test the image in slot 1 (i.e., transition to state II).</p>
<p>The particulars of step 3 vary depending on whether an image is being tested or
reverted:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>* test:
o Write slot0.copy_done = 1
(should now be in state III)
* revert:
o Write slot0.magic = BOOT_MAGIC
o Write slot0.copy_done = 1
o Write slot0.image_ok = 1
(should now be in state IV)
</code></pre></div>
<h3 id="swap-status">Swap Status</h3>
<p>The swap status region allows the boot loader to recover in case it restarts in
the middle of an image swap operation. The swap status region consists of a
series of single-byte records. These records are written independently, and
therefore must be padded according to the minimum write size imposed by the
flash hardware. In the below figure, a <code>min-write-size</code> of 1 is assumed for
simplicity. The structure of the swap status region is illustrated below. In
this figure, a <code>min-write-size</code> of 1 is assumed for simplicity.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sec127,state 0 |sec127,state 1 |sec127,state 2 |sec126,state 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sec126,state 1 |sec126,state 2 |sec125,state 0 |sec125,state 1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sec125,state 2 | |
+-+-+-+-+-+-+-+-+ +
~ ~
~ [Records for indices 124 through 1 ~
~ ~
~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ |sec000,state 0 |sec000,state 1 |sec000,state 2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</code></pre></div>
<p>And now, in English...</p>
<p>Each image slot is partitioned into a sequence of flash sectors. If we were to
enumerate the sectors in a single slot, starting at 0, we would have a list of
sector indices. Since there are two image slots, each sector index would
correspond to a pair of sectors. For example, sector index 0 corresponds to
the first sector in slot 0 and the first sector in slot 1. Furthermore, we
impose a limit of 128 indices. If an image slot consists of more than 128
sectors, the flash layout is not compatible with this boot loader. Finally,
reverse the list of indices such that the list starts with index 127 and ends
with 0. The swap status region is a representation of this reversed list.</p>
<p>During a swap operation, each sector index transitions through four separate
states:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>0. slot 0: image 0, slot 1: image 1, scratch: N/A
1. slot 0: image 0, slot 1: N/A, scratch: image 1 (1-&gt;s, erase 1)
2. slot 0: N/A, slot 1: image 0, scratch: image 1 (0-&gt;1, erase 0)
3. slot 0: image 1, slot 1: image 0, scratch: N/A (s-&gt;0)
</code></pre></div>
<p>Each time a sector index transitions to a new state, the boot loader writes a
record to the swap status region. Logically, the boot loader only needs one
record per sector index to keep track of the current swap state. However, due
to limitations imposed by flash hardware, a record cannot be overwritten when
an index's state changes. To solve this problem, the boot loader uses three
records per sector index rather than just one.</p>
<p>Each sector-state pair is represented as a set of three records. The record
values map to the above four states as follows</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> | rec0 | rec1 | rec2
--------+------+------+------
state 0 | 0xff | 0xff | 0xff
state 1 | 0x01 | 0xff | 0xff
state 2 | 0x01 | 0x02 | 0xff
state 3 | 0x01 | 0x02 | 0x03
</code></pre></div>
<p>The swap status region can accommodate 128 sector indices. Hence, the size of
the region, in bytes, is <code>128 * min-write-size * 3</code>. The number 128 is chosen
somewhat arbitrarily and will likely be made configurable. The only
requirement for the index count is that is is great enough to account for a
maximum-sized image (i.e., at least as great as the total sector count in an
image slot). If a device's image slots use less than 128 sectors, the first
record that gets written will be somewhere in the middle of the region. For
example, if a slot uses 64 sectors, the first sector index that gets swapped is
63, which corresponds to the exact halfway point within the region.</p>
<h3 id="reset-recovery">Reset Recovery</h3>
<p>If the boot loader resets in the middle of a swap operation, the two images may
be discontiguous in flash. Bootutil recovers from this condition by using the
boot vector to determine how the image parts are distributed in flash.</p>
<p>The first step is determine where the relevant swap status region is located.
Because this region is embedded within the image slots, its location in flash
changes during a swap operation. The below set of tables map boot vector
contents to swap status location. In these tables, the "source" field
indicates where the swap status region is located.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> | slot-0 | scratch |
----------+------------+------------|
magic | Good | Any |
copy-done | 0x01 | N/A |
----------+------------+------------&#39;
source: none |
------------------------------------&#39;
| slot-0 | scratch |
----------+------------+------------|
magic | Good | Any |
copy-done | 0xff | N/A |
----------+------------+------------&#39;
source: slot 0 |
------------------------------------&#39;
| slot-0 | scratch |
----------+------------+------------|
magic | Any | Good |
copy-done | Any | N/A |
----------+------------+------------&#39;
source: scratch |
------------------------------------&#39;
| slot-0 | scratch |
----------+------------+------------|
magic | Unset | Any |
copy-done | 0xff | N/A |
----------+------------+------------|
source: varies |
------------------------------------+------------------------------+
This represents one of two cases: |
o No swaps ever (no status to read, so no harm in checking). |
o Mid-revert; status in slot 0. |
-------------------------------------------------------------------&#39;
</code></pre></div>
<p>If the swap status region indicates that the images are not contiguous,
bootutil completes the swap operation that was in progress when the system was
reset. In other words, it applies the procedure defined in the previous
section, moving image 1 into slot 0 and image 0 into slot 1. If the boot
status file indicates that an image part is present in the scratch area, this
part is copied into the correct location by starting at step e or step h in the
area-swap procedure, depending on whether the part belongs to image 0 or image
1.</p>
<p>After the swap operation has been completed, the boot loader proceeds as though
it had just been started.</p>
<h3 id="integrity-check">Integrity Check</h3>
<p>An image is checked for integrity immediately before it gets copied into the
primary slot. If the boot loader doesn't perform an image swap, then it
doesn't perform an integrity check.</p>
<p>During the integrity check, the boot loader verifies the following aspects of
an image:</p>
<ul>
<li>32-bit magic number must be correct (0x96f3b83c).</li>
<li>Image must contain a SHA256 TLV.</li>
<li>Calculated SHA256 must matche SHA256 TLV contents.</li>
<li>Image <em>may</em> contain a signature TLV. If it does, its contents must be
verifiable using a key embedded in the boot loader.</li>
</ul>
<h3 id="image-signing-and-verification">Image Signing and Verification</h3>
<p>As indicated above, the final step of the integrity check is signature
verification. The boot loader can have one or more public keys embedded in it
at build time. During signature verification, the boot loader verifies that an
image was signed with a private key that corresponds to one of its public keys.
The image signature TLV indicates the index of the key that is has been signed
with. The boot loader uses this index to identify the corresponding public
key.</p>
<p>For information on embedding public keys in the boot loader, as well as
producing signed images, see: boot/bootutil/signed_images.md</p>
<div class="row">
<ul class="nav nav-pills" style="margin-bottom: 10px">
<li>
</li>
<li class="pull-right">
</li>
</ul>
</div>
<footer class="row">
<div class="col-xs-12">
<p class="copyright">Apache Mynewt (incubating) is available under Apache License, version 2.0.</p>
</div>
<div class="col-xs-12">
<div class="logos">
<a href="https://www.apache.org/">
<img src="/img/asf_logo_wide_small.png" alt="Apache" title="Apache">
</a>
<p>
Copyright © 2015-2021 The Apache Software Foundation.<br>
<small class="footnote">
Apache Mynewt, Mynewt, Apache, the Apache feather logo, and the Apache Mynewt
project logo are either registered trademarks or trademarks of the Apache
Software Foundation in the United States and other countries.
</small>
</p>
<a href="">
<img src="https://www.countit.com/images/add_to_slack.png" alt="Slack Icon" title="Join our Slack Community" />
</a>
</div>
</div>
<a href="https://www.apache.org/licenses/">
<button class="button-footer-asf">
License
</button>
</a>
<a href="https://www.apache.org/foundation/sponsorship.html">
<button class="button-footer-asf">
Sponsorship
</button>
</a>
<a href="https://www.apache.org/foundation/thanks.html">
<button class="button-footer-asf">
Thanks
</button>
</a>
<a href="https://www.apache.org/security/">
<button class="button-footer-asf">
Security
</button>
</a>
<a href="https://apache.org/events/current-event">
<button class="button-footer-asf">
ASF Events
</button>
</a>
</footer>
</div>
</div>
</div>
<script src="../../../../js/jquery-1.10.2.min.js"></script>
<script src="../../../../js/bootstrap-3.0.3.min.js"></script>
<script src="../../../../js/highlight.pack.js"></script>
<script src="../../../../js/base.js"></script>
<script src="../../../../js/custom.js"></script>
<script src="search/main.js"></script>
</body>
</html>