/* * This file is part of the Trezor project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include "trezor.h" #include #include #include #include #include "bitmaps.h" #include "bl_check.h" #include "layout.h" #include "memory.h" #include "memzero.h" #include "norcow_config.h" #include "oled.h" #include "rng.h" #include "setup.h" #include "supervise.h" #include "timer.h" #include "util.h" // legacy storage magic #define LEGACY_STORAGE_SECTOR 2 static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR' // norcow storage magic static const uint32_t NORCOW_MAGIC = 0x3243524e; // 'NRC2' static const uint8_t norcow_sectors[NORCOW_SECTOR_COUNT] = NORCOW_SECTORS; /** Flash program word operation extracted from libopencm3, * so it can run from RAM */ static void __attribute__((noinline, section(".data#"))) _flash_program_word(uint32_t address, uint32_t data) { // Wait for flash controller to be ready while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY) ; // Set program word width FLASH_CR &= ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT); FLASH_CR |= FLASH_CR_PROGRAM_X32 << FLASH_CR_PROGRAM_SHIFT; // Enable writes to flash FLASH_CR |= FLASH_CR_PG; // Program the word MMIO32(address) = data; // Wait for flash controller to be ready while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY) ; // Disable writes to flash FLASH_CR &= ~FLASH_CR_PG; } static void __attribute__((noinline, section(".data#"))) invalidate_firmware(void) { // Flash unlock FLASH_KEYR = FLASH_KEYR_KEY1; FLASH_KEYR = FLASH_KEYR_KEY2; // Erase the first firmware word // (we don't need full erasure, this speeds up the whole process) _flash_program_word(FLASH_FWHEADER_START, 0); // Flash lock FLASH_CR |= FLASH_CR_LOCK; } void __attribute__((noinline, noreturn, section(".data#"))) reboot_device(void) { __disable_irq(); *STAY_IN_BOOTLOADER_FLAG_ADDR = STAY_IN_BOOTLOADER_FLAG; SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ; while (1) ; } /** Entry point of RAM shim that deletes old FW, storage and reboot */ void __attribute__((noinline, noreturn, section(".data#"))) invalidate_firmware_and_reboot(void) { invalidate_firmware(); reboot_device(); for (;;) ; // never reached, but compiler would generate error } int main(void) { setupApp(); __stack_chk_guard = random32(); // this supports compiler provided // unpredictable stack protection checks if (is_mode_unprivileged()) { layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Cannot update", NULL, NULL, "Unprivileged mode", "Unsigned firmware", NULL); shutdown(); } mpu_config_off(); // needed for flash writable, RAM RWX timer_init(); check_and_replace_bootloader(false); secbool storage_initialized = secfalse; // check legacy storage uint32_t *magic = (uint32_t *)flash_get_address(LEGACY_STORAGE_SECTOR, 0, sizeof(META_MAGIC_V10)); if (*magic == META_MAGIC_V10) { storage_initialized = sectrue; } if (storage_initialized == secfalse) { // check norcow storage for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) { magic = (uint32_t *)flash_get_address(norcow_sectors[i], 0, sizeof(NORCOW_MAGIC)); if (*magic == NORCOW_MAGIC) { storage_initialized = sectrue; break; } } } if (sectrue == storage_initialized) { // Storage probably contains a seed so leave the firmware intact. // Invalidating it would cause the bootloader to wipe the storage before // installing the target firmware. User will need to confirm installation. reboot_device(); } else { // New device. Invalidate the intermediate firmware so that after reboot // the bootloader will install the target firmware without asking for user // confirmation. invalidate_firmware_and_reboot(); } return 0; }