Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compress embedded bootloader #3304

Merged
merged 2 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions core/SConscript.firmware
Original file line number Diff line number Diff line change
Expand Up @@ -790,16 +790,14 @@ if TREZOR_MODEL not in ('1',):
' $SOURCE $TARGET', ))

if TREZOR_MODEL not in ('DISC1', ):
obj_program.extend(
env.Command(
target='embed/firmware/bootloaders/bootloader.o',
source=f'embed/firmware/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin',
action='$OBJCOPY -I binary -O elf32-littlearm -B arm'
' --rename-section .data=.bootloader'
f' --redefine-sym _binary_embed_firmware_bootloaders_bootloader_{BOOTLOADER_SUFFIX}_bin_start=_binary_embed_firmware_bootloader_bin_start'
f' --redefine-sym _binary_embed_firmware_bootloaders_bootloader_{BOOTLOADER_SUFFIX}_bin_end=_binary_embed_firmware_bootloader_bin_end'
f' --redefine-sym _binary_embed_firmware_bootloaders_bootloader_{BOOTLOADER_SUFFIX}_bin_size=_binary_embed_firmware_bootloader_bin_size'
' $SOURCE $TARGET', ))
tools.embed_binary(
obj_program,
env,
'bootloader',
'embed/firmware/bootloaders/bootloader.o',
f'embed/firmware/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin',
)


env.Depends(obj_program, qstr_generated)

Expand Down
83 changes: 67 additions & 16 deletions core/embed/firmware/bl_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
#include "common.h"
#include "flash.h"
#include "image.h"
#include "memzero.h"
#include "model.h"
#include "uzlib.h"

// symbols from bootloader.bin => bootloader.o
extern const void _binary_embed_firmware_bootloader_bin_start;
extern const void _binary_embed_firmware_bootloader_bin_size;
extern const void
_binary_embed_firmware_bootloaders_bootloader_bin_deflated_start;
extern const void
_binary_embed_firmware_bootloaders_bootloader_bin_deflated_size;

