firmware/stm32/mk4-bootloader/main.c
2024-01-30 13:56:27 -05:00

283 lines
6.4 KiB
C

/*
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
*
* main.c
*
* Setup code. See dispatch.c for mainline code.
*
*/
#include "basics.h"
#include "main.h"
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include "misc.h"
#include "console.h"
#include "faster_sha256.h"
#include "aes.h"
#include "version.h"
#include "clocks.h"
#include "oled.h"
#include "delay.h"
#include "rng.h"
#include "gpio.h"
#include "ae.h"
#include "se2.h"
#include "pins.h"
#include "verify.h"
#include "storage.h"
#include "psram.h"
#include "sdcard.h"
#include "dispatch.h"
#include "constant_time.h"
#include SCREENS_H
#include "stm32l4xx_hal.h"
// wipe_all_sram()
//
void
wipe_all_sram(void)
{
const uint32_t noise = 0xdeadbeef;
// wipe all of SRAM (except our own memory)
STATIC_ASSERT((SRAM3_BASE + SRAM3_SIZE) - BL_SRAM_BASE == 8192);
memset4((void *)SRAM1_BASE, noise, SRAM1_SIZE_MAX);
memset4((void *)SRAM2_BASE, noise, SRAM2_SIZE);
memset4((void *)SRAM3_BASE, noise, SRAM3_SIZE - (BL_SRAM_BASE - SRAM3_BASE));
}
// system_startup()
//
// Called only on system boot.
//
void
system_startup(void)
{
// configure critical stuff
system_init0();
clocks_setup();
rng_setup(); // needs to be super early
rng_delay();
#if RELEASE
// security check: should we be in protected mode? Was there some UV-C bitrot perhaps?
if(!check_all_ones(rom_secrets->bag_number, sizeof(rom_secrets->bag_number))
&& !flash_is_security_level2()
) {
// yikes. recovery: do lockdown... we should be/(thought we were) locked already
flash_lockdown_hard(OB_RDP_LEVEL_2);
// CONCERN: this code has only been called once, and it left the unit with RDP=0xff(1)
// and not functional. See issue #1268.
}
#else
# warning "Built for debug."
#endif
// config pins
gpio_setup();
// debug output and banner
console_setup();
puts2(BOOT_BANNER);
puts(version_string);
uint32_t reset_reason = RCC->CSR;
if(reset_reason & RCC_CSR_FWRSTF) {
puts(">FIREWALLED<");
}
SET_BIT(RCC->CSR, RCC_CSR_RMVF);
pin_setup0();
rng_delay();
#ifndef RELEASE
sha256_selftest();
aes_selftest();
rng_delay();
#endif
#ifdef FOR_Q1_ONLY
extern void lcd_full_setup(void);
// clear and setup LCD display - includes long config process
lcd_full_setup();
#else
// clear and OLED display
oled_setup();
#endif
// Workaround to get into DFU from micropython
// LATER: none of this is useful with RDP=2, but okay in the office/factory
if(memcmp(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)) == 0) {
dfu_flag->magic[0] = 0;
// still see a flash here, but that's proof it works.
oled_show(dfu_flag->screen);
enter_dfu();
// NOT-REACHED
}
rng_delay();
// Show main boot-up screen
oled_show_progress(screen_verify, 0);
// wipe all of SRAM (except our own memory, which was already wiped)
wipe_all_sram();
// secure elements setup
//puts2("SE1 setup: ");
ae_setup();
ae_set_gpio(0); // turn light red
//puts("done");
//puts2("SE2 setup: ");
se2_setup();
se2_probe();
//puts("done");
// protect our flash, and/or check it's protected
// - and pick pairing secret if we don't already have one
// - may also do one-time setup of the secure elements
// - note: ae_setup must already be called, since it can talk to that
flash_setup();
// setup Quad SPI unit and PSRAM chip
psram_setup();
// broken pairing secret w/ SE1 means we've been fast-bricked
if(ae_pair_unlock() != 0) {
oled_show(screen_brick);
puts("pair-bricked");
LOCKUP_FOREVER();
}
// Check firmware has valid checksum and signature.
puts2("Verify: ");
bool main_ok = verify_firmware();
if(main_ok) {
// load a blank screen, so that if the firmware crashes, we are showing
// something reasonable and not misleading.
oled_show(screen_blankish);
return;
}
// Try to recover, using an image hanging around in PSRAM
// .. will reboot if it works; only helps w/ reset pulses, not power downs.
psram_recover_firmware();
if(!flash_is_security_level2()) {
// in factory, DFU is prefered; can't work if flash locked tho
enter_dfu();
}
// use SDCard to recover
while(1) sdcard_recovery();
}
// fatal_error(const char *msg)
//
void __attribute__((noreturn))
fatal_error(const char *msgvoid)
{
oled_setup();
oled_show(screen_fatal);
#ifndef RELEASE
puts2("\r\n\nAssert fail: ");
puts(msgvoid);
BREAKPOINT;
#endif
// Maybe should do a reset after a delay, like with
// the watchdog timer or something.
LOCKUP_FOREVER();
}
// fatal_mitm()
//
void __attribute__((noreturn))
fatal_mitm(void)
{
oled_setup();
oled_show(screen_mitm);
#ifdef RELEASE
wipe_all_sram();
#endif
LOCKUP_FOREVER();
}
// enter_dfu()
//
void __attribute__((noreturn))
enter_dfu(void)
{
puts("enter_dfu()");
// clear the green light, if set
ae_setup();
ae_set_gpio(0);
// Reset huge parts of the chip
__HAL_RCC_APB1_FORCE_RESET();
__HAL_RCC_APB1_RELEASE_RESET();
__HAL_RCC_APB2_FORCE_RESET();
__HAL_RCC_APB2_RELEASE_RESET();
__HAL_RCC_AHB1_FORCE_RESET();
__HAL_RCC_AHB1_RELEASE_RESET();
#if 0
// But not this; it borks things.
__HAL_RCC_AHB2_FORCE_RESET();
__HAL_RCC_AHB2_RELEASE_RESET();
#endif
__HAL_RCC_AHB3_FORCE_RESET();
__HAL_RCC_AHB3_RELEASE_RESET();
__HAL_FIREWALL_PREARM_ENABLE();
// Wipe all of memory SRAM, just in case
// there is some way to trick us into DFU
// after sensitive content in place.
wipe_all_sram();
if(flash_is_security_level2()) {
// cannot do DFU in RDP=2, so just die. Helps to preserve screen
LOCKUP_FOREVER();
}
// Reset clocks.
HAL_RCC_DeInit();
// move system ROM into 0x0
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
// need this here?!
asm("nop; nop; nop; nop;");
// simulate a reset vector
__ASM volatile ("movs r0, #0\n"
"ldr r3, [r0, #0]\n"
"msr msp, r3\n"
"ldr r3, [r0, #4]\n"
"blx r3"
: : : "r0", "r3"); // also SP
// NOT-REACHED.
__builtin_unreachable();
}
// EOF