bootloader+loader: rework build, make clear what is bootloader and what is loader in docu

This commit is contained in:
Pavol Rusnak 2017-03-20 15:58:47 +01:00
parent cc525e97ce
commit cbaca604f3
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
6 changed files with 28 additions and 23 deletions

View File

@ -29,9 +29,13 @@ build_firmware_debug: vendor res build_cross ## build firmware with frozen modul
$(MAKE) -f Makefile.firmware $(TREZORHAL_PORT_OPTS) DEBUG=1 $(MAKE) -f Makefile.firmware $(TREZORHAL_PORT_OPTS) DEBUG=1
build_bootloader: vendor ## build bootloader build_bootloader: vendor ## build bootloader
mkdir -p $(BOOTLOADER_BUILD_DIR)/genhdr
touch $(BOOTLOADER_BUILD_DIR)/genhdr/qstrdefs.generated.h
$(MAKE) -f Makefile.bootloader $(TREZORHAL_PORT_OPTS) $(MAKE) -f Makefile.bootloader $(TREZORHAL_PORT_OPTS)
build_loader: vendor ## build loader build_loader: vendor ## build loader
mkdir -p $(LOADER_BUILD_DIR)/genhdr
touch $(LOADER_BUILD_DIR)/genhdr/qstrdefs.generated.h
$(MAKE) -f Makefile.loader $(TREZORHAL_PORT_OPTS) $(MAKE) -f Makefile.loader $(TREZORHAL_PORT_OPTS)
build_unix: vendor ## build unix port build_unix: vendor ## build unix port

View File

@ -1,46 +1,47 @@
# TREZOR Core Bootloader # TREZOR Core Bootloader
Bootloader is split into two stages. See [Memory Layout](memory.md) for info about in which sectors each stage is stored. TREZOR initialization in split into two stages. See [Memory Layout](memory.md) for info about in which sectors each stage is stored.
First stage is stored in write-protected area, which means it is non-upgradable. Only second stage bootloader update is allowed. First stage (bootloader) is stored in write-protected area, which means it is non-upgradable.
Only second stage (loader) update is allowed.
## First Stage Bootloader ## First Stage - Bootloader
First stage checks the integrity and signatures of the second stage and runs it if everything is OK. First stage checks the integrity and signatures of the second stage and runs it if everything is OK.
If first stage bootloader finds a valid second stage bootloader image on the SD card (in raw format, no filesystem), If first stage bootloader finds a valid second stage loader image on the SD card (in raw format, no filesystem),
it will replace the internal second stage, allowing a second stage update via SD card. it will replace the internal second stage, allowing a second stage update via SD card.
## Second Stage Bootloader ## Second Stage - Loader
Second stage checks the integrity and signatures of the firmware and runs it if everything is OK. Second stage checks the integrity and signatures of the firmware and runs it if everything is OK.
If second stage bootloader detects a pressed finger on the display or there is no firmware loaded in the device, If second stage loader detects a pressed finger on the display or there is no firmware loaded in the device,
it will start in a firmware update mode, allowing a firmware update via USB. it will start in a firmware update mode, allowing a firmware update via USB.
## Common notes ## Common notes
* Hash function used below is SHA-256 and signature system is Ed25519 (allows combining signatures by multiple keys into one). * Hash function used below is SHA-256 and signature system is Ed25519 (allows combining signatures by multiple keys into one).
* All multibyte integer values are little endian. * All multibyte integer values are little endian.
* There is a tool called [firmwarectl](../tools/firmwarectl) which checks validity of the bootloader/firmware images including their headers. * There is a tool called [firmwarectl](../tools/firmwarectl) which checks validity of the loader/firmware images including their headers.
## Bootloader Format ## Loader Format
TREZOR Core (second stage) bootloader consists of 2 parts: TREZOR Core (second stage) loader consists of 2 parts:
1. bootloader header 1. loader header
2. bootloader code 2. loader code
### Bootloader Header ### Loader Header
Total length of bootloader header is always 256 bytes. Total length of loader header is always 256 bytes.
| offset | length | name | description | | offset | length | name | description |
|-------:|-------:|------|-------------| |-------:|-------:|------|-------------|
| 0x0000 | 4 | magic | firmware magic `TRZB` | | 0x0000 | 4 | magic | firmware magic `TRZL` |
| 0x0004 | 4 | hdrlen | length of the bootloader header | | 0x0004 | 4 | hdrlen | length of the loader header |
| 0x0008 | 4 | expiry | valid until timestamp (0=infinity) | | 0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
| 0x000C | 4 | codelen | length of the bootloader code (without the header) | | 0x000C | 4 | codelen | length of the loader code (without the header) |
| 0x0010 | 1 | vmajor | version (major) | | 0x0010 | 1 | vmajor | version (major) |
| 0x0011 | 1 | vminor | version (minor) | | 0x0011 | 1 | vminor | version (minor) |
| 0x0012 | 1 | vpatch | version (patch) | | 0x0012 | 1 | vpatch | version (patch) |
@ -100,7 +101,7 @@ Total length of firmware header is always 256 bytes.
## Various ideas ## Various ideas
* Bootloader should be able to read vendor+firmware header and send info about FW to client in features message. * Loader should be able to read vendor + firmware header and send info about FW to client in features message.
* Bootloader should not try to run firmware if there is not any. * Loader should not try to run firmware if there is not any.
* Storage wiping rule: Don't erase storage when old FW and new FW are signed using the same key set. Otherwise erase. * Storage wiping rule: Don't erase storage when old FW and new FW are signed using the same key set. Otherwise erase.
* Bootloader should send error to client when firmware update fails and allow client to try one more time. This prevents storage area erasure by accident. * Loader should send error to client when firmware update fails and allow client to try one more time. This prevents storage area erasure by accident.

View File

@ -4,11 +4,11 @@
| sector | range | size | function | sector | range | size | function
|-----------|-------------------------|--------:|---------------------- |-----------|-------------------------|--------:|----------------------
| Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader 1st stage (write-protected) | Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader (1st stage) (write-protected)
| Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader 1st stage (write-protected) | Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader (1st stage) (write-protected)
| Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | storage area | Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | storage area
| Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | storage area | Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | storage area
| Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | bootloader 2nd stage | Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | loader (2nd stage)
| Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | firmware | Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | firmware
| Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | firmware | Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | firmware
| Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | firmware | Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | firmware

View File

@ -11,7 +11,7 @@ bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8
{ {
uint32_t magic; uint32_t magic;
memcpy(&magic, data, 4); memcpy(&magic, data, 4);
if (magic != 0x425A5254) return false; // TRZB if (magic != 0x4C5A5254) return false; // TRZL
uint32_t hdrlen; uint32_t hdrlen;
memcpy(&hdrlen, data + 4, 4); memcpy(&hdrlen, data + 4, 4);