fix(core/bootloader): fix erroneous shutdown when rejecting firmware upload

tychovrahe/trdisplay/qr
tychovrahe 11 months ago committed by TychoVrahe
parent 01a7de5b98
commit a6d0842663

@ -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,

@ -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.

@ -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

@ -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,

@ -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;
if (sectrue != read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr)) {
firmware_present = secfalse;
}
if (sectrue == firmware_present) {
firmware_present = check_vendor_header_keys(&vhdr);
// detect whether the device contains a valid firmware
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;
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_lock(&vhdr);
if (sectrue == vhdr_keys_ok) {
vhdr_lock_ok = 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;
// start the bootloader ...
// ... if user touched the screen on start
// ... or we have stay_in_bootloader flag to force it
// ... 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;
ui_set_initial_setup(true);
// erase storage
ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL),
NULL);
// keep the model screen up for a while
ui_set_initial_setup(true);
// keep the model screen up for a while
#ifndef USE_BACKLIGHT
hal_delay(1500);
hal_delay(1500);
#else
// backlight fading takes some time so the explicit delay here is shorter
hal_delay(1000);
// 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
// ... or we have stay_in_bootloader flag to force it
if (touched || stay_in_bootloader == sectrue) {
ui_set_initial_setup(false);
screen_t screen = SCREEN_INTRO;
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;
}
}

@ -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);

@ -18,6 +18,8 @@ pub mod uzlib;
pub mod wordlist;
pub mod buffers;
pub mod secbool;
#[cfg(not(feature = "micropython"))]
pub mod time;

@ -0,0 +1,3 @@
use super::ffi;
pub use ffi::{secbool, secfalse, sectrue};

@ -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<Label<&'a str>>,
buttons: Child<ButtonController<&'static str>>,
text: Child<Label<&'a str>>,
warn: Option<Child<Label<&'a str>>>,
}
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);
}

@ -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(

@ -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)
}

@ -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<Button<&'static str>>,
host: Child<Button<&'static str>>,
text: Child<Label<&'a str>>,
warn: Option<Child<Label<&'a str>>>,
}
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();
}

@ -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();

@ -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)
}

@ -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);

Loading…
Cancel
Save