mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 17:38:39 +00:00
bootloader: allow stage 1 to rewrite whole flash
This commit is contained in:
parent
d8efa32091
commit
89ec08eec0
@ -6,15 +6,24 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
|
|
||||||
#define STAGE2_SECTOR 4
|
|
||||||
#define STAGE2_START 0x08010000
|
#define STAGE2_START 0x08010000
|
||||||
#define STAGE2_SIZE (64 * 1024)
|
|
||||||
|
|
||||||
#define BOOTLOADER_PRINT(X) display_print(X, -1)
|
#define BOOTLOADER_PRINT(X) display_print(X, -1)
|
||||||
#define BOOTLOADER_PRINTLN(X) display_print(X "\n", -1)
|
#define BOOTLOADER_PRINTLN(X) display_print(X "\n", -1)
|
||||||
|
|
||||||
void SystemClock_Config(void);
|
void SystemClock_Config(void);
|
||||||
|
|
||||||
|
void halt(void)
|
||||||
|
{
|
||||||
|
BOOTLOADER_PRINTLN("HALT!");
|
||||||
|
for (;;) {
|
||||||
|
display_backlight(255);
|
||||||
|
HAL_Delay(950);
|
||||||
|
display_backlight(0);
|
||||||
|
HAL_Delay(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void periph_init(void)
|
void periph_init(void)
|
||||||
{
|
{
|
||||||
HAL_Init();
|
HAL_Init();
|
||||||
@ -47,7 +56,7 @@ bool check_sdcard(void)
|
|||||||
sdcard_power_on();
|
sdcard_power_on();
|
||||||
|
|
||||||
uint64_t cap = sdcard_get_capacity_in_bytes();
|
uint64_t cap = sdcard_get_capacity_in_bytes();
|
||||||
if (cap < STAGE2_SIZE) {
|
if (cap < 1024 * 1024) {
|
||||||
BOOTLOADER_PRINTLN("SD card too small");
|
BOOTLOADER_PRINTLN("SD card too small");
|
||||||
sdcard_power_off();
|
sdcard_power_off();
|
||||||
return false;
|
return false;
|
||||||
@ -59,7 +68,8 @@ bool check_sdcard(void)
|
|||||||
|
|
||||||
sdcard_power_off();
|
sdcard_power_off();
|
||||||
|
|
||||||
if (check_header(buf)) {
|
uint32_t codelen;
|
||||||
|
if (parse_header(buf, &codelen)) {
|
||||||
BOOTLOADER_PRINTLN("SD card header is valid");
|
BOOTLOADER_PRINTLN("SD card header is valid");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -68,55 +78,63 @@ bool check_sdcard(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_sdcard(void)
|
bool copy_sdcard(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
BOOTLOADER_PRINTLN("erasing old stage 2");
|
BOOTLOADER_PRINT("erasing flash ");
|
||||||
|
|
||||||
// erase STAGE2_SECTOR
|
// erase flash (except stage 1)
|
||||||
HAL_FLASH_Unlock();
|
HAL_FLASH_Unlock();
|
||||||
FLASH_EraseInitTypeDef EraseInitStruct;
|
FLASH_EraseInitTypeDef EraseInitStruct;
|
||||||
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
|
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
|
||||||
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
|
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
|
||||||
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
|
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
|
||||||
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
|
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
|
||||||
EraseInitStruct.Sector = STAGE2_SECTOR;
|
|
||||||
EraseInitStruct.NbSectors = 1;
|
EraseInitStruct.NbSectors = 1;
|
||||||
uint32_t SectorError = 0;
|
uint32_t SectorError = 0;
|
||||||
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
|
for (int i = 3; i <= 11; i++) { // TODO: change start to 2
|
||||||
HAL_FLASH_Lock();
|
EraseInitStruct.Sector = i;
|
||||||
return;
|
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
|
||||||
|
HAL_FLASH_Lock();
|
||||||
|
BOOTLOADER_PRINTLN(" failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BOOTLOADER_PRINT(".");
|
||||||
}
|
}
|
||||||
|
BOOTLOADER_PRINTLN(" done");
|
||||||
|
|
||||||
BOOTLOADER_PRINTLN("copying new stage 2 from SD card");
|
BOOTLOADER_PRINTLN("copying new stage 2 from SD card");
|
||||||
|
|
||||||
|
sdcard_power_on();
|
||||||
|
|
||||||
// copy stage 2 from SD card to Flash
|
// copy stage 2 from SD card to Flash
|
||||||
uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
|
uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
|
||||||
|
sdcard_read_blocks((uint8_t *)buf, 0, 1);
|
||||||
|
|
||||||
sdcard_power_on();
|
uint32_t codelen;
|
||||||
for (int i = 0; i < STAGE2_SIZE / SDCARD_BLOCK_SIZE; i++) {
|
if (!parse_header((uint8_t *)buf, &codelen)) {
|
||||||
|
BOOTLOADER_PRINTLN("wrong header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < codelen / SDCARD_BLOCK_SIZE; i++) {
|
||||||
sdcard_read_blocks((uint8_t *)buf, i, 1);
|
sdcard_read_blocks((uint8_t *)buf, i, 1);
|
||||||
for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) {
|
for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) {
|
||||||
if (HAL_FLASH_Program(TYPEPROGRAM_WORD, STAGE2_START + i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]) != HAL_OK) {
|
if (HAL_FLASH_Program(TYPEPROGRAM_WORD, STAGE2_START + i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]) != HAL_OK) {
|
||||||
break;
|
BOOTLOADER_PRINTLN("copy failed");
|
||||||
|
sdcard_power_off();
|
||||||
|
HAL_FLASH_Lock();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sdcard_power_off();
|
|
||||||
|
|
||||||
|
sdcard_power_off();
|
||||||
HAL_FLASH_Lock();
|
HAL_FLASH_Lock();
|
||||||
|
|
||||||
BOOTLOADER_PRINTLN("done");
|
BOOTLOADER_PRINTLN("done");
|
||||||
}
|
|
||||||
|
|
||||||
void halt(void)
|
return true;
|
||||||
{
|
|
||||||
for (;;) {
|
|
||||||
display_backlight(255);
|
|
||||||
HAL_Delay(950);
|
|
||||||
display_backlight(0);
|
|
||||||
HAL_Delay(50);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
@ -129,11 +147,14 @@ int main(void)
|
|||||||
BOOTLOADER_PRINTLN("starting stage 1");
|
BOOTLOADER_PRINTLN("starting stage 1");
|
||||||
|
|
||||||
if (check_sdcard()) {
|
if (check_sdcard()) {
|
||||||
copy_sdcard();
|
if (!copy_sdcard()) {
|
||||||
|
halt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOTLOADER_PRINTLN("checking stage 2");
|
BOOTLOADER_PRINTLN("checking stage 2");
|
||||||
if (check_header((const uint8_t *)STAGE2_START)) {
|
uint32_t codelen;
|
||||||
|
if (parse_header((const uint8_t *)STAGE2_START, &codelen)) {
|
||||||
BOOTLOADER_PRINTLN("valid stage 2 header");
|
BOOTLOADER_PRINTLN("valid stage 2 header");
|
||||||
if (check_signature()) {
|
if (check_signature()) {
|
||||||
BOOTLOADER_PRINTLN("valid stage 2 signature");
|
BOOTLOADER_PRINTLN("valid stage 2 signature");
|
||||||
@ -147,7 +168,6 @@ int main(void)
|
|||||||
BOOTLOADER_PRINTLN("invalid stage 2 header");
|
BOOTLOADER_PRINTLN("invalid stage 2 header");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOTLOADER_PRINTLN("HALT!");
|
|
||||||
halt();
|
halt();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -17,7 +17,7 @@ bool ed25519_verify(const uint8_t *msg, uint32_t msglen, const uint8_t *pubkey,
|
|||||||
return (0 == ed25519_sign_open(msg, msglen, *(const ed25519_public_key *)pubkey, *(const ed25519_signature *)signature));
|
return (0 == ed25519_sign_open(msg, msglen, *(const ed25519_public_key *)pubkey, *(const ed25519_signature *)signature));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_header(const uint8_t *data)
|
bool parse_header(const uint8_t *data, uint32_t *codelen)
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
memcpy(&magic, data, 4);
|
memcpy(&magic, data, 4);
|
||||||
@ -31,9 +31,11 @@ bool check_header(const uint8_t *data)
|
|||||||
memcpy(&expiry, data + 8, 4);
|
memcpy(&expiry, data + 8, 4);
|
||||||
if (expiry != 0) return false;
|
if (expiry != 0) return false;
|
||||||
|
|
||||||
uint32_t codelen;
|
memcpy(codelen, data + 12, 4);
|
||||||
memcpy(&codelen, data + 12, 4);
|
// stage 2 (+header) must fit into sectors 4...11 - see docs/memory.md for more info
|
||||||
if (codelen != 64 * 1024 - 256) return false;
|
if (*codelen + hdrlen < 4 * 1024) return false;
|
||||||
|
if (*codelen + hdrlen > 64 * 1024 + 7 * 128 * 1024) return false;
|
||||||
|
if ((*codelen + hdrlen) % 512 != 0) return false;
|
||||||
|
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
memcpy(&version, data + 16, 4);
|
memcpy(&version, data + 16, 4);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
bool check_header(const uint8_t *data);
|
bool parse_header(const uint8_t *data, uint32_t *codelen);
|
||||||
|
|
||||||
bool check_signature(void);
|
bool check_signature(void);
|
||||||
|
|
||||||
|
BIN
tools/bootloader.bin
Normal file
BIN
tools/bootloader.bin
Normal file
Binary file not shown.
@ -42,10 +42,12 @@ class BootloaderImage:
|
|||||||
self.reserved, self.sigidx, self.sig = header
|
self.reserved, self.sigidx, self.sig = header
|
||||||
assert self.magic == b'TRZB'
|
assert self.magic == b'TRZB'
|
||||||
assert self.hdrlen == 256
|
assert self.hdrlen == 256
|
||||||
assert self.codelen == 64*1024 - 256
|
assert self.codelen + self.hdrlen >= 4 * 1024
|
||||||
|
assert self.codelen + self.hdrlen <= 64 * 1024 + 7 * 128 * 1024
|
||||||
|
assert (self.codelen + self.hdrlen) % 512 == 0
|
||||||
assert self.reserved == 171 * b'\x00'
|
assert self.reserved == 171 * b'\x00'
|
||||||
self.sigidx = bitmap_to_tuple(self.sigidx)
|
self.sigidx = bitmap_to_tuple(self.sigidx)
|
||||||
self.code = data[256:]
|
self.code = data[self.hdrlen:]
|
||||||
assert len(self.code) == self.codelen
|
assert len(self.code) == self.codelen
|
||||||
|
|
||||||
def print(self):
|
def print(self):
|
||||||
@ -68,11 +70,13 @@ class BootloaderImage:
|
|||||||
header += struct.pack('<B64s', sigidx, self.sig)
|
header += struct.pack('<B64s', sigidx, self.sig)
|
||||||
else:
|
else:
|
||||||
header += 65 * b'\x00'
|
header += 65 * b'\x00'
|
||||||
|
assert len(header) == self.hdrlen
|
||||||
return header
|
return header
|
||||||
|
|
||||||
def sign(self):
|
def sign(self):
|
||||||
header = self.header(sig=False)
|
header = self.header(sig=False)
|
||||||
data = header + self.code
|
data = header + self.code
|
||||||
|
assert len(data) == self.hdrlen + self.codelen
|
||||||
self.sigidx, self.sig = get_sig(data)
|
self.sigidx, self.sig = get_sig(data)
|
||||||
|
|
||||||
def write(self, filename):
|
def write(self, filename):
|
||||||
@ -141,6 +145,7 @@ class VendorHeader:
|
|||||||
header += struct.pack('<B64s', sigidx, self.sig)
|
header += struct.pack('<B64s', sigidx, self.sig)
|
||||||
else:
|
else:
|
||||||
header += 65 * b'\x00'
|
header += 65 * b'\x00'
|
||||||
|
assert len(header) == self.hdrlen
|
||||||
return header
|
return header
|
||||||
|
|
||||||
def sign(self):
|
def sign(self):
|
||||||
@ -164,7 +169,7 @@ class FirmwareImage:
|
|||||||
assert self.codelen % 4 == 0
|
assert self.codelen % 4 == 0
|
||||||
assert self.reserved == 171 * b'\x00'
|
assert self.reserved == 171 * b'\x00'
|
||||||
self.sigidx = bitmap_to_tuple(self.sigidx)
|
self.sigidx = bitmap_to_tuple(self.sigidx)
|
||||||
self.code = data[256:]
|
self.code = data[self.hdrlen:]
|
||||||
assert len(self.code) == self.codelen
|
assert len(self.code) == self.codelen
|
||||||
|
|
||||||
def print(self):
|
def print(self):
|
||||||
@ -187,11 +192,13 @@ class FirmwareImage:
|
|||||||
header += struct.pack('<B64s', sigidx, self.sig)
|
header += struct.pack('<B64s', sigidx, self.sig)
|
||||||
else:
|
else:
|
||||||
header += 65 * b'\x00'
|
header += 65 * b'\x00'
|
||||||
|
assert len(header) == self.hdrlen
|
||||||
return header
|
return header
|
||||||
|
|
||||||
def sign(self):
|
def sign(self):
|
||||||
header = self.header(sig=False)
|
header = self.header(sig=False)
|
||||||
data = header + self.code
|
data = header + self.code
|
||||||
|
assert len(data) == self.hdrlen + self.codelen
|
||||||
self.sigidx, self.sig = get_sig(data)
|
self.sigidx, self.sig = get_sig(data)
|
||||||
|
|
||||||
def write(self, filename):
|
def write(self, filename):
|
||||||
|
Loading…
Reference in New Issue
Block a user