From 9b8984896e11aae7f5ce344b91e6bead243f9f33 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Mon, 13 Mar 2023 18:56:16 +0100 Subject: [PATCH] refactor(core): unify error screens [no changelog] --- core/embed/bootloader/bootui.c | 4 +- core/embed/rust/rust_ui.h | 4 +- core/embed/rust/src/trezorhal/fatal_error.rs | 20 +--- core/embed/rust/src/ui/model_tr/screens.rs | 58 ++-------- .../rust/src/ui/model_tt/bootloader/mod.rs | 10 +- .../rust/src/ui/model_tt/component/error.rs | 105 ++++++++++++++++++ .../rust/src/ui/model_tt/component/mod.rs | 2 + .../rust/src/ui/model_tt/component/result.rs | 88 ++++++++++----- core/embed/rust/src/ui/model_tt/screens.rs | 87 ++------------- core/embed/rust/src/ui/model_tt/theme.rs | 3 + core/embed/rust/src/ui/screens.rs | 41 +++---- core/embed/trezorhal/common.c | 45 ++++++-- core/embed/unix/common.c | 49 ++++++-- 13 files changed, 295 insertions(+), 221 deletions(-) create mode 100644 core/embed/rust/src/ui/model_tt/component/error.rs diff --git a/core/embed/bootloader/bootui.c b/core/embed/bootloader/bootui.c index 85c45196b..bf5bd094d 100644 --- a/core/embed/bootloader/bootui.c +++ b/core/embed/bootloader/bootui.c @@ -191,11 +191,11 @@ void ui_screen_done(int restart_seconds, secbool full_redraw) { const char *str; char count_str[24]; if (restart_seconds >= 1) { - mini_snprintf(count_str, sizeof(count_str), "DONE! RESTARTING IN %d", + mini_snprintf(count_str, sizeof(count_str), "RESTARTING IN %d", restart_seconds); str = count_str; } else { - str = "DONE! RECONNECT THE DEVICE"; + str = "RECONNECT THE DEVICE"; } screen_install_success(str, initial_setup, full_redraw); diff --git a/core/embed/rust/rust_ui.h b/core/embed/rust/rust_ui.h index b27e0cc45..2399a3fd5 100644 --- a/core/embed/rust/rust_ui.h +++ b/core/embed/rust/rust_ui.h @@ -17,8 +17,8 @@ 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(const char* bld_version_str); void screen_connect(void); -void screen_fatal_error_c(const char* msg, const char* file); -void screen_error_shutdown_c(const char* label, const char* msg); +void screen_fatal_error_rust(const char* title, const char* msg, + const char* footer); void screen_wipe_success(void); void screen_wipe_fail(void); uint32_t screen_install_success(const char* reboot_msg, bool initial_setup, diff --git a/core/embed/rust/src/trezorhal/fatal_error.rs b/core/embed/rust/src/trezorhal/fatal_error.rs index 37a953285..aaae4bd2e 100644 --- a/core/embed/rust/src/trezorhal/fatal_error.rs +++ b/core/embed/rust/src/trezorhal/fatal_error.rs @@ -6,11 +6,6 @@ mod ffi { } use crate::ui::screens::screen_fatal_error; -#[cfg(not(feature = "bootloader"))] -use heapless::String; - -#[cfg(not(feature = "bootloader"))] -use crate::ui::util::u32_to_str; fn shutdown() -> ! { unsafe { ffi::trezor_shutdown() } @@ -18,22 +13,13 @@ fn shutdown() -> ! { #[cfg(feature = "bootloader")] pub fn __fatal_error(_expr: &str, _msg: &str, _file: &str, _line: u32, _func: &str) -> ! { - screen_fatal_error(Some("BL.rs"), "BL.rs"); + screen_fatal_error("BL.rs", "BL.rs", "PLEASE VISIT\nTREZOR.IO/RSOD"); shutdown() } #[cfg(not(feature = "bootloader"))] -pub fn __fatal_error(_expr: &str, msg: &str, file: &str, line: u32, _func: &str) -> ! { - let mut buf: String<256> = String::new(); - let _ = buf.push_str(file); // Nothing we can do if this fails - let _ = buf.push_str(": "); - - let mut line_buf = [0u8; 10]; - if let Some(text) = u32_to_str(line, &mut line_buf) { - let _ = buf.push_str(text); - } - - screen_fatal_error(Some(msg), buf.as_str()); +pub fn __fatal_error(_expr: &str, msg: &str, _file: &str, _line: u32, _func: &str) -> ! { + screen_fatal_error("FATAL ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); shutdown() } diff --git a/core/embed/rust/src/ui/model_tr/screens.rs b/core/embed/rust/src/ui/model_tr/screens.rs index 9ce43a73a..13c7e9128 100644 --- a/core/embed/rust/src/ui/model_tr/screens.rs +++ b/core/embed/rust/src/ui/model_tr/screens.rs @@ -26,64 +26,24 @@ unsafe fn get_str(text: &str) -> StrBuffer { unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) } } -pub fn screen_fatal_error(msg: Option<&str>, file: &str) { +pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) { // SAFETY: these will get placed into `frame` which does not outlive this // function - let msg = msg.map(|s| unsafe { get_str(s) }); - let file = unsafe { get_str(file) }; - - let m_top = if let Some(msg) = msg { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_BOLD, "FATAL ERROR!".into()).centered()); - messages.add(Paragraph::new(&TEXT_NORMAL, msg).centered()); - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - } else { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_BOLD, "FATAL ERROR!".into()).centered()); - - messages.add(Paragraph::new(&TEXT_NORMAL, file).centered()); - - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - }; + let title = unsafe { get_str(title) }; + let msg = unsafe { get_str(msg) }; + let footer = unsafe { get_str(footer) }; let mut messages = ParagraphVecShort::new(); - messages.add(Paragraph::new(&TEXT_BOLD, "PLEASE CONTACT".into()).centered()); - messages.add(Paragraph::new(&TEXT_BOLD, "TREZOR SUPPORT".into()).centered()); - - let m_bottom = + messages.add(Paragraph::new(&TEXT_BOLD, title).centered()); + messages.add(Paragraph::new(&TEXT_NORMAL, msg).centered()); + let m_top = Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); - let mut frame = ResultScreen::new(WHITE, BLACK, Icon::new(ICON_FAIL), m_top, m_bottom, true); - frame.place(constant::screen()); - frame.paint(); -} - -pub fn screen_error_shutdown(msg: Option<&str>, label: &str) { - // SAFETY: these will get placed into `frame` which does not outlive this - // function - let msg = msg.map(|s| unsafe { get_str(s) }); - let label = unsafe { get_str(label) }; - - let m_top = if let Some(msg) = msg { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_BOLD, label).centered()); - messages.add(Paragraph::new(&TEXT_NORMAL, msg).centered()); - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - } else { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_BOLD, label).centered()); - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - }; - let mut messages = ParagraphVecShort::new(); - messages.add(Paragraph::new(&TEXT_BOLD, "PLEASE UNPLUG".into()).centered()); - messages.add(Paragraph::new(&TEXT_BOLD, "THE DEVICE".into()).centered()); + messages.add(Paragraph::new(&TEXT_BOLD, footer).centered()); + let m_bottom = Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); 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 c6b66a983..623d0a3d9 100644 --- a/core/embed/rust/src/ui/model_tt/bootloader/mod.rs +++ b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs @@ -355,7 +355,7 @@ extern "C" fn screen_wipe_success() { BLD_WIPE_CANCEL_BTN_COLOR, Icon::new(CHECK40), m_top, - m_bottom, + Some(m_bottom), true, ); show(&mut frame, true); @@ -383,7 +383,7 @@ extern "C" fn screen_wipe_fail() { BLD_WIPE_CANCEL_BTN_COLOR, Icon::new(WARNING40), m_top, - m_bottom, + Some(m_bottom), true, ); show(&mut frame, true); @@ -433,7 +433,7 @@ extern "C" fn screen_install_fail() { BLD_BTN_COLOR, Icon::new(WARNING40), m_top, - m_bottom, + Some(m_bottom), true, ); show(&mut frame, true); @@ -457,7 +457,7 @@ fn screen_install_success_bld(msg: &'static str, complete_draw: bool) { BLD_BTN_COLOR, Icon::new(CHECK40), m_top, - m_bottom, + Some(m_bottom), complete_draw, ); show(&mut frame, complete_draw); @@ -483,7 +483,7 @@ fn screen_install_success_initial(msg: &'static str, complete_draw: bool) { WELCOME_HIGHLIGHT_COLOR, Icon::new(CHECK40), m_top, - m_bottom, + Some(m_bottom), complete_draw, ); show(&mut frame, complete_draw); diff --git a/core/embed/rust/src/ui/model_tt/component/error.rs b/core/embed/rust/src/ui/model_tt/component/error.rs new file mode 100644 index 000000000..e94f70602 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/component/error.rs @@ -0,0 +1,105 @@ +use crate::ui::{ + component::{ + text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs}, + Child, Component, Event, EventCtx, Label, Never, Pad, + }, + constant::screen, + display::{self, Icon}, + geometry::{Alignment::Center, Point, Rect, TOP_CENTER}, +}; + +use crate::ui::model_tt::{ + constant::WIDTH, + theme::{ + FATAL_ERROR_COLOR, FATAL_ERROR_HIGHLIGHT_COLOR, ICON_WARNING40, RESULT_FOOTER_HEIGHT, + RESULT_FOOTER_START, RESULT_PADDING, TEXT_ERROR_BOLD, WHITE, + }, +}; + +const TITLE_AREA_START: i16 = 70; +const ICON_TOP: i16 = 27; + +pub struct ErrorScreen { + bg: Pad, + title: Child>, + message: Child>>, + footer: Child>>, +} + +impl ErrorScreen { + pub fn new( + title: T, + message: Paragraphs>, + footer: Paragraphs>, + ) -> Self { + let title = Label::new(title, Center, TEXT_ERROR_BOLD); + Self { + bg: Pad::with_background(FATAL_ERROR_COLOR).with_clear(), + title: Child::new(title), + message: Child::new(message), + footer: Child::new(footer), + } + } +} + +impl Component for ErrorScreen { + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + self.bg.place(screen()); + + let title_area = Rect::new( + Point::new(RESULT_PADDING, TITLE_AREA_START), + Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START), + ); + + self.title.place(title_area); + + let (_, message_area) = title_area.split_top(self.title.inner().area().height()); + + self.message.place(message_area); + + let bottom_area = Rect::new( + Point::new(RESULT_PADDING, RESULT_FOOTER_START), + Point::new( + WIDTH - RESULT_PADDING, + RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT, + ), + ); + self.footer.place(bottom_area); + + bounds + } + + fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { + None + } + + fn paint(&mut self) { + self.bg.paint(); + + let icon = Icon::new(ICON_WARNING40); + icon.draw( + Point::new(screen().center().x, ICON_TOP), + TOP_CENTER, + WHITE, + FATAL_ERROR_COLOR, + ); + self.title.paint(); + self.message.paint(); + + display::rect_fill_rounded( + Rect::new( + Point::new(RESULT_PADDING, RESULT_FOOTER_START), + Point::new( + WIDTH - RESULT_PADDING, + RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT, + ), + ), + FATAL_ERROR_HIGHLIGHT_COLOR, + FATAL_ERROR_COLOR, + 2, + ); + self.footer.paint(); + } +} diff --git a/core/embed/rust/src/ui/model_tt/component/mod.rs b/core/embed/rust/src/ui/model_tt/component/mod.rs index 7744d14c0..31b3c756e 100644 --- a/core/embed/rust/src/ui/model_tt/component/mod.rs +++ b/core/embed/rust/src/ui/model_tt/component/mod.rs @@ -5,6 +5,7 @@ mod dialog; mod fido; #[rustfmt::skip] mod fido_icons; +mod error; mod frame; mod hold_to_confirm; #[cfg(feature = "dma2d")] @@ -27,6 +28,7 @@ pub use button::{ }; pub use coinjoin_progress::CoinJoinProgress; pub use dialog::{Dialog, DialogMsg, IconDialog}; +pub use error::ErrorScreen; pub use fido::{FidoConfirm, FidoMsg}; pub use frame::{Frame, FrameMsg, NotificationFrame}; pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg}; diff --git a/core/embed/rust/src/ui/model_tt/component/result.rs b/core/embed/rust/src/ui/model_tt/component/result.rs index 6a3ae9c48..b7f24b7f0 100644 --- a/core/embed/rust/src/ui/model_tt/component/result.rs +++ b/core/embed/rust/src/ui/model_tt/component/result.rs @@ -8,17 +8,23 @@ use crate::ui::{ geometry::{Point, Rect, CENTER}, }; -use crate::ui::model_tt::constant::{HEIGHT, WIDTH}; +use crate::ui::model_tt::{ + constant::WIDTH, + theme::{RESULT_FOOTER_HEIGHT, RESULT_FOOTER_START, RESULT_PADDING}, +}; + +const MESSAGE_AREA_START: i16 = 82; +const ICON_CENTER_Y: i16 = 62; pub struct ResultScreen { bg: Pad, - small_pad: Pad, + footer_pad: Pad, fg_color: Color, bg_color: Color, msg_area_color: Color, icon: Icon, - message_top: Child>>, - message_bottom: Child>>, + message: Child>>, + footer: Option>>>, } impl ResultScreen { @@ -27,25 +33,25 @@ impl ResultScreen { bg_color: Color, msg_area_color: Color, icon: Icon, - message_top: Paragraphs>, - message_bottom: Paragraphs>, + message: Paragraphs>, + footer: Option>>, complete_draw: bool, ) -> Self { let mut instance = Self { bg: Pad::with_background(bg_color), - small_pad: Pad::with_background(bg_color), + footer_pad: Pad::with_background(bg_color), fg_color, bg_color, msg_area_color, icon, - message_top: Child::new(message_top), - message_bottom: Child::new(message_bottom), + message: Child::new(message), + footer: footer.map(Child::new), }; if complete_draw { instance.bg.clear(); } else { - instance.small_pad.clear(); + instance.footer_pad.clear(); } instance } @@ -55,16 +61,33 @@ impl Component for ResultScreen { type Msg = Never; fn place(&mut self, bounds: Rect) -> Rect { - self.bg - .place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT))); - - self.message_top - .place(Rect::new(Point::new(15, 59), Point::new(WIDTH - 15, 176))); + self.bg.place(screen()); - let bottom_area = Rect::new(Point::new(6, 176), Point::new(WIDTH - 6, 176 + 56)); + let message_arae = if let Some(footer) = &mut self.footer { + let footer_area = Rect::new( + Point::new(RESULT_PADDING, RESULT_FOOTER_START), + Point::new( + WIDTH - RESULT_PADDING, + RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT, + ), + ); + self.footer_pad.place(footer_area); + footer.place(footer_area); + Rect::new( + Point::new(RESULT_PADDING, MESSAGE_AREA_START), + Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START), + ) + } else { + Rect::new( + Point::new(RESULT_PADDING, MESSAGE_AREA_START), + Point::new( + WIDTH - RESULT_PADDING, + RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT, + ), + ) + }; - self.small_pad.place(bottom_area); - self.message_bottom.place(bottom_area); + self.message.place(message_arae); bounds } @@ -75,21 +98,30 @@ impl Component for ResultScreen { fn paint(&mut self) { self.bg.paint(); - self.small_pad.paint(); + self.footer_pad.paint(); self.icon.draw( - Point::new(screen().center().x, 45), + Point::new(screen().center().x, ICON_CENTER_Y), CENTER, self.fg_color, self.bg_color, ); - self.message_top.paint(); - display::rect_fill_rounded( - Rect::new(Point::new(6, 176), Point::new(WIDTH - 6, 176 + 56)), - self.msg_area_color, - self.bg_color, - 2, - ); - self.message_bottom.paint(); + self.message.paint(); + + if let Some(bottom) = &mut self.footer { + display::rect_fill_rounded( + Rect::new( + Point::new(RESULT_PADDING, RESULT_FOOTER_START), + Point::new( + WIDTH - RESULT_PADDING, + RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT, + ), + ), + self.msg_area_color, + self.bg_color, + 2, + ); + bottom.paint(); + } } } diff --git a/core/embed/rust/src/ui/model_tt/screens.rs b/core/embed/rust/src/ui/model_tt/screens.rs index c4ded7897..d14ab5920 100644 --- a/core/embed/rust/src/ui/model_tt/screens.rs +++ b/core/embed/rust/src/ui/model_tt/screens.rs @@ -5,15 +5,11 @@ use crate::ui::{ text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt}, Component, }, - display::Icon, geometry::LinearPlacement, model_tt::{ - component::ResultScreen, + component::ErrorScreen, constant, - theme::{ - FATAL_ERROR_COLOR, FATAL_ERROR_HIGHLIGHT_COLOR, ICON_WARNING40, TEXT_ERROR_BOLD, - TEXT_ERROR_HIGHLIGHT, TEXT_ERROR_NORMAL, WHITE, - }, + theme::{TEXT_ERROR_HIGHLIGHT, TEXT_ERROR_NORMAL}, }, }; @@ -29,87 +25,28 @@ unsafe fn get_str(text: &str) -> StrBuffer { unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) } } -pub fn screen_fatal_error(msg: Option<&str>, file: &str) { +pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) { // SAFETY: these will get placed into `frame` which does not outlive this // function - let msg = msg.map(|s| unsafe { get_str(s) }); - let file = unsafe { get_str(file) }; + let title = unsafe { get_str(title) }; + let msg = unsafe { get_str(msg) }; + let footer = unsafe { get_str(footer) }; - let m_top = if let Some(msg) = msg { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "FATAL ERROR!".into()).centered()); - messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered()); - - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - } else { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "FATAL ERROR!".into()).centered()); - messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, file).centered()); - - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - }; let mut messages = ParagraphVecShort::new(); - messages.add( - Paragraph::new( - &TEXT_ERROR_HIGHLIGHT, - "PLEASE CONTACT\nTREZOR SUPPORT".into(), - ) - .centered(), - ); - let m_bottom = - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered()); - let mut frame = ResultScreen::new( - WHITE, - FATAL_ERROR_COLOR, - FATAL_ERROR_HIGHLIGHT_COLOR, - Icon::new(ICON_WARNING40), - m_top, - m_bottom, - true, - ); - frame.place(constant::screen()); - frame.paint(); -} - -pub fn screen_error_shutdown(label: &str, msg: Option<&str>) { - // SAFETY: these will get placed into `frame` which does not outlive this - // function - let msg = msg.map(|s| unsafe { get_str(s) }); - let label = unsafe { get_str(label) }; - - let m_top = if let Some(msg) = msg { - let mut messages = ParagraphVecShort::new(); - - messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered()); - messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered()); - - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - } else { - let mut messages = ParagraphVecShort::new(); + let m_top = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); - messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered()); - Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) - }; let mut messages = ParagraphVecShort::new(); - messages - .add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, "PLEASE UNPLUG\nTHE DEVICE".into()).centered()); + messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, footer).centered()); + let m_bottom = Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); - let mut frame = ResultScreen::new( - WHITE, - FATAL_ERROR_COLOR, - FATAL_ERROR_HIGHLIGHT_COLOR, - Icon::new(ICON_WARNING40), - m_top, - m_bottom, - true, - ); + let mut frame = ErrorScreen::new(title, m_top, m_bottom); frame.place(constant::screen()); frame.paint(); } diff --git a/core/embed/rust/src/ui/model_tt/theme.rs b/core/embed/rust/src/ui/model_tt/theme.rs index 82a9cba84..0b52b859f 100644 --- a/core/embed/rust/src/ui/model_tt/theme.rs +++ b/core/embed/rust/src/ui/model_tt/theme.rs @@ -556,6 +556,9 @@ pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING; pub const INFO_BUTTON_HEIGHT: i16 = 44; pub const PIN_BUTTON_HEIGHT: i16 = 40; pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52; +pub const RESULT_PADDING: i16 = 6; +pub const RESULT_FOOTER_START: i16 = 178; +pub const RESULT_FOOTER_HEIGHT: i16 = 56; pub const fn button_bar(inner: T) -> FixedHeightBar { FixedHeightBar::bottom(inner, BUTTON_HEIGHT) diff --git a/core/embed/rust/src/ui/screens.rs b/core/embed/rust/src/ui/screens.rs index 0460d0319..6d8863f19 100644 --- a/core/embed/rust/src/ui/screens.rs +++ b/core/embed/rust/src/ui/screens.rs @@ -7,34 +7,25 @@ pub use super::model_tr::screens::*; pub use super::model_tt::screens::*; use crate::ui::util::from_c_str; -#[no_mangle] -extern "C" fn screen_fatal_error_c(msg: *const cty::c_char, file: *const cty::c_char) { - let msg = if msg.is_null() { - None - } else { - unsafe { from_c_str(msg) } - }; - let file = if file.is_null() { - "" - } else { - unwrap!(unsafe { from_c_str(file) }) +macro_rules! convert_str { + ($str:expr) => { + if ($str).is_null() { + "" + } else { + unwrap!(unsafe { from_c_str($str) }) + } }; - - screen_fatal_error(msg, file); } #[no_mangle] -extern "C" fn screen_error_shutdown_c(msg: *const cty::c_char, file: *const cty::c_char) { - let msg = if msg.is_null() { - None - } else { - unsafe { from_c_str(msg) } - }; - let file = if file.is_null() { - "" - } else { - unwrap!(unsafe { from_c_str(file) }) - }; +extern "C" fn screen_fatal_error_rust( + title: *const cty::c_char, + msg: *const cty::c_char, + footer: *const cty::c_char, +) { + let title = convert_str!(title); + let msg = convert_str!(msg); + let footer = convert_str!(footer); - screen_fatal_error(msg, file); + screen_fatal_error(title, msg, footer); } diff --git a/core/embed/trezorhal/common.c b/core/embed/trezorhal/common.c index 01a83eacf..7c93505e9 100644 --- a/core/embed/trezorhal/common.c +++ b/core/embed/trezorhal/common.c @@ -55,6 +55,31 @@ void __attribute__((noreturn)) trezor_shutdown(void) { ; } +void __attribute__((noreturn)) +error_uni(const char *label, const char *msg, const char *footer) { + display_orientation(0); + +#ifdef FANCY_FATAL_ERROR + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (label) { + display_printf("%s\n", label); + } + if (msg) { + display_printf("%s\n", msg); + } + if (footer) { + display_printf("\n%s\n", footer); + } +#endif + display_backlight(255); + display_refresh(); + trezor_shutdown(); +} + void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func) { @@ -64,7 +89,8 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, #ifdef FANCY_FATAL_ERROR char buf[256] = {0}; mini_snprintf(buf, sizeof(buf), "%s: %d", file, line); - screen_fatal_error_c(msg, buf); + screen_fatal_error_rust("FATAL ERROR", msg != NULL ? msg : buf, + "PLEASE VISIT\nTREZOR.IO/RSOD"); display_refresh(); #else display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); @@ -94,8 +120,10 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, void __attribute__((noreturn)) error_shutdown(const char *label, const char *msg) { display_orientation(0); + #ifdef FANCY_FATAL_ERROR - screen_error_shutdown_c(label, msg); + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); display_refresh(); #else display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); @@ -105,7 +133,7 @@ error_shutdown(const char *label, const char *msg) { if (msg) { display_printf("%s\n", msg); } - display_printf("\nPlease unplug the device.\n"); + display_printf("\nPLEASE VISIT TREZOR.IO/RSOD\n"); #endif display_backlight(255); trezor_shutdown(); @@ -141,7 +169,7 @@ void clear_otg_hs_memory(void) { uint32_t __stack_chk_guard = 0; void __attribute__((noreturn)) __stack_chk_fail(void) { - error_shutdown("Internal error", "(SS)"); + error_shutdown("INTERNAL ERROR", "(SS)"); } uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; @@ -183,11 +211,10 @@ void ensure_compatible_settings(void) { } void show_wipe_code_screen(void) { - error_shutdown( - "DEVICE WIPED!", - "You have entered the wipe code. All private data has been erased."); + error_uni("WIPE CODE ENTERED", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); } void show_pin_too_many_screen(void) { - error_shutdown("DEVICE WIPED!", - "Too many wrong PIN attempts. Storage has been wiped."); + error_uni("TOO MANY PIN ATTEMPTS", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); } diff --git a/core/embed/unix/common.c b/core/embed/unix/common.c index 6317b9584..8ad31eca5 100644 --- a/core/embed/unix/common.c +++ b/core/embed/unix/common.c @@ -48,6 +48,32 @@ void __attribute__((noreturn)) trezor_shutdown(void) { #define COLOR_FATAL_ERROR 0x0000 #endif +void __attribute__((noreturn)) +error_uni(const char *label, const char *msg, const char *footer) { + display_orientation(0); + +#ifdef FANCY_FATAL_ERROR + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (label) { + display_printf("%s\n", label); + } + if (msg) { + display_printf("%s\n", msg); + } + if (footer) { + display_printf("\n%s\n", footer); + } +#endif + display_backlight(255); + display_refresh(); + hal_delay(3000); + trezor_shutdown(); +} + void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func) { @@ -55,9 +81,15 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, display_backlight(255); #ifdef FANCY_FATAL_ERROR - char buf[256] = {0}; - snprintf(buf, sizeof(buf), "%s: %d", file, line); - screen_fatal_error_c(msg, buf); + if (msg == NULL) { + msg = "Unknown error"; + char buf[256] = {0}; + snprintf(buf, sizeof(buf), "%s: %d", file, line); + screen_fatal_error_rust("FATAL ERROR", buf, "PLEASE VISIT\nTREZOR.IO/RSOD"); + } else { + screen_fatal_error_rust("FATAL ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + } + display_refresh(); #else display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); @@ -96,7 +128,7 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, void __attribute__((noreturn)) error_shutdown(const char *label, const char *msg) { #ifdef FANCY_FATAL_ERROR - screen_error_shutdown_c(label, msg); + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); display_refresh(); #else display_clear(); @@ -176,11 +208,10 @@ uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; void collect_hw_entropy(void) { memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); } void show_wipe_code_screen(void) { - error_shutdown( - "DEVICE WIPED!", - "You have entered the wipe code. All private data has been erased."); + error_uni("WIPE CODE ENTERED", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); } void show_pin_too_many_screen(void) { - error_shutdown("DEVICE WIPED!", - "Too many wrong PIN attempts. Storage has been wiped."); + error_uni("TOO MANY PIN ATTEMPTS", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); }