blob: 4a1f00241a5f45530154e7fbbdeca61109f009b7 [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">
<title>Bootloader &mdash; Apache Mynewt latest documentation</title>
<link rel="shortcut icon" href="../../../_static/mynewt-logo-only-newt32x32.png"/>
<link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/css/sphinx_theme.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/css/bootstrap-3.0.3.min.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/css/v2.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/css/custom.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/css/restructuredtext.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/css/overrides.css" type="text/css" />
<link rel="index" title="Index"
href="../../../genindex.html"/>
<link rel="search" title="Search" href="../../../search.html"/>
<link rel="top" title="Apache Mynewt latest documentation" href="../../../index.html"/>
<link rel="up" title="OS User Guide" href="../../os_user_guide.html"/>
<link rel="next" title="Split Images" href="../split/split.html"/>
<link rel="prev" title="BSP" href="../hal/hal_bsp/hal_bsp.html"/>
<script src="../../../_static/js/modernizr.min.js"></script>
<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="not-front page-documentation" role="document" >
<div id="wrapper">
<div class="container">
<div id="banner" class="row v2-main-banner">
<a class="logo-cell" href="/">
<img class="logo" src="../../../_static/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>
<header>
<nav id="navbar" class="navbar navbar-inverse" 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>
<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>
<a href="/about/">About</a>
</li>
<li>
<a href="/talks/">Talks</a>
</li>
<li class="active">
<a href="/documentation/">Documentation</a>
</li>
<li>
<a href="/download/">Download</a>
</li>
<li>
<a href="/community/">Community</a>
</li>
<li>
<a href="/events/">Events</a>
</li>
</ul>
<!-- Search, Navigation and Repo links -->
<ul class="nav navbar-nav navbar-right">
</ul>
</div>
</div>
</nav>
</header>
<!-- STARTS MAIN CONTENT -->
<div id="main-content">
<div id="breadcrumb">
<div class="container">
<a href="/documentation/">Docs</a> /
<a href="../../os_user_guide.html">OS User Guide</a> /
Bootloader
<div class="sourcelink">
<a href="https://github.com/apache/mynewt-core/edit/master/docs/os/modules/bootloader/bootloader.rst" class="icon icon-github"
rel="nofollow"> Edit on GitHub</a>
</div>
</div>
</div>
<!-- STARTS CONTAINER -->
<div class="container">
<!-- STARTS .content -->
<div id="content" class="row">
<!-- STARTS .container-sidebar -->
<div class="container-sidebar col-xs-12 col-sm-3">
<div id="docSidebar" class="sticky-container">
<div role="search" class="sphinx-search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search documentation" class="search-documentation" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<!-- Note: only works when deployed -->
<select class="form-control" onchange="if (this.value) window.location.href=this.value">
<option value="/latest" selected>
Version: latest
</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" selected="selected" >
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" >
Version: 1.0.0
</option>
<option value="/v0_9_0/os/introduction" >
Version: 0.9.0
</option>
</select>
<div class="region region-sidebar">
<div class="docs-menu">
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../../index.html">Introduction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../get_started/index.html">Setup &amp; Get Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../concepts.html">Concepts</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../tutorials/tutorials.html">Tutorials</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../external_links.html">Third-party Resources</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../../os_user_guide.html">OS User Guide</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../../core_os/mynewt_os.html">Kernel</a></li>
<li class="toctree-l2"><a class="reference internal" href="../system_modules.html">System</a></li>
<li class="toctree-l2"><a class="reference internal" href="../hal/hal.html">Hardware Abstraction</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">Secure Bootloader</a></li>
<li class="toctree-l2"><a class="reference internal" href="../split/split.html">Split Images</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../core_os/porting/port_os.html">Porting Guide</a></li>
<li class="toctree-l2"><a class="reference internal" href="../baselibc.html">Baselibc</a></li>
<li class="toctree-l2"><a class="reference internal" href="../drivers/driver.html">Drivers</a></li>
<li class="toctree-l2"><a class="reference internal" href="../devmgmt/newtmgr.html">Device Management with Newt Manager</a></li>
<li class="toctree-l2"><a class="reference internal" href="../mcumgr/mcumgr.html">Device Management with MCUmgr</a></li>
<li class="toctree-l2"><a class="reference internal" href="../imgmgr/imgmgr.html">Image Manager</a></li>
<li class="toctree-l2"><a class="reference internal" href="../sysinitconfig/sysinitconfig.html">Compile-Time Configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="../fs/fs.html">File System</a></li>
<li class="toctree-l2"><a class="reference internal" href="../fcb/fcb.html">Flash Circular Buffer</a></li>
<li class="toctree-l2"><a class="reference internal" href="../sensor_framework/sensor_framework.html">Sensor Framework</a></li>
<li class="toctree-l2"><a class="reference internal" href="../testutil/testutil.html">Test Utilities</a></li>
<li class="toctree-l2"><a class="reference internal" href="../json/json.html">JSON</a></li>
<li class="toctree-l2"><a class="reference internal" href="../mfg/mfg.html">Manufacturing support</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../../network/index.html">BLE User Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../newt/index.html">Newt Tool Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../newtmgr/index.html">Newt Manager Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../mynewt_faq/index.html">Mynewt FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../misc/index.html">Appendix</a></li>
</ul>
</div>
</div>
</div>
<!-- ENDS STICKY CONTAINER -->
</div>
<!-- ENDS .container-sidebar -->
<div class="col-xs-12 col-sm-9">
<div class="alert alert-warning">
<p>
Version 1.6.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>
<div class="">
<div class="rst-content">
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="bootloader">
<h1>Bootloader<a class="headerlink" href="#bootloader" title="Permalink to this headline"></a></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.</p>
<p>The “secure bootloader” should be placed in protected memory on a given
microcontroller.</p>
<p>The Apache Mynewt bootloader is the foundation of <a class="reference external" href="https://github.com/runtimeco/mcuboot/">MCUboot</a>,
a secure bootloader for 32-bit MCUs that has been ported to other Operating Systems as well.</p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><p><a class="reference internal" href="#limitations" id="id1">Limitations</a></p></li>
<li><p><a class="reference internal" href="#image-format" id="id2">Image Format</a></p></li>
<li><p><a class="reference internal" href="#flash-map" id="id3">Flash Map</a></p></li>
<li><p><a class="reference internal" href="#image-slots" id="id4">Image Slots</a></p></li>
<li><p><a class="reference internal" href="#boot-states" id="id5">Boot States</a></p></li>
<li><p><a class="reference internal" href="#boot-vector" id="id6">Boot Vector</a></p></li>
<li><p><a class="reference internal" href="#high-level-operation" id="id7">High-level Operation</a></p></li>
<li><p><a class="reference internal" href="#image-swapping" id="id8">Image Swapping</a></p></li>
<li><p><a class="reference internal" href="#swap-status" id="id9">Swap Status</a></p></li>
<li><p><a class="reference internal" href="#reset-recovery" id="id10">Reset Recovery</a></p></li>
<li><p><a class="reference internal" href="#integrity-check" id="id11">Integrity Check</a></p></li>
<li><p><a class="reference internal" href="#image-signing-and-verification" id="id12">Image Signing and Verification</a></p></li>
</ul>
</div>
<p>The Mynewt bootloader comprises two packages:</p>
<ul class="simple">
<li><p>The bootutil library (boot/bootutil)</p></li>
<li><p>The boot application (apps/boot)</p></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 class="arabic simple">
<li><p>By keeping architecture-dependent code separate, the bootutil library
can be reused among several boot loaders.</p></li>
<li><p>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.</p></li>
</ol>
<div class="section" id="limitations">
<h2><a class="toc-backref" href="#id1">Limitations</a><a class="headerlink" href="#limitations" title="Permalink to this headline"></a></h2>
<p>The boot loader currently only supports images with the following
characteristics:</p>
<ul class="simple">
<li><p>Built to run from flash.</p></li>
<li><p>Build to run from a fixed location (i.e., position-independent).</p></li>
</ul>
</div>
<div class="section" id="image-format">
<h2><a class="toc-backref" href="#id2">Image Format</a><a class="headerlink" href="#image-format" title="Permalink to this headline"></a></h2>
<p>The following definitions describe the image header format.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#define IMAGE_MAGIC 0x96f3b83c</span>
<span class="cp">#define IMAGE_MAGIC_NONE 0xffffffff</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">image_version</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">iv_major</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">iv_minor</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">iv_revision</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">iv_build_num</span><span class="p">;</span>
<span class="p">};</span>
<span class="cm">/** Image header. All fields are in little endian byte order. */</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">image_header</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">ih_magic</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">ih_tlv_size</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Trailing TLVs */</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">ih_key_id</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">_pad1</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">ih_hdr_size</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">_pad2</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">ih_img_size</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Does not include header. */</span>
<span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">ih_flags</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">image_version</span><span class="w"> </span><span class="n">ih_ver</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">_pad3</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">ih_hdr_size</span></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="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#define IMAGE_F_PIC 0x00000001</span>
<span class="cp">#define IMAGE_F_SHA256 0x00000002 </span><span class="cm">/* Image contains hash TLV */</span>
<span class="cp">#define IMAGE_F_PKCS15_RSA2048_SHA256 0x00000004 </span><span class="cm">/* PKCS15 w/RSA and SHA */</span>
<span class="cp">#define IMAGE_F_ECDSA224_SHA256 0x00000008 </span><span class="cm">/* ECDSA256 over SHA256 */</span>
<span class="cp">#define IMAGE_F_NON_BOOTABLE 0x00000010</span>
<span class="cp">#define IMAGE_HEADER_SIZE 32</span>
</pre></div>
</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="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/** Image trailer TLV format. All fields in little endian. */</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">image_tlv</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">it_type</span><span class="p">;</span><span class="w"> </span><span class="cm">/* IMAGE_TLV_[...]. */</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">_pad</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">it_len</span><span class="w"> </span><span class="cm">/* Data length (not including TLV header). */</span>
<span class="p">};</span>
<span class="cm">/*</span>
<span class="cm"> * Image trailer TLV types.</span>
<span class="cm"> */</span>
<span class="cp">#define IMAGE_TLV_SHA256 1 </span><span class="cm">/* SHA256 of image hdr and body */</span>
<span class="cp">#define IMAGE_TLV_RSA2048 2 </span><span class="cm">/* RSA2048 of hash output */</span>
<span class="cp">#define IMAGE_TLV_ECDSA224 3 </span><span class="cm">/* ECDSA of hash output */</span>
</pre></div>
</div>
</div>
<div class="section" id="flash-map">
<h2><a class="toc-backref" href="#id3">Flash Map</a><a class="headerlink" href="#flash-map" title="Permalink to this headline"></a></h2>
<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 class="arabic simple">
<li><p>An area can be fully erased without affecting any other areas.</p></li>
<li><p>A write to one area does not restrict writes to other areas.</p></li>
</ol>
<p>The boot loader uses the following flash areas:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#define FLASH_AREA_BOOTLOADER 0</span>
<span class="cp">#define FLASH_AREA_IMAGE_0 1</span>
<span class="cp">#define FLASH_AREA_IMAGE_1 2</span>
<span class="cp">#define FLASH_AREA_IMAGE_SCRATCH 3</span>
</pre></div>
</div>
</div>
<div class="section" id="image-slots">
<h2><a class="toc-backref" href="#id4">Image Slots</a><a class="headerlink" href="#image-slots" title="Permalink to this headline"></a></h2>
<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>
</div>
<div class="section" id="boot-states">
<h2><a class="toc-backref" href="#id5">Boot States</a><a class="headerlink" href="#boot-states" title="Permalink to this headline"></a></h2>
<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 class="simple">
<li><p>pending: image gets tested on next reboot; absent subsequent confirm
command, revert to original image on second reboot.</p></li>
<li><p>confirmed: always use image unless excluded by a test image.</p></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="highlight-none notranslate"><div class="highlight"><pre><span></span> | 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;
</pre></div>
</div>
</div>
<div class="section" id="boot-vector">
<h2><a class="toc-backref" href="#id6">Boot Vector</a><a class="headerlink" href="#boot-vector" title="Permalink to this headline"></a></h2>
<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="highlight-none notranslate"><div class="highlight"><pre><span></span> 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) ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</pre></div>
</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 class="docutils literal notranslate"><span class="pre">min-write-size</span></code> is a property of the flash hardware. If the
hardware allows individual bytes to be written at arbitrary addresses,
then <code class="docutils literal notranslate"><span class="pre">min-write-size</span></code> is 1. If the hardware only allows writes at even
addresses, then <code class="docutils literal notranslate"><span class="pre">min-write-size</span></code> is 2, and so on.</p>
<p>The fields are defined as follows:</p>
<ol class="arabic">
<li><p>MAGIC: The following 16 bytes, written in host-byte-order:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>const uint32_t boot_img_magic[4] = {
0xf395c277,
0x7fefd260,
0x0f505235,
0x8079b62c,
};
</pre></div>
</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 class="docutils literal notranslate"><span class="pre">0x01=done,</span> <span class="pre">0xff=not</span> <span class="pre">done</span></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 class="docutils literal notranslate"><span class="pre">0x01=confirmed;</span> <span class="pre">0xff=not</span> <span class="pre">confirmed</span></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="highlight-none notranslate"><div class="highlight"><pre><span></span>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;
</pre></div>
</div>
</div>
<div class="section" id="high-level-operation">
<h2><a class="toc-backref" href="#id7">High-level Operation</a><a class="headerlink" href="#high-level-operation" title="Permalink to this headline"></a></h2>
<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="highlight-none notranslate"><div class="highlight"><pre><span></span>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.
</pre></div>
</div>
</div>
<div class="section" id="image-swapping">
<h2><a class="toc-backref" href="#id8">Image Swapping</a><a class="headerlink" href="#image-swapping" title="Permalink to this headline"></a></h2>
<p>The boot loader swaps the contents of the two image slots for two
reasons:</p>
<ul class="simple">
<li><p>User has issued an “image test” operation; the image in slot-1 should
be run once (state II).</p></li>
<li><p>Test image rebooted without being confirmed; the boot loader should
revert to the original image currently in slot-1 (state III).</p></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="highlight-none notranslate"><div class="highlight"><pre><span></span>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.
</pre></div>
</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="highlight-none notranslate"><div class="highlight"><pre><span></span>* 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)
</pre></div>
</div>
</div>
<div class="section" id="swap-status">
<h2><a class="toc-backref" href="#id9">Swap Status</a><a class="headerlink" href="#swap-status" title="Permalink to this headline"></a></h2>
<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 class="docutils literal notranslate"><span class="pre">min-write-size</span></code> of 1 is assumed for simplicity. The structure of the
swap status region is illustrated below. In this figure, a
<code class="docutils literal notranslate"><span class="pre">min-write-size</span></code> of 1 is assumed for simplicity.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</pre></div>
</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="highlight-none notranslate"><div class="highlight"><pre><span></span>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)
</pre></div>
</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="highlight-none notranslate"><div class="highlight"><pre><span></span> | rec0 | rec1 | rec2
--------+------+------+------
state 0 | 0xff | 0xff | 0xff
state 1 | 0x01 | 0xff | 0xff
state 2 | 0x01 | 0x02 | 0xff
state 3 | 0x01 | 0x02 | 0x03
</pre></div>
</div>
<p>The swap status region can accommodate 128 sector indices. Hence, the
size of the region, in bytes, is <code class="docutils literal notranslate"><span class="pre">128</span> <span class="pre">*</span> <span class="pre">min-write-size</span> <span class="pre">*</span> <span class="pre">3</span></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>
</div>
<div class="section" id="reset-recovery">
<h2><a class="toc-backref" href="#id10">Reset Recovery</a><a class="headerlink" href="#reset-recovery" title="Permalink to this headline"></a></h2>
<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="highlight-none notranslate"><div class="highlight"><pre><span></span> | 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;
</pre></div>
</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>
</div>
<div class="section" id="integrity-check">
<h2><a class="toc-backref" href="#id11">Integrity Check</a><a class="headerlink" href="#integrity-check" title="Permalink to this headline"></a></h2>
<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 class="simple">
<li><p>32-bit magic number must be correct (0x96f3b83c).</p></li>
<li><p>Image must contain a SHA256 TLV.</p></li>
<li><p>Calculated SHA256 must matche SHA256 TLV contents.</p></li>
<li><p>Image <em>may</em> contain a signature TLV. If it does, its contents must be
verifiable using a key embedded in the boot loader.</p></li>
</ul>
</div>
<div class="section" id="image-signing-and-verification">
<h2><a class="toc-backref" href="#id12">Image Signing and Verification</a><a class="headerlink" href="#image-signing-and-verification" title="Permalink to this headline"></a></h2>
<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 <a class="reference external" href="https://github.com/apache/mynewt-core/blob/master/boot/bootutil/signed_images.md">here</a>.</p>
</div>
</div>
</div>
</div>
<div class="rst-footer-buttons row" role="navigation" aria-label="footer navigation">
<a href="../split/split.html" class="btn btn-neutral float-right" title="Split Images" accesskey="n">Next: Split Images <span class="fa fa-arrow-circle-right"></span></a>
<a href="../hal/hal_bsp/hal_bsp.html" class="btn btn-neutral" title="BSP" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous: BSP</a>
</div>
</div>
</div>
</div>
<!-- ENDS CONTENT SECTION -->
</div>
<!-- ENDS .content -->
</div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="col-xs-12">
<p class="copyright">Apache Mynewt is available under Apache License, version 2.0.</p>
</div>
<div class="col-xs-12">
<div class="logos">
<img src="../../../_static/img/asf_logo_wide_small.png" alt="Apache" title="Apache">
<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>
<a href="">
<img src="../../../_static/img/add_to_slack.png" alt="Slack Icon" title="Join our Slack Community" />
</a>
</div>
</div>
</div>
</div>
</footer>
</div>
<!-- ENDS #wrapper -->
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'../../../',
VERSION:'latest',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
LINK_SUFFIX: '.html'
};
</script>
<script type="text/javascript" src="../../../_static/jquery.js"></script>
<script type="text/javascript" src="../../../_static/underscore.js"></script>
<script type="text/javascript" src="../../../_static/doctools.js"></script>
<script type="text/javascript" src="../../../_static/js/bootstrap-3.0.3.min.js"></script>
<script type="text/javascript" src="../../../_static/js/affix.js"></script>
<script type="text/javascript" src="../../../_static/js/main.js"></script>
</body>
</html>