Skip to content
README.md 6.5 KiB
Newer Older
f4grx's avatar
f4grx committed
The hn70ap bootloader
=====================

The firmware on the hn70ap board can be directly flashed via JTAG. It can also
f4grx's avatar
f4grx committed
be updated using a dedicated process that does not required JTAG.
f4grx's avatar
f4grx committed

How it works
------------

The hn70ap board features an on-board 64 Mb (8 Mbytes) flash memory that is
logically split into two partitions:

 * a 2 MB firmware update partition,
 * a 6 MB a storage partition.

(Note: The next revision will hold two flash chip, and a kind of "RAID0" driver
will be used to aggregate the storage partition and the memory on a secondary
flash.)

Some firmware tools are available to download a firmware update image and store
it in this external flash. The download process can happen via Ethernet, serial,
or serial in the bootloader mode (failsafe recovery mode).

The internal STM32 flash memory is also logically split into two parts:
 * the bootloader, occupies the first sector (16kB) of the internal STM32 flash
(address range 0x08000000 - 0x08004000).
 * the user software, in the other sectors (starting at 0x08004000)

f4grx's avatar
f4grx committed
This means is that instead of directly starting to execute the user
f4grx's avatar
f4grx committed
software, the CPU always starts to execute inside the bootloader. The bootloader
runs some update process described later, then remaps the CPU vector table to
the beginning of the user software using the ARM VTOR register, setups the
stack pointer defined in the zeroth vector, and jumps to the address stored in
the first vector, as would be done by the CPU startup procedure.

In the original NuttX firmware, this address map is ensured by the project's
linker script, that justs makes the linker believe that the main .text section
starts at this 0x08004000 address instead of 0x08000000. No other change is
required in the NuttX RTOS. If you want to use a custom firmware, you have to
make sure that you skip the first 16 kbytes of the flash.

Once the firmware update image has landed in the external flash, the bootloader
can check that an update is present by looking at the image header in the first
256 bytes of the external flash. The first 4 bytes are the CRC32 of the next
252 bytes. If the image header is found valid, the update stored in the
following pages is programmed in the internal STM32 flash. If not valid, the
f4grx's avatar
f4grx committed
update partition is wiped before the current user software starts.

After having erased and reprogrammed the internal STM32 flash, the update
partition is then wiped.
f4grx's avatar
f4grx committed

The bootloader itself writes protects itself during its startup process, so it
cannot be erased inadvertently. If a bug is found during the life of the
product, the bootloader will be forced to update via a specific process.

f4grx's avatar
f4grx committed
Update failures
---------------

We have to be sure that the update process cannot brick the board. We believe
that it is not possible to end up with a board that cannot boot any software
because
 * the bootloader is write protected as soon as it starts
 * Any power interruption during the erase or programming of the internal
flash will trigger another attempt at next power cycle
 * Internal flash is verified before the external flash is wiped
 * Any invalid image is detected before any update takes place.

These reasons make us believe that the update process as designed is safe.
However, implementation bugs are still possible.

If the stm32 flash becomes erased, power is interrupted, and, because of this,
the external flash contents become invalid (which is highly unlikely), the
update will actually fail, and the bootloader will attempt to start an half
erased or half programmed stm32, while the external flash has become
unusable. This particular section cannot be detected at the
moment, but the update button can still be pressed to trigger a serial
downloader that will be able to put a new update image in the external flash.

f4grx's avatar
f4grx committed
Firmware update image format
f4grx's avatar
f4grx committed
============================
f4grx's avatar
f4grx committed

The following paragraph describes the layout of the firmware update image.

The image has two parts:
 * a 16k header (that replaces the bootloader contents, which is not stored in
the firmware update image)
 * a variable length memory image

Header
------

f4grx's avatar
f4grx committed
Note: bits in bytes are enumerated the natural way, b7 = 0x80 and b0 = 0x01.
f4grx's avatar
f4grx committed

f4grx's avatar
f4grx committed
The first 256 bytes of the update image contains critical information related
to the update. The first 4 bytes are the CRC-32 (ZIP or GZIP algorithm) of the
next 252 bytes. If the CRC is not valid, the update is not applied by the
bootloader.
The next 252 bytes contain a sequence of TLV elements. TLV elements are a
f4grx's avatar
f4grx committed
nestable binary data structure similar to BER or DER, but simpler. This
structure easy future extensions.

TLVs have 3 fields:
f4grx's avatar
f4grx committed
 * a TAG: actually a bit field. It indicates a tag number, a tag class, a bit
f4grx's avatar
f4grx committed
indicating if the tag data field is raw or contains more tag.
f4grx's avatar
f4grx committed
* a LENGTH: this one describes how many bytes are in the payload (value).
f4grx's avatar
f4grx committed
Lengths from 0 to 127 are encoded as one byte, longer lengths are encoded as a
first byte (0x80 + number of bytes needed to encode actual length) followed by actual
length encoded in that number of bytes.
f4grx's avatar
f4grx committed
* a VALUE: can be raw bytes or nested tags according to the TAG.
f4grx's avatar
f4grx committed

Tag encoding table:
```
76543210
00...... Universal tag class - basic types
01...... Application class - defined by a norm
10...... Context specific class - depends on parent tag
11...... Private class (we will use this)
..0..... Primitive data object (Value contains bytes)
..1..... Constructed data object (Value contains more tags)
...xxxxx Tag value from 0 to 30
...11111 Reserved tag signaling the use of a second tag byte
```

Some of this info is also described here:
https://www.openscdp.org/scripts/tutorial/emv/TLV.html

The following private tags are used to describe some metadata about the update:
```
f4grx's avatar
f4grx committed
0xC0 - User software size (4 bytes, required)
0xC1 - Major version (1 byte, optional)
0xC2 - Minor version (1 byte, optional)
0xC3 - CRC32 of the user software (4 bytes, required)
0xC4 - SHA256 of the user software (32 bytes, optional)
f4grx's avatar
f4grx committed
```

If multiple tags are defined, which is not normally done by the generation
tool, then the first values are used.

f4grx's avatar
f4grx committed
The tags are padded with 0xFF (invalid tag) to a length of 16384 bytes. In the
future this space will be usable to hold firmware signatures.
f4grx's avatar
f4grx committed

Image
-----
The image is nothing special. It just contains bytes that represent the user
software. The length of this part is equal to the value indicated in tag 0x80.

Firmware update tool
====================

This tool is written in python. It reads memory segments from an ELF file and
writes the firmware image. If a symbol table is found, the hn70ap entry is
searched and its content is used to initialize the header.

eof