diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 710ab376ff..4df11a6d10 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -206,7 +206,7 @@ env.Replace( 'TREZOR_EMULATOR', CPU_MODEL, 'HW_MODEL=' + MODEL_AS_NUMBER, - 'HW_REVISION=' + ('6' if TREZOR_MODEL in ('R',) else '0'), + 'HW_REVISION=' + ('10' if TREZOR_MODEL in ('R',) else '0'), 'TREZOR_MODEL_'+TREZOR_MODEL, 'TREZOR_BOARD=\\"boards/board-unix.h\\"', 'MCU_TYPE='+CPU_MODEL, diff --git a/core/embed/bootloader/.changelog.d/3122.changed b/core/embed/bootloader/.changelog.d/3122.changed new file mode 100644 index 0000000000..ba6f3d0e89 --- /dev/null +++ b/core/embed/bootloader/.changelog.d/3122.changed @@ -0,0 +1 @@ +No longer erases seed when firmware is corrupted but firmware header is correct and signed. Added firmware corrupted info to bootloader screen. diff --git a/core/embed/bootloader/bootui.c b/core/embed/bootloader/bootui.c index 4c7e5674aa..90aee5ab20 100644 --- a/core/embed/bootloader/bootui.c +++ b/core/embed/bootloader/bootui.c @@ -192,16 +192,18 @@ void ui_screen_boot_click(void) { void ui_screen_welcome(void) { screen_welcome(); } uint32_t ui_screen_intro(const vendor_header *const vhdr, - const image_header *const hdr) { + const image_header *const hdr, bool fw_ok) { char bld_ver[32]; char ver_str[64]; format_ver("%d.%d.%d", VERSION_UINT32, bld_ver, sizeof(bld_ver)); format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str)); - return screen_intro(bld_ver, vhdr->vstr, vhdr->vstr_len, ver_str); + return screen_intro(bld_ver, vhdr->vstr, vhdr->vstr_len, ver_str, fw_ok); } -uint32_t ui_screen_menu(void) { return screen_menu(); } +uint32_t ui_screen_menu(secbool firmware_present) { + return screen_menu(firmware_present); +} // install UI diff --git a/core/embed/bootloader/bootui.h b/core/embed/bootloader/bootui.h index a73349d018..50df21f8e3 100644 --- a/core/embed/bootloader/bootui.h +++ b/core/embed/bootloader/bootui.h @@ -31,6 +31,7 @@ typedef enum { SCREEN_WIPE_CONFIRM = 2, SCREEN_FINGER_PRINT = 3, SCREEN_WAIT_FOR_HOST = 4, + SCREEN_WELCOME = 5, } screen_t; void ui_screen_boot(const vendor_header* const vhdr, @@ -42,9 +43,9 @@ void ui_click(void); void ui_screen_welcome(void); uint32_t ui_screen_intro(const vendor_header* const vhdr, - const image_header* const hdr); + const image_header* const hdr, bool fw_ok); -uint32_t ui_screen_menu(void); +uint32_t ui_screen_menu(secbool firmware_present); uint32_t ui_screen_install_confirm(const vendor_header* const vhdr, const image_header* const hdr, diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 9772841ccb..2f6bd5682c 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -81,9 +81,9 @@ static const uint8_t * const BOOTLOADER_KEYS[] = { #define USB_IFACE_NUM 0 typedef enum { - CONTINUE = 0, - RETURN = 1, - SHUTDOWN = 2, + SHUTDOWN = 0, + CONTINUE_TO_FIRMWARE = 0xAABBCCDD, + RETURN_TO_MENU = 0x55667788, } usb_result_t; static void usb_init_all(secbool usb21_landing) { @@ -164,7 +164,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, hal_delay(100); usb_stop(); usb_deinit(); - return RETURN; + return RETURN_TO_MENU; } ui_screen_wipe(); r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf); @@ -200,7 +200,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, hal_delay(100); usb_stop(); usb_deinit(); - return RETURN; + return RETURN_TO_MENU; } else if (r == 0) { // last chunk received ui_screen_install_progress_upload(1000); ui_screen_done(4, sectrue); @@ -213,7 +213,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, usb_stop(); usb_deinit(); ui_screen_boot_empty(true); - return CONTINUE; + return CONTINUE_TO_FIRMWARE; } break; case MessageType_MessageType_GetFeatures: @@ -227,7 +227,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, hal_delay(100); usb_stop(); usb_deinit(); - return RETURN; + return RETURN_TO_MENU; } process_msg_UnlockBootloader(USB_IFACE_NUM, msg_size, buf); screen_unlock_bootloader_success(); @@ -315,39 +315,51 @@ int bootloader_main(void) { mpu_config_bootloader(); +#ifdef TREZOR_EMULATOR + // wait a bit so that the empty lock icon is visible + // (on a real device, we are waiting for touch init which takes longer) + hal_delay(400); +#endif + const image_header *hdr = NULL; vendor_header vhdr; + // detect whether the device contains a valid firmware - secbool firmware_present = sectrue; + volatile secbool vhdr_present = secfalse; + volatile secbool vhdr_keys_ok = secfalse; + volatile secbool vhdr_lock_ok = secfalse; + volatile secbool img_hdr_ok = secfalse; + volatile secbool model_ok = secfalse; + volatile secbool header_present = secfalse; + volatile secbool firmware_present = secfalse; - if (sectrue != read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr)) { - firmware_present = secfalse; + vhdr_present = read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr); + + if (sectrue == vhdr_present) { + vhdr_keys_ok = check_vendor_header_keys(&vhdr); } - if (sectrue == firmware_present) { - firmware_present = check_vendor_header_keys(&vhdr); + if (sectrue == vhdr_keys_ok) { + vhdr_lock_ok = check_vendor_header_lock(&vhdr); } - if (sectrue == firmware_present) { - firmware_present = check_vendor_header_lock(&vhdr); - } - - if (sectrue == firmware_present) { + if (sectrue == vhdr_lock_ok) { hdr = read_image_header( (const uint8_t *)(size_t)(FIRMWARE_START + vhdr.hdrlen), FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE); - if (hdr != (const image_header *)(size_t)(FIRMWARE_START + vhdr.hdrlen)) { - firmware_present = secfalse; + if (hdr == (const image_header *)(size_t)(FIRMWARE_START + vhdr.hdrlen)) { + img_hdr_ok = sectrue; } } - if (sectrue == firmware_present) { - firmware_present = check_image_model(hdr); + if (sectrue == img_hdr_ok) { + model_ok = check_image_model(hdr); } - if (sectrue == firmware_present) { - firmware_present = + if (sectrue == model_ok) { + header_present = check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub); } - if (sectrue == firmware_present) { + + if (sectrue == header_present) { firmware_present = check_image_contents( hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, &FIRMWARE_AREA); } @@ -414,54 +426,59 @@ int bootloader_main(void) { } #endif - // start the bootloader if no or broken firmware found ... - if (firmware_present != sectrue) { -#ifdef TREZOR_EMULATOR - // wait a bit so that the empty lock icon is visible - // (on a real device, we are waiting for touch init which takes longer) - hal_delay(400); -#endif - // ignore stay in bootloader - stay_in_bootloader = secfalse; - touched = false; - - ui_set_initial_setup(true); - - // keep the model screen up for a while -#ifndef USE_BACKLIGHT - hal_delay(1500); -#else - // backlight fading takes some time so the explicit delay here is shorter - hal_delay(1000); -#endif - - // show welcome screen - ui_screen_welcome(); - - // erase storage - ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), - NULL); - - // and start the usb loop - if (bootloader_usb_loop(NULL, NULL) != CONTINUE) { - return 1; - } - } - - // ... or if user touched the screen on start + // start the bootloader ... + // ... if user touched the screen on start // ... or we have stay_in_bootloader flag to force it - if (touched || stay_in_bootloader == sectrue) { - ui_set_initial_setup(false); + // ... or there is no valid firmware + if (touched || stay_in_bootloader == sectrue || firmware_present != sectrue) { + screen_t screen; + if (header_present == sectrue) { + ui_set_initial_setup(false); + screen = SCREEN_INTRO; + } else { + screen = SCREEN_WELCOME; - screen_t screen = SCREEN_INTRO; + // erase storage + ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), + NULL); + + ui_set_initial_setup(true); + + // keep the model screen up for a while +#ifndef USE_BACKLIGHT + hal_delay(1500); +#else + // backlight fading takes some time so the explicit delay here is + // shorter + hal_delay(1000); +#endif + } while (true) { - bool continue_to_firmware = false; + secbool continue_to_firmware = secfalse; uint32_t ui_result = 0; switch (screen) { + case SCREEN_WELCOME: + + ui_screen_welcome(); + + // and start the usb loop + switch (bootloader_usb_loop(NULL, NULL)) { + case CONTINUE_TO_FIRMWARE: + continue_to_firmware = sectrue; + break; + case RETURN_TO_MENU: + break; + default: + case SHUTDOWN: + return 1; + break; + } + break; + case SCREEN_INTRO: - ui_result = ui_screen_intro(&vhdr, hdr); + ui_result = ui_screen_intro(&vhdr, hdr, firmware_present); if (ui_result == 1) { screen = SCREEN_MENU; } @@ -470,15 +487,15 @@ int bootloader_main(void) { } break; case SCREEN_MENU: - ui_result = ui_screen_menu(); - if (ui_result == 1) { // exit menu + ui_result = ui_screen_menu(firmware_present); + if (ui_result == 0xAABBCCDD) { // exit menu screen = SCREEN_INTRO; } - if (ui_result == 2) { // reboot + if (ui_result == 0x11223344) { // reboot ui_screen_boot_empty(true); - continue_to_firmware = true; + continue_to_firmware = firmware_present; } - if (ui_result == 3) { // wipe + if (ui_result == 0x55667788) { // wipe screen = SCREEN_WIPE_CONFIRM; } break; @@ -503,10 +520,10 @@ int bootloader_main(void) { case SCREEN_WAIT_FOR_HOST: screen_connect(); switch (bootloader_usb_loop(&vhdr, hdr)) { - case CONTINUE: - continue_to_firmware = true; + case CONTINUE_TO_FIRMWARE: + continue_to_firmware = sectrue; break; - case RETURN: + case RETURN_TO_MENU: screen = SCREEN_INTRO; break; case SHUTDOWN: @@ -520,7 +537,7 @@ int bootloader_main(void) { break; } - if (continue_to_firmware) { + if (sectrue == continue_to_firmware) { break; } } diff --git a/core/embed/rust/rust_ui.h b/core/embed/rust/rust_ui.h index 9dc21fa869..fb79f8de59 100644 --- a/core/embed/rust/rust_ui.h +++ b/core/embed/rust/rust_ui.h @@ -12,8 +12,9 @@ void screen_install_progress(int16_t progress, bool initialize, bool initial_setup); void screen_wipe_progress(int16_t progress, bool initialize); uint32_t screen_intro(const char* bld_version_str, const char* vendor_str, - uint8_t vendor_str_len, const char* version_str); -uint32_t screen_menu(void); + uint8_t vendor_str_len, const char* version_str, + bool fw_ok); +uint32_t screen_menu(secbool firmware_present); void screen_connect(void); void screen_fatal_error_rust(const char* title, const char* msg, const char* footer); diff --git a/core/embed/rust/src/trezorhal/mod.rs b/core/embed/rust/src/trezorhal/mod.rs index 69bfafd7ef..8a55becbb9 100644 --- a/core/embed/rust/src/trezorhal/mod.rs +++ b/core/embed/rust/src/trezorhal/mod.rs @@ -18,6 +18,8 @@ pub mod uzlib; pub mod wordlist; pub mod buffers; +pub mod secbool; + #[cfg(not(feature = "micropython"))] pub mod time; diff --git a/core/embed/rust/src/trezorhal/secbool.rs b/core/embed/rust/src/trezorhal/secbool.rs new file mode 100644 index 0000000000..1ea872dd59 --- /dev/null +++ b/core/embed/rust/src/trezorhal/secbool.rs @@ -0,0 +1,3 @@ +use super::ffi; + +pub use ffi::{secbool, secfalse, sectrue}; diff --git a/core/embed/rust/src/ui/model_tr/bootloader/intro.rs b/core/embed/rust/src/ui/model_tr/bootloader/intro.rs index 3409280071..b7b157904b 100644 --- a/core/embed/rust/src/ui/model_tr/bootloader/intro.rs +++ b/core/embed/rust/src/ui/model_tr/bootloader/intro.rs @@ -1,6 +1,6 @@ use crate::ui::{ component::{Child, Component, Event, EventCtx, Label, Pad}, - geometry::{Alignment2D, Rect}, + geometry::{Alignment, Alignment2D, Rect}, }; use super::{ @@ -32,10 +32,11 @@ pub struct Intro<'a> { title: Child>, buttons: Child>, text: Child>, + warn: Option>>, } impl<'a> Intro<'a> { - pub fn new(title: &'a str, content: &'a str) -> Self { + pub fn new(title: &'a str, content: &'a str, fw_ok: bool) -> Self { Self { bg: Pad::with_background(BLD_BG).with_clear(), title: Child::new(Label::centered(title, TEXT_NORMAL).vertically_centered()), @@ -44,6 +45,10 @@ impl<'a> Intro<'a> { RIGHT_BUTTON_TEXT, ))), text: Child::new(Label::left_aligned(content, TEXT_NORMAL).vertically_centered()), + warn: (!fw_ok).then_some(Child::new( + Label::new("FIRMWARE CORRUPTED", Alignment::Start, TEXT_NORMAL) + .vertically_centered(), + )), } } } @@ -61,6 +66,15 @@ impl<'a> Component for Intro<'a> { self.title.place(title_area); self.buttons.place(buttons_area); self.text.place(text_area); + + if self.warn.is_some() { + let (warn_area, text_area) = text_area.split_top(10); + self.warn.place(warn_area); + self.text.place(text_area); + } else { + self.text.place(text_area); + } + bounds } @@ -82,6 +96,7 @@ impl<'a> Component for Intro<'a> { let area = self.bg.area; ICON_WARN_TITLE.draw(area.top_left(), Alignment2D::TOP_LEFT, BLD_FG, BLD_BG); ICON_WARN_TITLE.draw(area.top_right(), Alignment2D::TOP_RIGHT, BLD_FG, BLD_BG); + self.warn.paint(); self.text.paint(); self.buttons.paint(); } @@ -89,6 +104,7 @@ impl<'a> Component for Intro<'a> { #[cfg(feature = "ui_bounds")] fn bounds(&self, sink: &mut dyn FnMut(Rect)) { self.title.bounds(sink); + self.warn.bounds(sink); self.text.bounds(sink); self.buttons.bounds(sink); } diff --git a/core/embed/rust/src/ui/model_tr/bootloader/menu.rs b/core/embed/rust/src/ui/model_tr/bootloader/menu.rs index 843018cd58..a8d61b6b0b 100644 --- a/core/embed/rust/src/ui/model_tr/bootloader/menu.rs +++ b/core/embed/rust/src/ui/model_tr/bootloader/menu.rs @@ -1,11 +1,14 @@ #[cfg(feature = "ui_debug")] use crate::trace::{Trace, Tracer}; -use crate::ui::{ - component::{Child, Component, Event, EventCtx, Pad}, - constant::screen, - display, - display::{Font, Icon}, - geometry::{Alignment2D, Offset, Point, Rect}, +use crate::{ + trezorhal::secbool::{secbool, sectrue}, + ui::{ + component::{Child, Component, Event, EventCtx, Pad}, + constant::screen, + display, + display::{Font, Icon}, + geometry::{Alignment2D, Offset, Point, Rect}, + }, }; use super::{ @@ -17,9 +20,9 @@ use super::{ #[repr(u32)] #[derive(Copy, Clone)] pub enum MenuMsg { - Close = 1, - Reboot = 2, - FactoryReset = 3, + Close = 0xAABBCCDD, + Reboot = 0x11223344, + FactoryReset = 0x55667788, } impl ReturnToC for MenuMsg { fn return_to_c(self) -> u32 { @@ -74,17 +77,19 @@ impl Trace for MenuChoice { } } -pub struct MenuChoiceFactory; +pub struct MenuChoiceFactory { + firmware_present: secbool, +} impl MenuChoiceFactory { const CHOICES: [(&'static str, &'static str, Icon); CHOICE_LENGTH] = [ ("Factory", "reset", ICON_TRASH), - ("Reboot", "Trezor", ICON_REDO), ("Exit", "menu", ICON_EXIT), + ("Reboot", "Trezor", ICON_REDO), ]; - pub fn new() -> Self { - Self {} + pub fn new(firmware_present: secbool) -> Self { + Self { firmware_present } } } @@ -93,7 +98,11 @@ impl ChoiceFactory<&'static str> for MenuChoiceFactory { type Item = MenuChoice; fn count(&self) -> usize { - CHOICE_LENGTH + if self.firmware_present == sectrue { + CHOICE_LENGTH + } else { + CHOICE_LENGTH - 1 + } } fn get(&self, choice_index: usize) -> (Self::Item, Self::Action) { @@ -104,8 +113,8 @@ impl ChoiceFactory<&'static str> for MenuChoiceFactory { ); let action = match choice_index { 0 => MenuMsg::FactoryReset, - 1 => MenuMsg::Reboot, - 2 => MenuMsg::Close, + 1 => MenuMsg::Close, + 2 if self.firmware_present == sectrue => MenuMsg::Reboot, _ => unreachable!(), }; (choice_item, action) @@ -118,8 +127,8 @@ pub struct Menu { } impl Menu { - pub fn new() -> Self { - let choices = MenuChoiceFactory::new(); + pub fn new(firmware_present: secbool) -> Self { + let choices = MenuChoiceFactory::new(firmware_present); Self { pad: Pad::with_background(BLD_BG).with_clear(), choice_page: Child::new( diff --git a/core/embed/rust/src/ui/model_tr/bootloader/mod.rs b/core/embed/rust/src/ui/model_tr/bootloader/mod.rs index 8f10f155a0..aa92083483 100644 --- a/core/embed/rust/src/ui/model_tr/bootloader/mod.rs +++ b/core/embed/rust/src/ui/model_tr/bootloader/mod.rs @@ -21,11 +21,14 @@ mod menu; mod theme; mod welcome; -use crate::ui::{ - constant, - constant::HEIGHT, - geometry::Point, - model_tr::theme::{ICON_ARM_LEFT, ICON_ARM_RIGHT, WHITE}, +use crate::{ + trezorhal::secbool::secbool, + ui::{ + constant, + constant::HEIGHT, + geometry::Point, + model_tr::theme::{ICON_ARM_LEFT, ICON_ARM_RIGHT, WHITE}, + }, }; use confirm::Confirm; use connect::Connect; @@ -192,8 +195,8 @@ extern "C" fn screen_unlock_bootloader_success() { } #[no_mangle] -extern "C" fn screen_menu(_bld_version: *const cty::c_char) -> u32 { - run(&mut Menu::new()) +extern "C" fn screen_menu(firmware_present: secbool) -> u32 { + run(&mut Menu::new(firmware_present)) } #[no_mangle] @@ -202,6 +205,7 @@ extern "C" fn screen_intro( vendor_str: *const cty::c_char, vendor_str_len: u8, version: *const cty::c_char, + fw_ok: bool, ) -> u32 { let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); let version = unwrap!(unsafe { from_c_str(version) }); @@ -217,7 +221,7 @@ extern "C" fn screen_intro( unwrap!(version_str.push_str("\nby ")); unwrap!(version_str.push_str(vendor)); - let mut frame = Intro::new(title_str.as_str(), version_str.as_str()); + let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok); run(&mut frame) } diff --git a/core/embed/rust/src/ui/model_tt/bootloader/intro.rs b/core/embed/rust/src/ui/model_tt/bootloader/intro.rs index 851a3bfde4..81e99f2dd0 100644 --- a/core/embed/rust/src/ui/model_tt/bootloader/intro.rs +++ b/core/embed/rust/src/ui/model_tt/bootloader/intro.rs @@ -2,11 +2,11 @@ use crate::ui::{ component::{Child, Component, Event, EventCtx, Label, Pad}, constant::screen, display::Icon, - geometry::{Insets, Point, Rect}, + geometry::{Alignment, Insets, Point, Rect}, model_tt::{ bootloader::theme::{ button_bld, button_bld_menu, BLD_BG, BUTTON_AREA_START, BUTTON_HEIGHT, CONTENT_PADDING, - CORNER_BUTTON_AREA, MENU32, TEXT_NORMAL, TEXT_TITLE, TITLE_AREA, + CORNER_BUTTON_AREA, MENU32, TEXT_NORMAL, TEXT_TITLE, TEXT_WARNING, TITLE_AREA, }, component::{Button, ButtonMsg::Clicked}, constant::WIDTH, @@ -26,10 +26,11 @@ pub struct Intro<'a> { menu: Child>, host: Child>, text: Child>, + warn: Option>>, } impl<'a> Intro<'a> { - pub fn new(title: &'a str, content: &'a str) -> Self { + pub fn new(title: &'a str, content: &'a str, fw_ok: bool) -> Self { Self { bg: Pad::with_background(BLD_BG).with_clear(), title: Child::new(Label::left_aligned(title, TEXT_TITLE).vertically_centered()), @@ -40,6 +41,10 @@ impl<'a> Intro<'a> { ), host: Child::new(Button::with_text("INSTALL FIRMWARE").styled(button_bld())), text: Child::new(Label::left_aligned(content, TEXT_NORMAL).vertically_centered()), + warn: (!fw_ok).then_some(Child::new( + Label::new("FIRMWARE CORRUPTED", Alignment::Start, TEXT_WARNING) + .vertically_centered(), + )), } } } @@ -56,10 +61,25 @@ impl<'a> Component for Intro<'a> { Point::new(CONTENT_PADDING, BUTTON_AREA_START), Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START + BUTTON_HEIGHT), )); - self.text.place(Rect::new( - Point::new(CONTENT_PADDING, TITLE_AREA.y1 + CONTENT_PADDING), - Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START - CONTENT_PADDING), - )); + if self.warn.is_some() { + self.warn.place(Rect::new( + Point::new(CONTENT_PADDING, TITLE_AREA.y1 + CONTENT_PADDING), + Point::new( + WIDTH - CONTENT_PADDING, + TITLE_AREA.y1 + CONTENT_PADDING + 30, + ), + )); + self.text.place(Rect::new( + Point::new(CONTENT_PADDING, TITLE_AREA.y1 + CONTENT_PADDING + 30), + Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START - CONTENT_PADDING), + )); + } else { + self.text.place(Rect::new( + Point::new(CONTENT_PADDING, TITLE_AREA.y1 + CONTENT_PADDING), + Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START - CONTENT_PADDING), + )); + } + bounds } @@ -77,6 +97,7 @@ impl<'a> Component for Intro<'a> { self.bg.paint(); self.title.paint(); self.text.paint(); + self.warn.paint(); self.host.paint(); self.menu.paint(); } diff --git a/core/embed/rust/src/ui/model_tt/bootloader/menu.rs b/core/embed/rust/src/ui/model_tt/bootloader/menu.rs index 4b0ca8e337..3c1a441610 100644 --- a/core/embed/rust/src/ui/model_tt/bootloader/menu.rs +++ b/core/embed/rust/src/ui/model_tt/bootloader/menu.rs @@ -1,15 +1,18 @@ -use crate::ui::{ - component::{Child, Component, Event, EventCtx, Label, Pad}, - constant::{screen, WIDTH}, - display::Icon, - geometry::{Insets, Point, Rect}, - model_tt::{ - bootloader::theme::{ - button_bld, button_bld_menu, BLD_BG, BUTTON_HEIGHT, CONTENT_PADDING, - CORNER_BUTTON_AREA, CORNER_BUTTON_TOUCH_EXPANSION, FIRE24, REFRESH24, TEXT_TITLE, - TITLE_AREA, X32, +use crate::{ + trezorhal::secbool::{secbool, sectrue}, + ui::{ + component::{Child, Component, Event, EventCtx, Label, Pad}, + constant::{screen, WIDTH}, + display::Icon, + geometry::{Insets, Point, Rect}, + model_tt::{ + bootloader::theme::{ + button_bld, button_bld_menu, BLD_BG, BUTTON_HEIGHT, CONTENT_PADDING, + CORNER_BUTTON_AREA, CORNER_BUTTON_TOUCH_EXPANSION, FIRE24, REFRESH24, TEXT_TITLE, + TITLE_AREA, X32, + }, + component::{Button, ButtonMsg::Clicked, IconText}, }, - component::{Button, ButtonMsg::Clicked, IconText}, }, }; @@ -19,9 +22,9 @@ const BUTTON_SPACING: i16 = 8; #[repr(u32)] #[derive(Copy, Clone, ToPrimitive)] pub enum MenuMsg { - Close = 1, - Reboot = 2, - FactoryReset = 3, + Close = 0xAABBCCDD, + Reboot = 0x11223344, + FactoryReset = 0x55667788, } pub struct Menu { @@ -33,7 +36,7 @@ pub struct Menu { } impl Menu { - pub fn new() -> Self { + pub fn new(firmware_present: secbool) -> Self { let content_reboot = IconText::new("REBOOT TREZOR", Icon::new(REFRESH24)); let content_reset = IconText::new("FACTORY RESET", Icon::new(FIRE24)); @@ -45,7 +48,11 @@ impl Menu { .styled(button_bld_menu()) .with_expanded_touch_area(Insets::uniform(CORNER_BUTTON_TOUCH_EXPANSION)), ), - reboot: Child::new(Button::with_icon_and_text(content_reboot).styled(button_bld())), + reboot: Child::new( + Button::with_icon_and_text(content_reboot) + .styled(button_bld()) + .initially_enabled(sectrue == firmware_present), + ), reset: Child::new(Button::with_icon_and_text(content_reset).styled(button_bld())), }; instance.bg.clear(); diff --git a/core/embed/rust/src/ui/model_tt/bootloader/mod.rs b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs index 36daa14520..c6eff2353d 100644 --- a/core/embed/rust/src/ui/model_tt/bootloader/mod.rs +++ b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs @@ -35,7 +35,7 @@ pub mod menu; pub mod theme; pub mod welcome; -use crate::ui::model_tt::theme::BLACK; +use crate::{trezorhal::secbool::secbool, ui::model_tt::theme::BLACK}; use confirm::Confirm; use intro::Intro; use menu::Menu; @@ -220,8 +220,8 @@ extern "C" fn screen_wipe_confirm() -> u32 { } #[no_mangle] -extern "C" fn screen_menu() -> u32 { - run(&mut Menu::new()) +extern "C" fn screen_menu(firmware_present: secbool) -> u32 { + run(&mut Menu::new(firmware_present)) } #[no_mangle] @@ -230,6 +230,7 @@ extern "C" fn screen_intro( vendor_str: *const cty::c_char, vendor_str_len: u8, version: *const cty::c_char, + fw_ok: bool, ) -> u32 { let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); let version = unwrap!(unsafe { from_c_str(version) }); @@ -245,7 +246,7 @@ extern "C" fn screen_intro( unwrap!(version_str.push_str("\nby ")); unwrap!(version_str.push_str(vendor)); - let mut frame = Intro::new(title_str.as_str(), version_str.as_str()); + let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok); run(&mut frame) } diff --git a/core/embed/rust/src/ui/model_tt/bootloader/theme.rs b/core/embed/rust/src/ui/model_tt/bootloader/theme.rs index e865d3db9c..6c34ba3d97 100644 --- a/core/embed/rust/src/ui/model_tt/bootloader/theme.rs +++ b/core/embed/rust/src/ui/model_tt/bootloader/theme.rs @@ -14,6 +14,8 @@ pub const BLD_FG: Color = WHITE; pub const BLD_WIPE_COLOR: Color = Color::rgb(0xE7, 0x0E, 0x0E); pub const BLD_WIPE_TEXT_COLOR: Color = WHITE; +pub const BLD_WARN_COLOR: Color = Color::rgb(0xFF, 0x00, 0x00); + pub const BLD_WIPE_BTN_COLOR: Color = WHITE; pub const BLD_WIPE_BTN_COLOR_ACTIVE: Color = Color::rgb(0xFA, 0xCF, 0xCF); @@ -238,6 +240,13 @@ pub const TEXT_TITLE: TextStyle = TextStyle::new( ); pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG); +pub const TEXT_WARNING: TextStyle = TextStyle::new( + Font::BOLD, + BLD_WARN_COLOR, + BLD_BG, + BLD_WARN_COLOR, + BLD_WARN_COLOR, +); pub const TEXT_FINGERPRINT: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG) .with_line_breaking(BreakWordsNoHyphen);