/*
static secbool known_bootloader(const uint8_t *hash, int len) {
Expand Down Expand Up @@ -111,11 +115,31 @@ static secbool latest_bootloader(const uint8_t *hash, int len) {
}
#endif

#define UZLIB_WINDOW_SIZE (1 << 10)

#if PRODUCTION || BOOTLOADER_QA
static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window,
const void *src, uint32_t srcsize, void *dest,
uint32_t destsize) {
memzero(decomp, sizeof(struct uzlib_uncomp));
if (window) {
memzero(window, UZLIB_WINDOW_SIZE);
}
memzero(dest, destsize);
decomp->source = (const uint8_t *)src;
decomp->source_limit = decomp->source + srcsize;
decomp->dest = (uint8_t *)dest;
decomp->dest_limit = decomp->dest + destsize;
uzlib_uncompress_init(decomp, window, window ? UZLIB_WINDOW_SIZE : 0);
}
#endif

void check_and_replace_bootloader(void) {
#if PRODUCTION || BOOTLOADER_QA

// compute current bootloader hash
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
const uint32_t bl_len = 128 * 1024;
const uint32_t bl_len = flash_area_get_size(&BOOTLOADER_AREA);
const void *bl_data = flash_area_get_address(&BOOTLOADER_AREA, 0, bl_len);
blake2s(bl_data, bl_len, hash, BLAKE2S_DIGEST_LENGTH);

Expand All @@ -130,14 +154,25 @@ void check_and_replace_bootloader(void) {

// replace bootloader with the latest one
const uint32_t *data =
(const uint32_t *)&_binary_embed_firmware_bootloader_bin_start;
(const uint32_t
*)&_binary_embed_firmware_bootloaders_bootloader_bin_deflated_start;
const uint32_t len =
(const uint32_t)&_binary_embed_firmware_bootloader_bin_size;
(const uint32_t)&_binary_embed_firmware_bootloaders_bootloader_bin_deflated_size;

struct uzlib_uncomp decomp = {0};
uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0};
uint32_t decomp_out[IMAGE_HEADER_SIZE / sizeof(uint32_t)] = {0};

uzlib_prepare(&decomp, decomp_window, data, len, decomp_out,
sizeof(decomp_out));

ensure((uzlib_uncompress(&decomp) == TINF_OK) ? sectrue : secfalse,
"Bootloader header decompression failed");

const image_header *new_bld_hdr = read_image_header(
(uint8_t *)data, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE);
(uint8_t *)decomp_out, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE);

ensure(new_bld_hdr == (const image_header *)data ? sectrue : secfalse,
ensure(new_bld_hdr == (const image_header *)decomp_out ? sectrue : secfalse,
"Invalid embedded bootloader");

ensure(check_image_model(new_bld_hdr), "Incompatible embedded bootloader");
Expand Down Expand Up @@ -177,16 +212,32 @@ void check_and_replace_bootloader(void) {

ensure(flash_area_erase(&BOOTLOADER_AREA, NULL), NULL);
ensure(flash_unlock_write(), NULL);
for (int i = 0; i < len / sizeof(uint32_t); i++) {
ensure(
flash_area_write_word(&BOOTLOADER_AREA, i * sizeof(uint32_t), data[i]),
NULL);
}
for (int i = len / sizeof(uint32_t); i < 128 * 1024 / sizeof(uint32_t); i++) {
ensure(flash_area_write_word(&BOOTLOADER_AREA, i * sizeof(uint32_t),
0x00000000),
NULL);

uint32_t offset = 0;

do {
uint32_t *p = decomp_out;
uint32_t last_whole_word_addr = (((uint32_t)decomp.dest) & ~3);
while ((uint32_t)p < last_whole_word_addr) {
ensure(flash_area_write_word(&BOOTLOADER_AREA, offset, *p++), NULL);
offset += sizeof(uint32_t);
}
if ((uint8_t *)p < decomp.dest) {
// last few bytes in case of unaligned data
uint32_t d = 0;
memcpy(&d, p, (uint32_t)decomp.dest - (uint32_t)p);
ensure(flash_area_write_word(&BOOTLOADER_AREA, offset, d), NULL);
offset += sizeof(uint32_t);
}
decomp.dest = (uint8_t *)decomp_out;
} while (uzlib_uncompress(&decomp) >= 0);

// fill the rest of the bootloader area with 0x00
while (offset < bl_len) {
ensure(flash_area_write_word(&BOOTLOADER_AREA, offset, 0x00000000), NULL);
offset += sizeof(uint32_t);
}

ensure(flash_lock_write(), NULL);
#endif
}
49 changes: 49 additions & 0 deletions core/site_scons/tools.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import subprocess
import zlib
from pathlib import Path

from boards import (
Expand Down Expand Up @@ -120,3 +121,51 @@ def get_defs_for_cmake(defs: list[str | tuple[str, str]]) -> list[str]:
else:
result.append(d)
return result


def _compress(data: bytes) -> bytes:
z = zlib.compressobj(level=9, wbits=-10)
return z.compress(data) + z.flush()


def embed_binary(obj_program, env, section, target_, file):
_in = f"embedded_{section}.bin.deflated"

def redefine_sym(name):
src = (
"_binary_build_firmware_"
+ _in.replace("/", "_").replace(".", "_")
+ "_"
+ name
)
dest = (
"_binary_"
+ target_.replace("/", "_").replace(".o", "_bin_deflated")
+ "_"
+ name
)
return f" --redefine-sym {src}={dest}"

def compress_action(target, source, env):
srcf = Path(str(source[0]))
dstf = Path(str(target[0]))
compressed = _compress(srcf.read_bytes())
dstf.write_bytes(compressed)
return 0

compress = env.Command(target=_in, source=file, action=compress_action)

obj_program.extend(
env.Command(
target=target_,
source=_in,
action="$OBJCOPY -I binary -O elf32-littlearm -B arm"
f" --rename-section .data=.{section}"
+ redefine_sym("start")
+ redefine_sym("end")
+ redefine_sym("size")
+ " $SOURCE $TARGET",
)
)

env.Depends(obj_program, compress)
12 changes: 4 additions & 8 deletions tools/check-bitcoin-only
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@ RETURN=0
EXCEPTIONS=()
EXCEPTIONS+=( "decred" ) # "decred" figures in field names used by the bitcoin app
EXCEPTIONS+=( "omni" ) # OMNI is part of the bitcoin app
# BIP39 or SLIP39 words that have "dash", "nem", or "flo" in them
EXCEPTIONS+=( "cinema" "dash" "enemy" "float" "flock" "flower" "floor" "floral" )
EXCEPTIONS+=( "mnemonic" ) # has NEM in it
EXCEPTIONS+=( "workflow" "overflow" ) # has Flo in it
EXCEPTIONS+=( "SyntaxError" ) # has Axe in it
EXCEPTIONS+=( "DKDNEM" ) # has NEM in it, some sort of weird coincidence
# BIP39 or SLIP39 words that have "dash" in them
EXCEPTIONS+=( "dash" )
EXCEPTIONS+=( "confirm_ethereum_tx" ) # is model-specific, so is in layout/__init__.py instead of ethereum/layout.py

GREP_ARGS=()
for exception in "${EXCEPTIONS[@]}"; do
GREP_ARGS+=(-e $exception)
done

# dump all coins except the first 3 (Bitcoin, Testnet, Regtest)
ALTCOINS=$(./common/tools/cointool.py dump -l -p -t -d T1B1 -d T2T1 -d T2B1 | grep '"name"' | cut -d '"' -f 4 | tail -n +4)
# dump all coins except the first 3 (Bitcoin, Testnet, Regtest), exclude names with less than 4 characters
ALTCOINS=$(./common/tools/cointool.py dump -l -p -t -d T1B1 -d T2T1 -d T2B1 | grep '"name"' | cut -d '"' -f 4 | tail -n +4 | awk 'length($0)>3')
# split on newlines only
OLDIFS=$IFS
IFS="
Expand Down
Loading