You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/rust/src/ui/model_tt/bootloader/mod.rs

339 lines
9.5 KiB

use heapless::String;
use crate::{
strutil::hexlify,
trezorhal::secbool::secbool,
ui::{
component::{connect::Connect, Label},
display::{self, Color, Font, Icon},
geometry::{Point, Rect},
layout::simplified::{run, show, SimplifiedFeatures as _},
util::{from_c_array, from_c_str},
},
};
use super::{
bootloader::welcome::Welcome,
component::{
bl_confirm::{Confirm, ConfirmTitle},
Button, ResultScreen, WelcomeScreen,
},
theme::{
bootloader::{
button_bld, button_bld_menu, button_confirm, button_wipe_cancel, button_wipe_confirm,
BLD_BG, BLD_FG, BLD_TITLE_COLOR, BLD_WIPE_COLOR, CHECK24, CHECK40, DOWNLOAD32, FIRE32,
FIRE40, RESULT_FW_INSTALL, RESULT_INITIAL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL,
TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
},
BACKLIGHT_NORMAL, BLACK, FG, WHITE,
},
ModelTTFeatures,
};
use intro::Intro;
use menu::Menu;
pub mod intro;
pub mod menu;
pub mod welcome;
pub type BootloaderString = String<128>;
const RECONNECT_MESSAGE: &str = "PLEASE RECONNECT\nTHE DEVICE";
const SCREEN: Rect = ModelTTFeatures::SCREEN;
#[no_mangle]
extern "C" fn screen_install_confirm(
vendor_str: *const cty::c_char,
vendor_str_len: u8,
version: *const cty::c_char,
fingerprint: *const cty::uint8_t,
should_keep_seed: bool,
is_newvendor: bool,
version_cmp: cty::c_int,
) -> u32 {
let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
let version = unwrap!(unsafe { from_c_str(version) });
let mut fingerprint_buffer: [u8; 64] = [0; 64];
let fingerprint_str = unsafe {
let fingerprint_slice = core::slice::from_raw_parts(fingerprint, 32);
hexlify(fingerprint_slice, &mut fingerprint_buffer);
core::str::from_utf8_unchecked(fingerprint_buffer.as_ref())
};
let mut version_str: BootloaderString = String::new();
unwrap!(version_str.push_str("Firmware version "));
unwrap!(version_str.push_str(version));
unwrap!(version_str.push_str("\nby "));
unwrap!(version_str.push_str(text));
let title_str = if is_newvendor {
"CHANGE FW\nVENDOR"
} else if version_cmp > 0 {
"UPDATE FIRMWARE"
} else if version_cmp == 0 {
"REINSTALL FW"
} else {
"DOWNGRADE FW"
};
let title = Label::left_aligned(title_str, TEXT_BOLD).vertically_centered();
let msg = Label::left_aligned(version_str.as_ref(), TEXT_NORMAL);
let alert =
(!should_keep_seed).then_some(Label::left_aligned("SEED WILL BE ERASED!", TEXT_BOLD));
let (left, right) = if should_keep_seed {
let l = Button::with_text("CANCEL").styled(button_bld());
let r = Button::with_text("INSTALL").styled(button_confirm());
(l, r)
} else {
let l = Button::with_icon(Icon::new(X24)).styled(button_bld());
let r = Button::with_icon(Icon::new(CHECK24)).styled(button_confirm());
(l, r)
};
let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg).with_info(
"FW FINGERPRINT",
fingerprint_str,
button_bld_menu(),
);
if let Some(alert) = alert {
frame = frame.with_alert(alert);
}
run(&mut frame)
}
#[no_mangle]
extern "C" fn screen_wipe_confirm() -> u32 {
let icon = Icon::new(FIRE40);
let msg = Label::centered(
"Are you sure you want to factory reset the device?",
TEXT_WIPE_NORMAL,
);
let alert = Label::centered("SEED AND FIRMWARE\nWILL BE ERASED!", TEXT_WIPE_BOLD);
let right = Button::with_text("RESET").styled(button_wipe_confirm());
let left = Button::with_text("CANCEL").styled(button_wipe_cancel());
let mut frame =
Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg).with_alert(alert);
run(&mut frame)
}
#[no_mangle]
extern "C" fn screen_menu(firmware_present: secbool) -> u32 {
run(&mut Menu::new(firmware_present))
}
#[no_mangle]
extern "C" fn screen_intro(
bld_version: *const cty::c_char,
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) });
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
let mut title_str: BootloaderString = String::new();
unwrap!(title_str.push_str("BOOTLOADER "));
unwrap!(title_str.push_str(bld_version));
let mut version_str: BootloaderString = String::new();
unwrap!(version_str.push_str("Firmware version "));
unwrap!(version_str.push_str(version));
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(), fw_ok);
run(&mut frame)
}
fn screen_progress(
text: &str,
progress: u16,
initialize: bool,
fg_color: Color,
bg_color: Color,
icon: Option<(Icon, Color)>,
) {
if initialize {
ModelTTFeatures::fadeout();
display::rect_fill(SCREEN, bg_color);
}
display::text_center(
Point::new(SCREEN.width() / 2, SCREEN.height() - 45),
text,
Font::NORMAL,
fg_color,
bg_color,
);
display::loader(progress, -20, fg_color, bg_color, icon);
display::refresh();
if initialize {
ModelTTFeatures::fadein();
}
}
#[no_mangle]
extern "C" fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) {
let bg_color = if initial_setup { WELCOME_COLOR } else { BLD_BG };
let fg_color = if initial_setup { FG } else { BLD_FG };
screen_progress(
"Installing firmware",
progress,
initialize,
fg_color,
bg_color,
Some((Icon::new(DOWNLOAD32), fg_color)),
)
}
#[no_mangle]
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) {
screen_progress(
"Resetting Trezor",
progress,
initialize,
BLD_FG,
BLD_WIPE_COLOR,
Some((Icon::new(FIRE32), BLD_FG)),
)
}
#[no_mangle]
extern "C" fn screen_connect(initial_setup: bool) {
let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG };
let mut frame = Connect::new("Waiting for host...", BLD_TITLE_COLOR, bg);
show(&mut frame, true);
}
#[no_mangle]
extern "C" fn screen_wipe_success() {
let mut frame = ResultScreen::new(
&RESULT_WIPE,
Icon::new(CHECK40),
"Trezor reset\nsuccessfully",
Label::centered(RECONNECT_MESSAGE, RESULT_WIPE.title_style()).vertically_centered(),
true,
);
show(&mut frame, true);
}
#[no_mangle]
extern "C" fn screen_wipe_fail() {
let mut frame = ResultScreen::new(
&RESULT_WIPE,
Icon::new(WARNING40),
"Trezor reset was\nnot successful",
Label::centered(RECONNECT_MESSAGE, RESULT_WIPE.title_style()).vertically_centered(),
true,
);
show(&mut frame, true);
}
#[no_mangle]
extern "C" fn screen_boot_empty(fading: bool) {
if fading {
ModelTTFeatures::fadeout();
}
display::rect_fill(SCREEN, BLACK);
let mut frame = WelcomeScreen::new(true);
show(&mut frame, false);
if fading {
ModelTTFeatures::fadein();
} else {
display::set_backlight(BACKLIGHT_NORMAL);
}
display::refresh();
}
#[no_mangle]
extern "C" fn screen_install_fail() {
let mut frame = ResultScreen::new(
&RESULT_FW_INSTALL,
Icon::new(WARNING40),
"Firmware installation was not successful",
Label::centered(RECONNECT_MESSAGE, RESULT_FW_INSTALL.title_style()).vertically_centered(),
true,
);
show(&mut frame, true);
}
fn screen_install_success_bld(msg: &str, complete_draw: bool) {
let mut frame = ResultScreen::new(
&RESULT_FW_INSTALL,
Icon::new(CHECK40),
"Firmware installed\nsuccessfully",
Label::centered(msg, RESULT_FW_INSTALL.title_style()).vertically_centered(),
complete_draw,
);
show(&mut frame, complete_draw);
}
fn screen_install_success_initial(msg: &str, complete_draw: bool) {
let mut frame = ResultScreen::new(
&RESULT_INITIAL,
Icon::new(CHECK40),
"Firmware installed\nsuccessfully",
Label::centered(msg, RESULT_INITIAL.title_style()).vertically_centered(),
complete_draw,
);
show(&mut frame, complete_draw);
}
#[no_mangle]
extern "C" fn screen_install_success(
restart_seconds: u8,
initial_setup: bool,
complete_draw: bool,
) {
let mut reboot_msg = BootloaderString::new();
if restart_seconds >= 1 {
unwrap!(reboot_msg.push_str("RESTARTING IN "));
// in practice, restart_seconds is 5 or less so this is fine
let seconds_char = b'0' + restart_seconds % 10;
unwrap!(reboot_msg.push(seconds_char as char));
} else {
unwrap!(reboot_msg.push_str(RECONNECT_MESSAGE));
}
if initial_setup {
screen_install_success_initial(reboot_msg.as_str(), complete_draw)
} else {
screen_install_success_bld(reboot_msg.as_str(), complete_draw)
}
display::refresh();
}
#[no_mangle]
extern "C" fn screen_welcome() {
let mut frame = Welcome::new();
show(&mut frame, true);
}
#[no_mangle]
extern "C" fn bld_continue_label(bg_color: cty::uint16_t) {
display::text_center(
Point::new(SCREEN.width() / 2, SCREEN.height() - 5),
"click to continue ...",
Font::NORMAL,
WHITE,
Color::from_u16(bg_color),
);
}