diff --git a/core/.changelog.d/1049.added b/core/.changelog.d/1049.added new file mode 100644 index 000000000..97c386e6b --- /dev/null +++ b/core/.changelog.d/1049.added @@ -0,0 +1 @@ +Error screens redesign diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index ec8b33e53..56d41d4d1 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -32,10 +32,10 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD=None FONT_MONO='Font_PixelOperatorMono_Regular_8' if TREZOR_MODEL in ('T', ): - FONT_NORMAL='Font_Roboto_Regular_20' + FONT_NORMAL='Font_TTHoves_Regular_18' FONT_DEMIBOLD=None - FONT_BOLD=None - FONT_MONO='Font_RobotoMono_Regular_20' + FONT_BOLD='Font_TTHoves_Bold_16' + FONT_MONO=None # modtrezorcrypto CCFLAGS_MOD += '-Wno-sequence-point ' @@ -47,6 +47,9 @@ CPPDEFINES_MOD += [ 'AES_192', 'USE_KECCAK', 'ED25519_NO_PRECOMP', + 'TREZOR_UI2', + 'USE_RUST_LOADER', + 'FANCY_FATAL_ERROR' ] SOURCE_MOD += [ 'vendor/trezor-crypto/blake2s.c', diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 62bb0bf03..06022f6fe 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -192,6 +192,11 @@ CPPDEFINES_MOD += [ 'USE_RUST_LOADER' ] +if TREZOR_MODEL not in ('1', ): + CPPDEFINES_MOD += [ + 'FANCY_FATAL_ERROR', + ] + # modtrezorutils SOURCE_MOD += [ 'embed/extmod/modtrezorutils/modtrezorutils.c', diff --git a/core/SConscript.unix b/core/SConscript.unix index e1b8724e8..dad147417 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -184,6 +184,11 @@ CPPDEFINES_MOD += [ 'TREZOR_UI2', 'USE_RUST_LOADER' ] +if TREZOR_MODEL not in ('1', ): + CPPDEFINES_MOD += [ + 'FANCY_FATAL_ERROR', + ] + if FROZEN: CPPDEFINES_MOD += ['TREZOR_EMULATOR_FROZEN'] if RASPI: diff --git a/core/assets/close.png b/core/assets/close.png new file mode 100644 index 000000000..e75807674 Binary files /dev/null and b/core/assets/close.png differ diff --git a/core/assets/erase_big.png b/core/assets/erase_big.png new file mode 100644 index 000000000..4282cf69d Binary files /dev/null and b/core/assets/erase_big.png differ diff --git a/core/assets/info_small.png b/core/assets/info_small.png new file mode 100644 index 000000000..838004eac Binary files /dev/null and b/core/assets/info_small.png differ diff --git a/core/assets/menu.png b/core/assets/menu.png new file mode 100644 index 000000000..55027b2da Binary files /dev/null and b/core/assets/menu.png differ diff --git a/core/assets/success_bld.png b/core/assets/success_bld.png new file mode 100644 index 000000000..1119e3864 Binary files /dev/null and b/core/assets/success_bld.png differ diff --git a/core/assets/warn_bld.png b/core/assets/warn_bld.png new file mode 100644 index 000000000..dcedb0be7 Binary files /dev/null and b/core/assets/warn_bld.png differ diff --git a/core/embed/bootloader/.changelog.d/1049.added b/core/embed/bootloader/.changelog.d/1049.added new file mode 100644 index 000000000..873319b6a --- /dev/null +++ b/core/embed/bootloader/.changelog.d/1049.added @@ -0,0 +1 @@ +Bootloader redesign diff --git a/core/embed/bootloader/bootui.c b/core/embed/bootloader/bootui.c index 69dc9346d..ae5a9d6c8 100644 --- a/core/embed/bootloader/bootui.c +++ b/core/embed/bootloader/bootui.c @@ -21,27 +21,10 @@ #include "bootui.h" #include "display.h" -#include "icon_cancel.h" -#include "icon_confirm.h" -#include "icon_done.h" -#include "icon_fail.h" -#include "icon_info.h" -#include "icon_install.h" -#include "icon_logo.h" -#include "icon_safeplace.h" -#include "icon_welcome.h" -#include "icon_wipe.h" #include "mini_printf.h" +#include "rust_ui.h" #include "version.h" -#if defined USE_TOUCH -#include "touch/touch.h" -#elif defined USE_BUTTON -#include "button.h" -#else -#error No input method defined -#endif - #define BACKLIGHT_NORMAL 150 #define COLOR_BL_BG COLOR_WHITE // background @@ -59,34 +42,22 @@ #define COLOR_BL_GRAY COLOR_BL_FG #endif -#define COLOR_WELCOME_BG COLOR_WHITE // welcome background -#define COLOR_WELCOME_FG COLOR_BLACK // welcome foreground - // common shared functions -static void ui_confirm_cancel_buttons(void) { - display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_BL_BG, 4); - display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16, - toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_BL_BG, - COLOR_BL_FAIL); - display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_BL_BG, 4); - display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, - toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, - COLOR_BL_BG, COLOR_BL_DONE); -} - -static const char *format_ver(const char *format, uint32_t version) { - static char ver_str[64]; - mini_snprintf(ver_str, sizeof(ver_str), format, (int)(version & 0xFF), +static void format_ver(const char *format, uint32_t version, char *buffer, + size_t buffer_len) { + mini_snprintf(buffer, buffer_len, format, (int)(version & 0xFF), (int)((version >> 8) & 0xFF), (int)((version >> 16) & 0xFF) // ignore build field (int)((version >> 24) & 0xFF) ); - return ver_str; } // boot UI static uint16_t boot_background; +static bool initial_setup = true; + +void ui_set_initial_setup(bool initial) { initial_setup = initial; } void ui_screen_boot(const vendor_header *const vhdr, const image_header *const hdr) { @@ -112,10 +83,11 @@ void ui_screen_boot(const vendor_header *const vhdr, } if (show_string) { + char ver_str[64]; display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 50, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BL_BG, boot_background); - const char *ver_str = format_ver("%d.%d.%d", fw_version); + format_ver("%d.%d.%d", fw_version, ver_str, sizeof(ver_str)); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 25, ver_str, -1, FONT_NORMAL, COLOR_BL_BG, boot_background); } @@ -145,187 +117,75 @@ void ui_screen_boot_click(void) { // welcome UI -void ui_screen_welcome_first(void) { - display_icon(0, 0, 240, 240, toi_icon_logo + 12, sizeof(toi_icon_logo) - 12, - COLOR_WELCOME_FG, COLOR_WELCOME_BG); - PIXELDATA_DIRTY(); - display_refresh(); -} +void ui_screen_welcome(void) { screen_welcome(); } -void ui_screen_welcome_second(void) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WELCOME_BG); - display_icon((DISPLAY_RESX - 200) / 2, (DISPLAY_RESY - 60) / 2, 200, 60, - toi_icon_safeplace + 12, sizeof(toi_icon_safeplace) - 12, - COLOR_WELCOME_FG, COLOR_WELCOME_BG); - PIXELDATA_DIRTY(); - display_refresh(); -} +uint32_t ui_screen_intro(const vendor_header *const vhdr, + const image_header *const hdr) { + 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)); -void ui_screen_welcome_third(void) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WELCOME_BG); - display_icon((DISPLAY_RESX - 180) / 2, (DISPLAY_RESY - 30) / 2 - 5, 180, 30, - toi_icon_welcome + 12, sizeof(toi_icon_welcome) - 12, - COLOR_WELCOME_FG, COLOR_WELCOME_BG); - display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL, - COLOR_WELCOME_FG, COLOR_WELCOME_BG); - PIXELDATA_DIRTY(); - display_refresh(); + return screen_intro(bld_ver, vhdr->vstr, vhdr->vstr_len, ver_str); } -// info UI - -static int display_vendor_string(const char *text, int textlen, - uint16_t fgcolor) { - int split = display_text_split(text, textlen, FONT_NORMAL, DISPLAY_RESX - 55); - if (split >= textlen) { - display_text(55, 95, text, textlen, FONT_NORMAL, fgcolor, COLOR_BL_BG); - return 120; - } else { - display_text(55, 95, text, split, FONT_NORMAL, fgcolor, COLOR_BL_BG); - if (text[split] == ' ') { - split++; - } - display_text(55, 120, text + split, textlen - split, FONT_NORMAL, fgcolor, - COLOR_BL_BG); - return 145; - } - PIXELDATA_DIRTY(); - display_refresh(); -} - -void ui_screen_firmware_info(const vendor_header *const vhdr, - const image_header *const hdr) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - const char *ver_str = format_ver("Bootloader %d.%d.%d", VERSION_UINT32); - display_text(16, 32, ver_str, -1, FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG); - display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG); - display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, - COLOR_BL_GRAY, COLOR_BL_BG); - if (vhdr && hdr) { - ver_str = format_ver("Firmware %d.%d.%d by", (hdr->version)); - display_text(55, 70, ver_str, -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_BL_BG); - display_vendor_string(vhdr->vstr, vhdr->vstr_len, COLOR_BL_GRAY); - } else { - display_text(55, 70, "No Firmware", -1, FONT_NORMAL, COLOR_BL_GRAY, - COLOR_BL_BG); - } - display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL, - COLOR_BL_FG, COLOR_BL_BG); - PIXELDATA_DIRTY(); - display_refresh(); +uint32_t ui_screen_menu(void) { + char bld_ver[32]; + format_ver("%d.%d.%d", VERSION_UINT32, bld_ver, sizeof(bld_ver)); + return screen_menu(bld_ver); } // install UI -void ui_screen_install_confirm_upgrade(const vendor_header *const vhdr, - const image_header *const hdr) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - display_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG); - display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, - COLOR_BL_FG, COLOR_BL_BG); - display_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - int next_y = display_vendor_string(vhdr->vstr, vhdr->vstr_len, COLOR_BL_FG); - const char *ver_str = format_ver("to version %d.%d.%d?", hdr->version); - display_text(55, next_y, ver_str, -1, FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG); - ui_confirm_cancel_buttons(); - PIXELDATA_DIRTY(); - display_refresh(); +uint32_t ui_screen_install_confirm_upgrade(const vendor_header *const vhdr, + const image_header *const hdr) { + uint8_t fingerprint[32]; + char ver_str[64]; + get_image_fingerprint(hdr, fingerprint); + format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str)); + return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, + fingerprint, false, false); } -void ui_screen_install_confirm_newvendor_or_downgrade_wipe( +uint32_t ui_screen_install_confirm_newvendor_or_downgrade_wipe( const vendor_header *const vhdr, const image_header *const hdr, secbool downgrade_wipe) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - display_text( - 16, 32, - (sectrue == downgrade_wipe) ? "Firmware downgrade" : "Vendor change", -1, - FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG); - display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG); - display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, - COLOR_BL_FG, COLOR_BL_BG); - display_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - int next_y = display_vendor_string(vhdr->vstr, vhdr->vstr_len, COLOR_BL_FG); - const char *ver_str = format_ver("(version %d.%d.%d)?", hdr->version); - display_text(55, next_y, ver_str, -1, FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG); - display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL, - COLOR_BL_FAIL, COLOR_BL_BG); - ui_confirm_cancel_buttons(); - PIXELDATA_DIRTY(); - display_refresh(); + uint8_t fingerprint[32]; + char ver_str[64]; + get_image_fingerprint(hdr, fingerprint); + format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str)); + if (downgrade_wipe) { + return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, + fingerprint, true, false); + } else { + return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, + fingerprint, false, true); + } } -void ui_screen_install_start(void) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - display_loader(0, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, toi_icon_install, - sizeof(toi_icon_install), COLOR_BL_FG); - display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, - "Installing firmware", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - PIXELDATA_DIRTY(); - display_refresh(); +void ui_screen_install_start() { + screen_install_progress(0, true, initial_setup); } void ui_screen_install_progress_erase(int pos, int len) { - display_loader(250 * pos / len, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, - toi_icon_install, sizeof(toi_icon_install), COLOR_BL_FG); - - PIXELDATA_DIRTY(); - display_refresh(); + screen_install_progress(250 * pos / len, false, initial_setup); } void ui_screen_install_progress_upload(int pos) { - display_loader(pos, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, - toi_icon_install, sizeof(toi_icon_install), COLOR_BL_FG); - - PIXELDATA_DIRTY(); - display_refresh(); + screen_install_progress(pos, false, initial_setup); } // wipe UI -void ui_screen_wipe_confirm(void) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - display_text(16, 32, "Wipe device", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG); - display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, - COLOR_BL_FG, COLOR_BL_BG); - display_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - display_text(55, 95, "wipe the device?", -1, FONT_NORMAL, COLOR_BL_FG, - COLOR_BL_BG); - - display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL, - COLOR_BL_FAIL, COLOR_BL_BG); - ui_confirm_cancel_buttons(); - PIXELDATA_DIRTY(); - display_refresh(); -} +uint32_t ui_screen_wipe_confirm(void) { return screen_wipe_confirm(); } -void ui_screen_wipe(void) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - display_loader(0, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, toi_icon_wipe, - sizeof(toi_icon_wipe), COLOR_BL_FG); - display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Wiping device", -1, - FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG); - PIXELDATA_DIRTY(); - display_refresh(); -} +void ui_screen_wipe(void) { screen_wipe_progress(0, true); } void ui_screen_wipe_progress(int pos, int len) { - display_loader(1000 * pos / len, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, - toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BL_FG); - - PIXELDATA_DIRTY(); - display_refresh(); + screen_wipe_progress(1000 * pos / len, false); } // done UI - void ui_screen_done(int restart_seconds, secbool full_redraw) { const char *str; char count_str[24]; @@ -336,35 +196,17 @@ void ui_screen_done(int restart_seconds, secbool full_redraw) { } else { str = "Done! Unplug the device."; } - if (sectrue == full_redraw) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - } - display_loader(1000, false, -20, COLOR_BL_DONE, COLOR_BL_BG, toi_icon_done, - sizeof(toi_icon_done), COLOR_BL_FG); - if (secfalse == full_redraw) { - display_bar(0, DISPLAY_RESY - 24 - 18, 240, 23, COLOR_BL_BG); - } - display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, str, -1, FONT_NORMAL, - COLOR_BL_FG, COLOR_BL_BG); - PIXELDATA_DIRTY(); - display_refresh(); + screen_install_success(str, initial_setup, full_redraw); } -// error UI - -void ui_screen_fail(void) { - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG); - display_loader(1000, false, -20, COLOR_BL_FAIL, COLOR_BL_BG, toi_icon_fail, - sizeof(toi_icon_fail), COLOR_BL_FG); - display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, - "Failed! Please, reconnect.", -1, FONT_NORMAL, - COLOR_BL_FG, COLOR_BL_BG); - - PIXELDATA_DIRTY(); - display_refresh(); +void ui_screen_boot_empty(bool firmware_present, bool fading) { + screen_boot_empty(firmware_present, fading); } +// error UI +void ui_screen_fail(void) { screen_install_fail(); } + // general functions void ui_fadein(void) { display_fade(0, BACKLIGHT_NORMAL, 1000); } @@ -373,43 +215,3 @@ void ui_fadeout(void) { display_fade(BACKLIGHT_NORMAL, 0, 500); display_clear(); } - -int ui_user_input(int zones) { - for (;;) { -#if defined USE_TOUCH - uint32_t evt = touch_click(); - uint16_t x = touch_unpack_x(evt); - uint16_t y = touch_unpack_y(evt); - // clicked on Cancel button - if ((zones & INPUT_CANCEL) && x >= 9 && x < 9 + 108 && y > 184 && - y < 184 + 50) { - return INPUT_CANCEL; - } - // clicked on Confirm button - if ((zones & INPUT_CONFIRM) && x >= 123 && x < 123 + 108 && y > 184 && - y < 184 + 50) { - return INPUT_CONFIRM; - } - // clicked on Long Confirm button - if ((zones & INPUT_LONG_CONFIRM) && x >= 9 && x < 9 + 222 && y > 184 && - y < 184 + 50) { - return INPUT_LONG_CONFIRM; - } - // clicked on Info icon - if ((zones & INPUT_INFO) && x >= 16 && x < 16 + 32 && y > 54 && - y < 54 + 32) { - return INPUT_INFO; - } -#elif defined USE_BUTTON - uint32_t evt = button_read(); - if (evt == (BTN_LEFT | BTN_EVT_DOWN)) { - return INPUT_CANCEL; - } - if (evt == (BTN_RIGHT | BTN_EVT_DOWN)) { - return INPUT_CONFIRM; - } -#else -#error No input method defined -#endif - } -} diff --git a/core/embed/bootloader/bootui.h b/core/embed/bootloader/bootui.h index 73285e419..5159d7a7a 100644 --- a/core/embed/bootloader/bootui.h +++ b/core/embed/bootloader/bootui.h @@ -22,29 +22,38 @@ #include "image.h" #include "secbool.h" +#include "stdbool.h" + +typedef enum { + SCREEN_INTRO = 0, + SCREEN_MENU = 1, + SCREEN_WIPE_CONFIRM = 2, + SCREEN_FINGER_PRINT = 3, + SCREEN_WAIT_FOR_HOST = 4, +} screen_t; void ui_screen_boot(const vendor_header* const vhdr, const image_header* const hdr); void ui_screen_boot_wait(int wait_seconds); void ui_screen_boot_click(void); -void ui_screen_welcome_first(void); -void ui_screen_welcome_second(void); -void ui_screen_welcome_third(void); +void ui_screen_welcome(void); + +uint32_t ui_screen_intro(const vendor_header* const vhdr, + const image_header* const hdr); -void ui_screen_firmware_info(const vendor_header* const vhdr, - const image_header* const hdr); +uint32_t ui_screen_menu(void); -void ui_screen_install_confirm_upgrade(const vendor_header* const vhdr, - const image_header* const hdr); -void ui_screen_install_confirm_newvendor_or_downgrade_wipe( +uint32_t ui_screen_install_confirm_upgrade(const vendor_header* const vhdr, + const image_header* const hdr); +uint32_t ui_screen_install_confirm_newvendor_or_downgrade_wipe( const vendor_header* const vhdr, const image_header* const hdr, secbool downgrade_wipe); -void ui_screen_install_start(void); +void ui_screen_install_start(); void ui_screen_install_progress_erase(int pos, int len); void ui_screen_install_progress_upload(int pos); -void ui_screen_wipe_confirm(void); +uint32_t ui_screen_wipe_confirm(void); void ui_screen_wipe(void); void ui_screen_wipe_progress(int pos, int len); @@ -54,6 +63,9 @@ void ui_screen_fail(void); void ui_fadein(void); void ui_fadeout(void); +void ui_set_initial_setup(bool initial); + +void ui_screen_boot_empty(bool firmware_present, bool fading); // clang-format off #define INPUT_CANCEL 0x01 // Cancel button diff --git a/core/embed/bootloader/icon_cancel.h b/core/embed/bootloader/icon_cancel.h deleted file mode 100644 index 50ac0a813..000000000 --- a/core/embed/bootloader/icon_cancel.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_cancel[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x10, 0x00, 0x10, 0x00, - // compressed data length (32-bit) - 0x52, 0x00, 0x00, 0x00, - // compressed data - 0x45, 0x4d, 0xc1, 0x09, 0x80, 0x30, 0x10, 0x4b, 0xcf, 0x05, 0xba, 0x80, 0xd0, 0x01, 0x2c, 0xb8, 0xff, 0x47, 0x70, 0x01, 0xb1, 0x0b, 0xdc, 0x20, 0xb6, 0xc4, 0x48, 0x5b, 0x0c, 0x1c, 0x09, 0xe1, 0x92, 0xe0, 0x0c, 0x40, 0xdc, 0x90, 0x5a, 0x06, 0x8a, 0x5b, 0xa1, 0x5b, 0x6a, 0xcc, 0x0f, 0xb9, 0xde, 0xe4, 0xa1, 0xf3, 0x26, 0x9d, 0x2a, 0x85, 0xcb, 0x50, 0x3e, 0xd6, 0x6f, 0x94, 0xeb, 0xe1, 0xe7, 0xe1, 0x2b, 0x2b, 0xb8, 0xcd, 0x5c, 0xed, 0x3d, 0xd7, 0xec, 0xdd, 0xfb, 0xce, 0x82, 0xb1, 0xfb, 0x02, -}; diff --git a/core/embed/bootloader/icon_confirm.h b/core/embed/bootloader/icon_confirm.h deleted file mode 100644 index 4c6ac8309..000000000 --- a/core/embed/bootloader/icon_confirm.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_confirm[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x14, 0x00, 0x10, 0x00, - // compressed data length (32-bit) - 0x69, 0x00, 0x00, 0x00, - // compressed data - 0x63, 0x60, 0x80, 0x80, 0x48, 0x28, 0xcd, 0x30, 0xe1, 0x3f, 0x2b, 0x94, 0xf5, 0xe3, 0x7f, 0x3c, 0x84, 0xd1, 0xf0, 0xff, 0xff, 0x7a, 0x08, 0xeb, 0xfb, 0xff, 0xff, 0xdc, 0x60, 0x46, 0xc1, 0xff, 0xff, 0xfb, 0x19, 0x18, 0x1c, 0x38, 0x19, 0x18, 0xbe, 0x81, 0x85, 0xbe, 0xcc, 0x67, 0x48, 0x00, 0x0a, 0x31, 0x32, 0x38, 0xfc, 0xff, 0x2f, 0xf1, 0xec, 0xff, 0x7f, 0x69, 0x06, 0x86, 0x05, 0x40, 0xfe, 0x3f, 0x90, 0x10, 0x83, 0xc0, 0xef, 0xff, 0x40, 0xa0, 0x0d, 0xd2, 0xb7, 0x11, 0xc8, 0xd8, 0xcf, 0x04, 0x62, 0x81, 0x04, 0x75, 0x20, 0xa6, 0x6e, 0xfa, 0x7f, 0x9e, 0x19, 0xc2, 0x52, 0xf8, 0x6d, 0x03, 0x73, 0xc7, 0x62, 0x16, 0x30, 0x05, 0x00, -}; diff --git a/core/embed/bootloader/icon_done.h b/core/embed/bootloader/icon_done.h deleted file mode 100644 index a7cdb382d..000000000 --- a/core/embed/bootloader/icon_done.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_done[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x40, 0x00, 0x40, 0x00, - // compressed data length (32-bit) - 0xce, 0x00, 0x00, 0x00, - // compressed data - 0x63, 0x60, 0x18, 0x05, 0x23, 0x0f, 0x4c, 0xe0, 0xc6, 0x2f, 0xff, 0xfb, 0x3e, 0x7e, 0xed, 0xff, 0xff, 0x4b, 0xe3, 0x93, 0xff, 0xf5, 0xff, 0xff, 0x79, 0xfc, 0xda, 0xff, 0xff, 0xe7, 0xc1, 0x2d, 0xff, 0x03, 0x24, 0xbf, 0x1f, 0xa7, 0xf4, 0x82, 0xff, 0x60, 0xc0, 0x89, 0x57, 0xfb, 0xff, 0xfb, 0x78, 0x6d, 0xff, 0xff, 0x5f, 0x17, 0xbf, 0xf6, 0xf7, 0x8c, 0x38, 0xa4, 0x1b, 0x88, 0xd3, 0xce, 0x84, 0x5f, 0xbb, 0x2c, 0x86, 0xab, 0xa4, 0xf1, 0x6b, 0x87, 0xc6, 0x08, 0xd4, 0xf1, 0x72, 0x58, 0x3c, 0x25, 0x03, 0xa2, 0xbf, 0x43, 0xfc, 0x8e, 0xa1, 0xfd, 0x27, 0x24, 0x46, 0xa0, 0xb6, 0xeb, 0x61, 0x0d, 0x52, 0x59, 0x98, 0xf6, 0xf7, 0xd8, 0xb4, 0x83, 0x62, 0xa4, 0x00, 0x87, 0xdf, 0xa1, 0xc6, 0xf2, 0x7d, 0x83, 0xd0, 0xcc, 0xe8, 0xf2, 0x06, 0xff, 0x20, 0xce, 0xc2, 0x61, 0x3b, 0x03, 0xc3, 0xe7, 0xff, 0x48, 0x80, 0x19, 0x53, 0xde, 0x00, 0x49, 0x5a, 0x1e, 0x5b, 0xb0, 0x3e, 0x86, 0x4b, 0xbf, 0x67, 0xc6, 0x26, 0x8f, 0x30, 0x40, 0x1f, 0x7b, 0xbc, 0x3c, 0xc5, 0xab, 0x1d, 0x61, 0x80, 0x3d, 0xae, 0x78, 0xff, 0x8a, 0xd3, 0xf1, 0xc8, 0x06, 0xd8, 0xe3, 0x4e, 0xf5, 0x9f, 0xf1, 0x6a, 0x67, 0x60, 0x08, 0x00, 0x4a, 0xfb, 0x33, 0xe0, 0x01, 0x4f, 0xfe, 0xff, 0x67, 0xc1, 0x27, 0x9f, 0x80, 0x5f, 0x3b, 0x03, 0xc3, 0x15, 0x16, 0x86, 0x51, 0x30, 0xc2, 0x00, 0x00, -}; diff --git a/core/embed/bootloader/icon_fail.h b/core/embed/bootloader/icon_fail.h deleted file mode 100644 index e11530a1d..000000000 --- a/core/embed/bootloader/icon_fail.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_fail[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x40, 0x00, 0x40, 0x00, - // compressed data length (32-bit) - 0x21, 0x01, 0x00, 0x00, - // compressed data - 0xed, 0x52, 0x39, 0x12, 0x82, 0x40, 0x10, 0x44, 0x17, 0x88, 0x7d, 0x82, 0x1f, 0xd0, 0xe2, 0x05, 0x2e, 0x0f, 0xb0, 0x84, 0x1f, 0xc0, 0x0f, 0x7c, 0xa2, 0x89, 0xb9, 0x55, 0xfe, 0xc0, 0x23, 0xdf, 0xc0, 0x23, 0xd1, 0x62, 0x14, 0xd8, 0x65, 0xf6, 0xe8, 0x22, 0x36, 0xb0, 0xa3, 0xae, 0x69, 0x66, 0xd8, 0x9e, 0xe9, 0x28, 0xfa, 0xe3, 0x27, 0x30, 0x5f, 0x33, 0xdf, 0x4f, 0x43, 0xfd, 0x44, 0xa9, 0xa1, 0x35, 0x2d, 0xc3, 0xf6, 0x86, 0x0a, 0xc3, 0xef, 0xa4, 0x82, 0x01, 0x47, 0x22, 0x4a, 0x7a, 0x5a, 0x7e, 0xe9, 0x22, 0x6c, 0x27, 0xaa, 0x7a, 0xfe, 0xf8, 0x52, 0x7f, 0x40, 0xdb, 0x4e, 0x14, 0xb7, 0x34, 0xef, 0xa8, 0x3b, 0x60, 0xd6, 0x74, 0xc5, 0x6d, 0xcb, 0x9f, 0x1d, 0x55, 0x13, 0x5b, 0x3f, 0x13, 0x99, 0x01, 0xb9, 0xa6, 0x8e, 0x85, 0x97, 0x2e, 0x16, 0xed, 0xe3, 0x7b, 0xec, 0x6c, 0xfd, 0xa6, 0x8b, 0x94, 0xd6, 0x86, 0x49, 0x5b, 0x37, 0x43, 0xa9, 0x30, 0xed, 0xfd, 0x5b, 0x07, 0x5c, 0x74, 0x55, 0x35, 0x9a, 0xac, 0x5c, 0x7f, 0x19, 0x79, 0x10, 0xde, 0x82, 0xae, 0xae, 0xbc, 0xf1, 0xf7, 0x9b, 0x8d, 0xb7, 0xb3, 0x2f, 0xe3, 0x33, 0x18, 0xd0, 0xb0, 0xac, 0x04, 0x08, 0xc8, 0x8d, 0x75, 0x89, 0x02, 0x94, 0x0f, 0x03, 0x54, 0x0c, 0x13, 0x66, 0x76, 0xe0, 0x7b, 0x0f, 0x2c, 0x6e, 0xa0, 0x5c, 0xf3, 0xff, 0x53, 0xa4, 0xdf, 0x47, 0xed, 0xf1, 0x89, 0xc2, 0xe3, 0x44, 0x1c, 0x1b, 0x8d, 0xed, 0x78, 0x3b, 0x18, 0xf0, 0x70, 0xf5, 0xca, 0x93, 0x4b, 0xff, 0xbe, 0x31, 0x5e, 0xee, 0x90, 0x0f, 0x89, 0xdb, 0xe5, 0x70, 0x85, 0x04, 0x7a, 0x4f, 0x4a, 0xb8, 0x83, 0x77, 0x98, 0xef, 0x03, 0xfa, 0xbd, 0xe0, 0x20, 0x49, 0x90, 0xae, 0xca, 0x72, 0x2a, 0xc0, 0x6d, 0x05, 0x7f, 0x8b, 0xf2, 0x5d, 0x59, 0xab, 0x12, 0x20, 0x1c, 0x31, 0xaf, 0x7a, 0x05, 0xf2, 0x2d, 0xad, 0xd7, 0x0a, 0x10, 0xcf, 0x84, 0xb7, 0x05, 0x02, 0x9a, 0xad, 0x99, 0xef, 0x45, 0xf4, 0xc7, 0x6f, 0xe0, 0x03, -}; diff --git a/core/embed/bootloader/icon_info.h b/core/embed/bootloader/icon_info.h deleted file mode 100644 index d1e22b2a1..000000000 --- a/core/embed/bootloader/icon_info.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_info[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x20, 0x00, 0x20, 0x00, - // compressed data length (32-bit) - 0xde, 0x00, 0x00, 0x00, - // compressed data - 0x7d, 0x91, 0x3d, 0x0a, 0xc2, 0x40, 0x10, 0x85, 0x27, 0x10, 0xfc, 0x05, 0xe3, 0x0d, 0xbc, 0x82, 0xa0, 0x07, 0x10, 0x3c, 0x80, 0xde, 0x20, 0xf6, 0x22, 0xd8, 0x5b, 0xc4, 0xde, 0x42, 0x6f, 0x60, 0x67, 0x91, 0x46, 0x4b, 0x3b, 0xc5, 0x0b, 0xe4, 0x06, 0xba, 0x17, 0x10, 0x21, 0x10, 0x45, 0x89, 0x3e, 0x37, 0x3b, 0xbb, 0xa8, 0xab, 0x38, 0xc5, 0xce, 0x7e, 0x30, 0x3b, 0xb3, 0xf3, 0x1e, 0x91, 0x8c, 0xfa, 0xfa, 0xb8, 0x9f, 0xb8, 0x64, 0x62, 0x0c, 0x15, 0x45, 0x8d, 0x3d, 0xe8, 0x28, 0x30, 0xa7, 0xc0, 0xa8, 0xd9, 0x5e, 0x00, 0x07, 0x85, 0x02, 0xc8, 0xeb, 0xb2, 0x5a, 0x96, 0x1f, 0x28, 0x73, 0xdd, 0x0c, 0x70, 0x88, 0x56, 0x08, 0x4c, 0xdf, 0x04, 0x15, 0xa2, 0xb3, 0xaa, 0x4e, 0x96, 0xf2, 0xe8, 0x62, 0x4a, 0x84, 0x8d, 0xbc, 0x55, 0x81, 0x9c, 0x4c, 0x57, 0x38, 0x43, 0x78, 0xf2, 0xd2, 0xe2, 0xe9, 0x02, 0x45, 0xc1, 0x53, 0x01, 0x57, 0x3d, 0xf0, 0x62, 0xa8, 0x56, 0xbb, 0x81, 0x4a, 0xf0, 0x2f, 0x11, 0xbd, 0xc5, 0x6d, 0x7e, 0x0b, 0xde, 0x39, 0x89, 0x52, 0x9f, 0x5e, 0xfd, 0x29, 0x3e, 0xdd, 0x3b, 0xff, 0xd9, 0xae, 0xe7, 0x7e, 0x86, 0x93, 0x88, 0xe7, 0x19, 0xbe, 0xce, 0xf9, 0x3f, 0x86, 0xe1, 0x0b, 0xb5, 0x9e, 0x66, 0xf9, 0x5f, 0xde, 0x47, 0xb3, 0x40, 0xc9, 0xde, 0x57, 0xeb, 0x11, 0x86, 0xae, 0xd6, 0x63, 0x6b, 0xe9, 0x65, 0xeb, 0xf9, 0xa5, 0x77, 0xe6, 0x47, 0xbf, 0xd9, 0x90, 0x7e, 0x9c, 0x9c, 0x9f, 0x7e, 0xd9, 0x7e, 0x7e, 0xf8, 0xfd, 0x04, -}; diff --git a/core/embed/bootloader/icon_install.h b/core/embed/bootloader/icon_install.h deleted file mode 100644 index 6b4eb2b9e..000000000 --- a/core/embed/bootloader/icon_install.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_install[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x40, 0x00, 0x40, 0x00, - // compressed data length (32-bit) - 0xb8, 0x00, 0x00, 0x00, - // compressed data - 0x63, 0x60, 0x18, 0x05, 0xa3, 0x80, 0x58, 0xe0, 0xec, 0xe2, 0x62, 0x82, 0x4f, 0xfe, 0xcf, 0xff, 0xff, 0xe7, 0x47, 0xe5, 0xc9, 0x93, 0x3f, 0x85, 0x90, 0x5f, 0x83, 0x45, 0x7a, 0xc1, 0x7f, 0x5e, 0x98, 0xfc, 0x85, 0xff, 0x5c, 0x98, 0xf2, 0xbf, 0xfe, 0xef, 0x87, 0xc9, 0xff, 0xfe, 0xbf, 0x1e, 0x43, 0xfa, 0xc0, 0xff, 0xff, 0x40, 0x03, 0xc0, 0xf2, 0x17, 0x80, 0x4c, 0x1e, 0x74, 0x79, 0x07, 0xa0, 0xe0, 0x79, 0x46, 0x90, 0xbc, 0x00, 0x90, 0xf8, 0xcf, 0x82, 0x61, 0xc0, 0x17, 0xa0, 0xa8, 0x2e, 0x48, 0xfe, 0x12, 0x90, 0xe1, 0x8f, 0x69, 0xbf, 0x02, 0x50, 0xf8, 0xfd, 0x3f, 0x08, 0xfe, 0xcf, 0x84, 0xc5, 0x03, 0x20, 0x03, 0xa0, 0xc0, 0x1f, 0x9b, 0xff, 0x15, 0x10, 0xf2, 0x4c, 0x58, 0x03, 0xe8, 0x13, 0x4c, 0x5a, 0x1f, 0x7b, 0x00, 0x1a, 0xc0, 0xe4, 0x99, 0x71, 0x84, 0xf0, 0x63, 0x88, 0xb4, 0x1e, 0xae, 0x18, 0x50, 0x00, 0x39, 0xfd, 0xff, 0x7b, 0x26, 0x9c, 0xd1, 0x77, 0x11, 0x24, 0x2f, 0x8b, 0x3b, 0x7a, 0x05, 0xfe, 0xfe, 0xff, 0x7f, 0x9f, 0x11, 0x4f, 0xfc, 0x1f, 0xfc, 0xff, 0x5f, 0x86, 0x01, 0x6f, 0x02, 0xc1, 0x9b, 0x7c, 0x80, 0x06, 0xe0, 0xd7, 0xce, 0x20, 0xc0, 0xc8, 0x30, 0x0a, 0x46, 0x01, 0xf1, 0x00, 0x00, -}; diff --git a/core/embed/bootloader/icon_logo.h b/core/embed/bootloader/icon_logo.h deleted file mode 100644 index fc2e93b5e..000000000 --- a/core/embed/bootloader/icon_logo.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_logo[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0xf0, 0x00, 0xf0, 0x00, - // compressed data length (32-bit) - 0x85, 0x04, 0x00, 0x00, - // compressed data - 0xed, 0x92, 0x4f, 0x68, 0x5c, 0x45, 0x1c, 0xc7, 0x7f, 0xbb, 0x2f, 0xdb, 0xdd, 0xf4, 0x9f, 0x0b, 0xb6, 0xd4, 0x3f, 0x11, 0x16, 0x2f, 0x0d, 0x05, 0x49, 0xda, 0x85, 0x22, 0xa9, 0x74, 0x17, 0x5c, 0x3c, 0xf4, 0xb2, 0x11, 0x0f, 0xe2, 0xa1, 0x6c, 0x15, 0x8c, 0xc7, 0x06, 0x45, 0x0a, 0x82, 0x58, 0x73, 0x8a, 0x5e, 0x12, 0xd4, 0x83, 0x37, 0xe3, 0x45, 0x70, 0xb1, 0xb4, 0x17, 0x2f, 0x22, 0x26, 0xa2, 0xde, 0x84, 0x67, 0x0a, 0x22, 0x8a, 0x18, 0x9b, 0x22, 0x7a, 0x10, 0x5e, 0x6c, 0xbb, 0x8d, 0xf9, 0xf3, 0x76, 0x9c, 0xf9, 0xcd, 0xbc, 0xf7, 0xf6, 0x6d, 0x92, 0x65, 0xdd, 0xe7, 0xce, 0x56, 0xf8, 0x7e, 0x0e, 0x3b, 0xbf, 0x99, 0xf9, 0xed, 0x7c, 0xde, 0xcc, 0xef, 0x47, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x2c, 0xf9, 0x81, 0x58, 0x5f, 0xf9, 0x49, 0x88, 0x2b, 0xa7, 0xad, 0x6b, 0xbf, 0x69, 0x0a, 0x89, 0x77, 0xc6, 0xb2, 0x76, 0x41, 0x18, 0x72, 0x56, 0xb5, 0x05, 0x3f, 0xf0, 0x2e, 0xa6, 0x6c, 0x7a, 0x6f, 0x8a, 0x90, 0xc7, 0x6c, 0x76, 0xb2, 0x1f, 0x79, 0xdd, 0xd4, 0x00, 0xaa, 0xab, 0xc8, 0xda, 0xf3, 0x36, 0xf8, 0xa2, 0x6f, 0xbd, 0xcf, 0xd7, 0x1e, 0xb3, 0xe7, 0x6d, 0x4a, 0xdd, 0x8a, 0x43, 0x54, 0x56, 0x81, 0x6b, 0x4d, 0x5b, 0x56, 0xd7, 0x3c, 0xa0, 0xa2, 0x2f, 0x55, 0x94, 0xb6, 0xe5, 0x9d, 0x57, 0xd7, 0xe5, 0xa8, 0xd0, 0xb4, 0x59, 0xe0, 0x6b, 0x52, 0x56, 0x8a, 0x2a, 0xbd, 0xdf, 0x96, 0x77, 0x59, 0xca, 0x0e, 0xe9, 0x70, 0x4d, 0x86, 0x07, 0x6d, 0x79, 0xaf, 0x4b, 0xd9, 0xb0, 0x0e, 0x97, 0x64, 0x38, 0x62, 0xcb, 0xbb, 0x2a, 0x65, 0xb9, 0xe8, 0xc9, 0xe1, 0xed, 0x63, 0x7d, 0xad, 0x7b, 0x4f, 0x56, 0x2a, 0xbf, 0x49, 0xd9, 0x44, 0x85, 0xf9, 0x4a, 0x86, 0xe7, 0x2b, 0x15, 0xa7, 0xff, 0xde, 0x86, 0xd8, 0x85, 0xd2, 0x80, 0xbc, 0x67, 0xe1, 0x85, 0xf7, 0xff, 0xeb, 0xbd, 0x7a, 0xa9, 0x85, 0x2d, 0x7b, 0xde, 0x6a, 0xeb, 0xc2, 0x3a, 0xbc, 0xf0, 0xc2, 0x0b, 0x2f, 0xbc, 0xf0, 0xc2, 0x0b, 0xef, 0x7f, 0xef, 0xad, 0x0d, 0xc8, 0xeb, 0x1e, 0x8d, 0xe6, 0x2f, 0xf8, 0xf6, 0xbc, 0x62, 0xe5, 0x81, 0x60, 0xfa, 0x8e, 0xd2, 0x5a, 0xf3, 0x0a, 0x91, 0xd3, 0xb3, 0x0f, 0xf5, 0xcc, 0x9e, 0x57, 0x8c, 0xaa, 0xc9, 0xbb, 0xc2, 0xba, 0xd7, 0x3b, 0x47, 0xf4, 0xa9, 0x89, 0x45, 0xa9, 0xff, 0xde, 0xeb, 0x81, 0x4b, 0x3c, 0xf1, 0x7d, 0x18, 0x3e, 0xdc, 0x7f, 0x2f, 0x7d, 0x2d, 0xda, 0xf1, 0xce, 0x90, 0x0d, 0xde, 0x6b, 0xd7, 0x3e, 0x4e, 0x76, 0x98, 0x89, 0x7b, 0x8f, 0x91, 0x2d, 0xe6, 0x5b, 0x6f, 0x9b, 0x25, 0x7b, 0xbc, 0xe9, 0x07, 0x5a, 0xf7, 0x18, 0xd9, 0xe4, 0x69, 0x23, 0x5e, 0x3c, 0x42, 0x76, 0x29, 0xb3, 0xd8, 0x75, 0xc8, 0x36, 0x93, 0x5b, 0x42, 0x7c, 0x31, 0x44, 0xf6, 0x19, 0xdf, 0x98, 0x73, 0x68, 0x10, 0xe4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7b, 0x88, 0x0b, 0x97, 0x22, 0x8e, 0xd3, 0xcb, 0x26, 0x3a, 0xca, 0x7b, 0xd1, 0xce, 0xb3, 0xad, 0x79, 0x2f, 0xf1, 0x66, 0xf9, 0x47, 0x21, 0xae, 0x64, 0xf4, 0x21, 0xaf, 0x9a, 0x0d, 0xa7, 0x7b, 0xef, 0x77, 0x22, 0xa2, 0x4a, 0x77, 0x82, 0xf0, 0xf5, 0x94, 0xdc, 0x8b, 0x76, 0x5c, 0xba, 0x11, 0x4d, 0x3c, 0xf5, 0xbf, 0x19, 0x1d, 0x4f, 0xf0, 0x21, 0xdb, 0xc1, 0xd6, 0x44, 0xd7, 0xde, 0xa5, 0xdd, 0xbd, 0xe2, 0x7c, 0x67, 0xef, 0xe5, 0x60, 0x72, 0x42, 0x1d, 0xb2, 0x15, 0xee, 0x3d, 0x94, 0xd4, 0x2b, 0xb2, 0x9d, 0xbc, 0x79, 0x3f, 0x9c, 0x64, 0x62, 0x5e, 0x2f, 0x95, 0xd4, 0x5b, 0xed, 0xe4, 0xbd, 0x15, 0xcd, 0x6a, 0x31, 0xaf, 0x38, 0x98, 0xd4, 0xeb, 0xa6, 0xf6, 0xf6, 0x46, 0xd7, 0x95, 0x0c, 0xc5, 0xbc, 0xb5, 0x64, 0x7d, 0xc5, 0xe7, 0xed, 0xe1, 0x75, 0x69, 0xa1, 0x25, 0x4d, 0x1c, 0x8e, 0x79, 0xdd, 0x2e, 0xbd, 0xd3, 0xb3, 0xb3, 0xb3, 0x7f, 0xc8, 0xfc, 0x39, 0x39, 0x8e, 0xb2, 0xf7, 0xb9, 0xa9, 0xa9, 0x1f, 0xd4, 0x09, 0xc3, 0xca, 0xeb, 0xbd, 0x38, 0xa5, 0x78, 0x8a, 0xf3, 0x74, 0xa6, 0xb8, 0x4f, 0x7f, 0xde, 0x9c, 0x53, 0xf8, 0x5d, 0x8d, 0x8b, 0xda, 0x2b, 0x13, 0x37, 0xd4, 0x34, 0xd5, 0x75, 0x4b, 0xd3, 0x35, 0x3e, 0x4c, 0xa1, 0x0e, 0x54, 0x8d, 0xb2, 0xce, 0x95, 0x92, 0x3f, 0x2b, 0xf1, 0xcc, 0x86, 0x7e, 0x88, 0xa6, 0xfc, 0xfd, 0x80, 0x4c, 0x9e, 0x70, 0xd8, 0x4b, 0xa6, 0xdb, 0x32, 0xbd, 0x7a, 0xf7, 0xc9, 0x71, 0x99, 0xdf, 0x6f, 0x87, 0x77, 0x5c, 0x09, 0xe7, 0x68, 0x52, 0xd9, 0x72, 0x6a, 0x61, 0x52, 0x3f, 0x8c, 0xf1, 0xd2, 0x5d, 0x39, 0x66, 0x93, 0x78, 0xf5, 0xca, 0x0e, 0xaf, 0x5a, 0x16, 0x87, 0x78, 0x30, 0x1b, 0x7f, 0xcb, 0x70, 0x24, 0xf4, 0x36, 0x82, 0xef, 0x49, 0x7c, 0x5f, 0xef, 0x54, 0x51, 0x71, 0xbf, 0x4e, 0xe4, 0x67, 0x4d, 0xf3, 0x6e, 0x49, 0xaf, 0xfc, 0x2a, 0xc3, 0xb1, 0xd0, 0xbb, 0x9e, 0xe4, 0xbe, 0xb2, 0x40, 0xf9, 0xcd, 0xa0, 0xbe, 0x86, 0x8b, 0x14, 0xbe, 0x6a, 0x95, 0xe8, 0xa6, 0xee, 0x62, 0xc5, 0x65, 0x19, 0xd6, 0x02, 0x6f, 0xb9, 0xc9, 0xd5, 0xef, 0xd1, 0xfb, 0x49, 0xbd, 0xfe, 0xa7, 0x2e, 0x60, 0xbb, 0x77, 0xd5, 0xd4, 0xf5, 0x0e, 0x17, 0x35, 0xfc, 0x94, 0x37, 0xd8, 0x5b, 0xaf, 0x7f, 0xe6, 0x27, 0xea, 0xe7, 0x00, 0x67, 0x87, 0x57, 0x1d, 0xef, 0xa6, 0x74, 0x19, 0xcd, 0x73, 0x96, 0xb9, 0xb3, 0xb7, 0xa2, 0xcc, 0x45, 0x4a, 0xe8, 0x95, 0x07, 0xb4, 0x79, 0xa7, 0x85, 0xa9, 0x6b, 0xc3, 0x74, 0x81, 0xea, 0xf0, 0x76, 0x6f, 0x35, 0xa9, 0x77, 0x6c, 0x87, 0x97, 0x37, 0x33, 0xd4, 0xf9, 0xbe, 0xc3, 0x49, 0xbd, 0xe9, 0x76, 0x6f, 0x5e, 0xb0, 0xc3, 0x64, 0xed, 0x6f, 0xaf, 0xef, 0xbf, 0x7f, 0xe6, 0xdd, 0xbc, 0xde, 0x09, 0xd2, 0xde, 0x8f, 0xeb, 0x8a, 0x73, 0x26, 0x4b, 0x3c, 0xa2, 0xb2, 0x5a, 0xfa, 0x79, 0x9e, 0x9f, 0x36, 0xf4, 0xae, 0x64, 0x13, 0x7a, 0xf9, 0xbb, 0xd5, 0x41, 0x51, 0xd6, 0xba, 0x6e, 0x36, 0xc9, 0xb2, 0x0c, 0x6a, 0x7a, 0x71, 0x8d, 0x2b, 0x12, 0x7a, 0x4b, 0xd4, 0xbb, 0xf7, 0xf8, 0x8c, 0xba, 0x6f, 0xba, 0xdd, 0x5b, 0x10, 0xfc, 0xa4, 0x41, 0xbe, 0xa7, 0x57, 0x37, 0x65, 0x38, 0xc2, 0xde, 0x47, 0x57, 0x83, 0x32, 0xf4, 0xe8, 0xcd, 0x50, 0xd3, 0xf4, 0x47, 0xcc, 0x7b, 0x43, 0x84, 0x55, 0x9d, 0x0c, 0xc3, 0x0b, 0x2a, 0xca, 0xb1, 0x97, 0x5b, 0xcc, 0x73, 0x7a, 0xf7, 0xee, 0xa3, 0xdb, 0xe6, 0xc5, 0x62, 0x5e, 0x75, 0xb6, 0x6b, 0x62, 0x5f, 0x55, 0x42, 0x2a, 0xf2, 0x1b, 0xba, 0x03, 0xd9, 0xcb, 0xbf, 0x07, 0x92, 0x78, 0x17, 0x8c, 0x50, 0x1d, 0xca, 0x6d, 0x55, 0x7f, 0x5b, 0xdf, 0xcc, 0xfb, 0x56, 0xf1, 0x39, 0x7f, 0x98, 0x70, 0x4f, 0x3f, 0xb3, 0x69, 0x5a, 0x5c, 0x7b, 0x6f, 0x47, 0x65, 0xef, 0xcd, 0x3b, 0x2e, 0x78, 0x20, 0x11, 0xe2, 0xea, 0x67, 0x36, 0xbd, 0xce, 0x5d, 0x1c, 0x72, 0x38, 0xf0, 0xaa, 0xcf, 0x15, 0x49, 0xbc, 0xdc, 0x2d, 0x63, 0x1d, 0xbc, 0xf9, 0xed, 0x96, 0x59, 0x3a, 0xf0, 0xf2, 0xe7, 0x0e, 0x27, 0xf1, 0xde, 0xd2, 0xcf, 0xb7, 0xa7, 0xb7, 0x75, 0x56, 0xa5, 0xc0, 0xcb, 0x9f, 0x7b, 0x36, 0x89, 0x97, 0xdf, 0xd1, 0xe9, 0xe0, 0xa5, 0xf0, 0xc2, 0xdc, 0xc1, 0xc6, 0xbb, 0x26, 0x87, 0xab, 0x49, 0xbc, 0xd4, 0xe4, 0xd6, 0xec, 0xe0, 0x9d, 0xf6, 0x4d, 0xfc, 0x20, 0x45, 0x5e, 0xee, 0xbd, 0xa1, 0xee, 0xbd, 0x4b, 0xa1, 0xb7, 0x61, 0xbc, 0x77, 0xe5, 0x78, 0x31, 0xe6, 0xfd, 0x2b, 0xee, 0xa5, 0xe7, 0x59, 0xec, 0x8d, 0xf2, 0xdf, 0xb6, 0xb5, 0x37, 0xef, 0x87, 0x07, 0x75, 0x45, 0xa1, 0x58, 0x2c, 0xea, 0xcf, 0x3c, 0x59, 0x2c, 0x3e, 0x99, 0x92, 0xe3, 0xb8, 0x5c, 0x29, 0x52, 0x31, 0x42, 0xaf, 0x04, 0x13, 0x45, 0xfe, 0xa3, 0x9f, 0x7f, 0x79, 0x2d, 0xad, 0x0f, 0x38, 0x65, 0x16, 0xd5, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x99, 0x7f, 0x00, -}; diff --git a/core/embed/bootloader/icon_safeplace.h b/core/embed/bootloader/icon_safeplace.h deleted file mode 100644 index 1089f3781..000000000 --- a/core/embed/bootloader/icon_safeplace.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_safeplace[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0xc8, 0x00, 0x3c, 0x00, - // compressed data length (32-bit) - 0xc3, 0x04, 0x00, 0x00, - // compressed data - 0xed, 0x92, 0x4f, 0x68, 0x1b, 0x47, 0x14, 0xc6, 0x47, 0xb2, 0x64, 0xcb, 0x52, 0xf4, 0xe7, 0x50, 0x68, 0x7b, 0xb2, 0xd9, 0x5c, 0x5a, 0x0a, 0xb1, 0x29, 0xee, 0xc1, 0x50, 0xf0, 0x52, 0x02, 0x2d, 0x24, 0x35, 0x02, 0x1d, 0x4b, 0x88, 0xa1, 0xd7, 0x12, 0x09, 0x72, 0x2d, 0x58, 0xa5, 0xc7, 0xc6, 0xd8, 0x49, 0xce, 0x4d, 0x74, 0xce, 0xc5, 0xbe, 0xb8, 0x97, 0x42, 0xe4, 0xd2, 0x86, 0xe6, 0x54, 0x39, 0x07, 0x1f, 0x0a, 0x4d, 0xa5, 0x43, 0x48, 0x8b, 0x93, 0x46, 0x8a, 0xfc, 0xdf, 0xd6, 0xee, 0x97, 0xf7, 0x66, 0x67, 0xb4, 0x23, 0xaf, 0xac, 0xb8, 0x71, 0xe5, 0x4b, 0xfd, 0x40, 0x9a, 0xdd, 0xf7, 0xbe, 0x79, 0xbf, 0x9d, 0x79, 0x9f, 0x10, 0x7e, 0x34, 0x90, 0x16, 0xaf, 0x8b, 0x65, 0xf7, 0x5a, 0xb7, 0x34, 0xd0, 0x7b, 0x5b, 0x03, 0x5e, 0xa4, 0x8f, 0xc1, 0x28, 0x01, 0xf3, 0xfd, 0x66, 0x6c, 0x9f, 0x02, 0xa3, 0x85, 0x4b, 0xe7, 0xdf, 0x84, 0x31, 0x6a, 0x59, 0x4d, 0x8c, 0x59, 0x56, 0xf8, 0x18, 0x0c, 0x17, 0x21, 0xf1, 0x26, 0x8c, 0xf6, 0xb4, 0x8f, 0xc1, 0x38, 0xaa, 0xd7, 0xbf, 0x61, 0x3c, 0xc0, 0x57, 0xf4, 0x30, 0xf3, 0xac, 0xfe, 0x85, 0xaa, 0xdc, 0x72, 0xea, 0x5f, 0xd3, 0xa7, 0x67, 0x7e, 0x75, 0x2b, 0xef, 0x70, 0x2b, 0xb0, 0xf2, 0x07, 0xf7, 0x7e, 0x54, 0xf5, 0x2e, 0xdf, 0x74, 0xef, 0x84, 0x3c, 0x86, 0xd2, 0x08, 0x7b, 0x1d, 0x73, 0x7c, 0x5a, 0x5f, 0xd5, 0xc1, 0x58, 0xa4, 0x1e, 0x09, 0x91, 0x71, 0xe4, 0xc2, 0x51, 0xe0, 0xae, 0xd3, 0x42, 0x3c, 0xe1, 0x75, 0x50, 0x31, 0x1e, 0xd1, 0x7f, 0x59, 0x31, 0xea, 0x2e, 0x70, 0xc1, 0x63, 0x28, 0x8d, 0xd8, 0xf3, 0xb6, 0x18, 0xaa, 0x0e, 0x06, 0xc7, 0x55, 0xb1, 0xca, 0xcb, 0x5d, 0x59, 0xd8, 0x92, 0xa9, 0xf0, 0xb8, 0x5c, 0xa6, 0x14, 0x83, 0x3f, 0x01, 0xc3, 0xea, 0x8e, 0x28, 0xaa, 0x92, 0xa1, 0x35, 0x45, 0x6f, 0x8b, 0xa9, 0xea, 0x60, 0x54, 0x3f, 0x5a, 0x23, 0xf6, 0x1e, 0xae, 0x7c, 0xe9, 0x92, 0x4a, 0xfa, 0xe8, 0x72, 0xce, 0x41, 0x7c, 0x09, 0xe5, 0x89, 0x35, 0x2c, 0x0a, 0x0b, 0xb0, 0xc2, 0x0b, 0x24, 0x7b, 0x8a, 0x31, 0xc5, 0xb8, 0x7c, 0x1d, 0x88, 0x32, 0x43, 0x6b, 0x9a, 0xc8, 0xe7, 0x5c, 0x0c, 0x9b, 0xaa, 0x0e, 0xc6, 0x08, 0x7d, 0x4d, 0x9d, 0x36, 0x84, 0xc4, 0x26, 0x62, 0xda, 0x47, 0x4d, 0xa4, 0x4a, 0x3f, 0x26, 0xc4, 0x28, 0x55, 0xe4, 0x9d, 0xb0, 0xcc, 0xc6, 0xbc, 0x62, 0x84, 0xc4, 0x2e, 0xe2, 0x9c, 0xd7, 0x9a, 0x5d, 0x0c, 0xd1, 0xee, 0x94, 0xa9, 0x3a, 0xec, 0x2b, 0xc0, 0x46, 0xd9, 0xb2, 0x36, 0x70, 0xce, 0x3b, 0x47, 0x4c, 0x49, 0x32, 0x16, 0xf7, 0xe7, 0xdf, 0x26, 0x3e, 0xb0, 0x3e, 0x44, 0xa5, 0xed, 0xa7, 0x0d, 0x24, 0x95, 0xaf, 0xa4, 0xc6, 0xa1, 0x1b, 0x28, 0xdd, 0x8b, 0x9b, 0xaa, 0x20, 0x63, 0x46, 0x5e, 0x28, 0x52, 0x5c, 0xd8, 0x04, 0xbe, 0x8b, 0x78, 0x5e, 0x81, 0x66, 0x6c, 0xcb, 0x72, 0xbd, 0xcd, 0xe0, 0x6d, 0xbc, 0x2a, 0x8d, 0xb2, 0xb1, 0xa9, 0x0a, 0x32, 0x0a, 0x1e, 0x83, 0x33, 0x62, 0xbc, 0x45, 0x4f, 0xef, 0x7b, 0x5e, 0xd1, 0x8c, 0x1d, 0xa8, 0x97, 0x43, 0x0c, 0xa5, 0x51, 0x15, 0x53, 0xd5, 0x9b, 0x21, 0xc6, 0x1f, 0xd2, 0xe3, 0x40, 0x01, 0xd5, 0xb7, 0xc4, 0x6b, 0x18, 0x5a, 0x73, 0x2c, 0x46, 0x96, 0xcc, 0x61, 0x84, 0xdd, 0x42, 0x62, 0x95, 0x0d, 0xa2, 0x19, 0x5b, 0x34, 0x63, 0x1d, 0xc6, 0x3c, 0xb4, 0x86, 0xe7, 0x61, 0x5f, 0x8c, 0x98, 0xaa, 0x20, 0x23, 0x43, 0x1f, 0x2e, 0xc4, 0xa0, 0x2c, 0xfc, 0xf1, 0x58, 0x88, 0x97, 0x6c, 0x92, 0x34, 0x79, 0x46, 0x31, 0x5e, 0x62, 0x4a, 0x88, 0x19, 0x61, 0xf8, 0x6a, 0x98, 0xf3, 0x5a, 0xc3, 0xbe, 0x22, 0x2b, 0x9a, 0xaa, 0x20, 0x83, 0x2e, 0x76, 0x76, 0xe2, 0x41, 0x59, 0x16, 0x0e, 0xc8, 0x57, 0x5b, 0x48, 0xd6, 0x50, 0x9e, 0xf8, 0x4b, 0x33, 0x16, 0x80, 0x4f, 0x73, 0xad, 0x84, 0x62, 0x7c, 0x7e, 0x1d, 0x88, 0x70, 0x5e, 0x6b, 0x9a, 0xc8, 0xe7, 0x1c, 0xc4, 0x4d, 0x55, 0x17, 0xc6, 0x23, 0x79, 0x93, 0x51, 0x2e, 0x6c, 0x00, 0xff, 0x00, 0x83, 0x45, 0x18, 0x33, 0xcf, 0x38, 0xfc, 0x7c, 0x55, 0x31, 0x28, 0x2a, 0x32, 0xaf, 0x35, 0xde, 0x1a, 0x36, 0x55, 0x5d, 0x18, 0x19, 0x36, 0xd3, 0xac, 0x37, 0x0c, 0x97, 0x1e, 0xe7, 0xf9, 0x3c, 0xa8, 0xbb, 0x74, 0x2f, 0x72, 0x88, 0x3f, 0xf1, 0xee, 0x21, 0xc5, 0xa0, 0x56, 0x17, 0x3c, 0xb6, 0xd6, 0xec, 0x53, 0x75, 0xba, 0x43, 0xd5, 0x85, 0x21, 0xb2, 0xcf, 0xea, 0x73, 0x61, 0xaf, 0xf2, 0xcd, 0x73, 0x7c, 0x4f, 0xd3, 0x99, 0x69, 0xd5, 0xdf, 0xdd, 0xa3, 0xa3, 0x79, 0x46, 0x59, 0x76, 0xff, 0x7c, 0x4f, 0xcf, 0xe3, 0xa6, 0x7b, 0x27, 0xe4, 0xed, 0xd2, 0x1a, 0x7b, 0x1d, 0x37, 0x42, 0x1d, 0xaa, 0x93, 0x85, 0x69, 0xce, 0x7e, 0xc5, 0x19, 0xe3, 0xff, 0xc7, 0x38, 0x8b, 0xb3, 0xe8, 0x19, 0xcb, 0xee, 0xb5, 0x93, 0xb6, 0xc8, 0xbe, 0x88, 0xf6, 0xac, 0x97, 0x80, 0xf9, 0x93, 0x32, 0x6a, 0x48, 0xf5, 0xac, 0x6f, 0x9f, 0x02, 0xa3, 0x85, 0x4b, 0xe7, 0xfb, 0x7d, 0x57, 0x2e, 0x42, 0x7d, 0x1f, 0x39, 0x70, 0x0a, 0x08, 0x20, 0x2d, 0xc4, 0x2d, 0xa7, 0x3a, 0x29, 0xdf, 0x8a, 0x6e, 0x4c, 0x0e, 0x29, 0xc9, 0x2f, 0x03, 0x2a, 0xdf, 0x60, 0x09, 0x7d, 0x0c, 0xad, 0x7f, 0x7b, 0xc3, 0xb3, 0xd7, 0x31, 0xc7, 0xe7, 0xf7, 0xeb, 0x28, 0xcf, 0x3c, 0xaf, 0xd2, 0xde, 0xd1, 0xdf, 0xf1, 0xdb, 0xdb, 0xdd, 0x18, 0x05, 0x5e, 0x62, 0xfc, 0x76, 0xc0, 0x0b, 0x6d, 0x1a, 0x13, 0x36, 0xea, 0x3a, 0xef, 0x33, 0xca, 0xca, 0x20, 0x7b, 0x94, 0x9f, 0x16, 0x66, 0x1d, 0xd5, 0x03, 0xa0, 0x22, 0xc4, 0x0e, 0x65, 0xea, 0x91, 0x2e, 0x0c, 0x2e, 0x60, 0xd6, 0x7b, 0x63, 0xc6, 0x12, 0xf2, 0xa2, 0x48, 0xed, 0x54, 0xde, 0x67, 0x28, 0x13, 0x16, 0x39, 0x8f, 0xb0, 0x59, 0x97, 0x19, 0x0c, 0x66, 0xe5, 0x32, 0xd6, 0xc1, 0xb0, 0x00, 0x2b, 0x9c, 0x01, 0x26, 0x6f, 0x83, 0x86, 0xaf, 0x19, 0x59, 0x94, 0xc5, 0x2a, 0xa6, 0x74, 0x3e, 0xc0, 0x68, 0x22, 0x9f, 0x73, 0x31, 0x6c, 0xd6, 0x81, 0x2b, 0x39, 0x07, 0x89, 0x15, 0x54, 0x26, 0xd6, 0xb0, 0x18, 0x9c, 0x79, 0x91, 0x93, 0xfb, 0xd4, 0x1d, 0xf8, 0xb8, 0x9d, 0x6d, 0x22, 0xa9, 0xf3, 0x3e, 0xa3, 0x32, 0x20, 0xcb, 0xbb, 0x18, 0x12, 0x9b, 0x48, 0x99, 0x75, 0xfe, 0xc4, 0x0d, 0xa4, 0x6a, 0x18, 0x11, 0xa3, 0x74, 0xcb, 0x01, 0xc6, 0x0a, 0xa6, 0x04, 0x09, 0xce, 0x49, 0xa1, 0x8c, 0x7d, 0x44, 0xb7, 0x11, 0xd3, 0x79, 0x9f, 0x31, 0xe2, 0x95, 0x1d, 0xba, 0xa7, 0xd2, 0xbd, 0xb8, 0x59, 0xe7, 0x3e, 0xb4, 0xae, 0xa8, 0x81, 0x05, 0x18, 0x35, 0xee, 0xd1, 0x40, 0xca, 0x37, 0xf2, 0x16, 0x86, 0x0f, 0x10, 0xd6, 0x79, 0xc3, 0x57, 0x1d, 0x86, 0x37, 0xeb, 0x8a, 0x61, 0x03, 0xe5, 0xcf, 0xba, 0x31, 0x1a, 0x9e, 0x36, 0xed, 0x33, 0x68, 0x23, 0xaa, 0xed, 0xfc, 0x51, 0x0c, 0xb3, 0xae, 0xfb, 0xfc, 0x4c, 0x33, 0xbb, 0x1b, 0x3e, 0x92, 0x61, 0x9c, 0xa3, 0x84, 0x59, 0xed, 0xa7, 0x1e, 0xe7, 0x68, 0x04, 0xcf, 0x21, 0xc4, 0xb7, 0x2d, 0xf0, 0x15, 0xf6, 0x98, 0x87, 0xca, 0xda, 0xd2, 0x80, 0xc1, 0x79, 0xa4, 0xfd, 0x79, 0xd8, 0x17, 0x23, 0x5d, 0xe6, 0xc1, 0xd5, 0x5f, 0xc8, 0x95, 0xbd, 0x7c, 0xa5, 0xd3, 0x2e, 0x08, 0xe9, 0xfb, 0x86, 0xcd, 0x62, 0x30, 0xd8, 0x57, 0xcd, 0xc3, 0xbe, 0xf2, 0x66, 0xfe, 0x38, 0x29, 0x32, 0xdd, 0x7c, 0xa5, 0x7d, 0x6e, 0x30, 0xf6, 0x40, 0x6d, 0x74, 0x9e, 0x4d, 0xff, 0xd4, 0x64, 0x34, 0x91, 0xcf, 0x39, 0x88, 0xeb, 0xba, 0xc1, 0x58, 0x22, 0x5f, 0x65, 0x69, 0x94, 0xd9, 0x17, 0x91, 0x4e, 0x86, 0xd8, 0xa1, 0xab, 0xa1, 0xfb, 0x37, 0x18, 0x9b, 0xd2, 0xc6, 0x2a, 0x5f, 0x80, 0x0c, 0x9f, 0x51, 0x94, 0xef, 0x61, 0x5d, 0x37, 0x18, 0xe3, 0x40, 0xd5, 0x45, 0x9e, 0x2c, 0x97, 0x3c, 0xc4, 0x90, 0x7b, 0x62, 0x26, 0xa3, 0x86, 0x8a, 0x91, 0x6f, 0xc9, 0x9d, 0x3e, 0x83, 0x2e, 0x08, 0x98, 0x6e, 0xd7, 0xcd, 0x79, 0x3c, 0xf1, 0x52, 0x41, 0x86, 0xb8, 0xed, 0x54, 0x27, 0x85, 0xc9, 0x58, 0xa0, 0x6f, 0xf1, 0xf3, 0x85, 0x56, 0x35, 0xd6, 0x32, 0x19, 0xf6, 0x3a, 0x6e, 0x84, 0xda, 0x75, 0x93, 0x91, 0x79, 0xe8, 0x72, 0xaa, 0xe3, 0xae, 0x8e, 0x88, 0x22, 0x8d, 0xb9, 0xdf, 0x51, 0x43, 0xa2, 0xdf, 0x88, 0x4f, 0x0e, 0x10, 0xed, 0x37, 0x83, 0x66, 0x2c, 0xfa, 0xcf, 0x98, 0xea, 0x3b, 0xc3, 0xb9, 0x3f, 0xf0, 0x5f, 0xb4, 0x79, 0x05, -}; diff --git a/core/embed/bootloader/icon_welcome.h b/core/embed/bootloader/icon_welcome.h deleted file mode 100644 index 097daf0ff..000000000 --- a/core/embed/bootloader/icon_welcome.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_welcome[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0xb4, 0x00, 0x1e, 0x00, - // compressed data length (32-bit) - 0x32, 0x03, 0x00, 0x00, - // compressed data - 0xc5, 0x52, 0xc1, 0x4e, 0x13, 0x51, 0x14, 0xbd, 0x50, 0xa0, 0x50, 0x2c, 0x74, 0xa7, 0x0b, 0x11, 0xbe, 0x80, 0xf2, 0x07, 0xf0, 0x07, 0xfa, 0x03, 0x06, 0x56, 0x6c, 0xdb, 0xb8, 0xc2, 0x15, 0x26, 0x2e, 0xd8, 0x90, 0x40, 0x22, 0x89, 0x1b, 0x05, 0x34, 0x26, 0xec, 0x6c, 0xf5, 0x03, 0x04, 0x75, 0xe1, 0xb2, 0xc4, 0x95, 0x3b, 0x4a, 0xe2, 0xc6, 0x28, 0x4e, 0x29, 0x50, 0x5a, 0xa0, 0x73, 0x3c, 0xf7, 0xbe, 0xe9, 0x74, 0x3a, 0x40, 0x62, 0xa4, 0x89, 0x77, 0x31, 0x73, 0xdf, 0x7b, 0xf7, 0x9c, 0x77, 0xdf, 0xb9, 0x47, 0xe4, 0x3f, 0x05, 0x30, 0x7b, 0x13, 0xf8, 0x11, 0xd0, 0xc7, 0xdf, 0x05, 0xb2, 0xfc, 0x56, 0x80, 0xc1, 0x9b, 0x31, 0x47, 0x30, 0x24, 0x4b, 0x86, 0x3b, 0x55, 0xa0, 0xbf, 0x6b, 0xcc, 0x3b, 0x40, 0x4a, 0x64, 0x06, 0xd8, 0xe0, 0xe2, 0x04, 0xe8, 0xe9, 0x1a, 0xf3, 0x2a, 0x90, 0x16, 0xc9, 0x03, 0x25, 0x2e, 0xea, 0xf0, 0xa4, 0x6b, 0xcc, 0x73, 0xc0, 0xa8, 0x48, 0x11, 0x00, 0x17, 0xe7, 0x28, 0x74, 0x8f, 0x79, 0x02, 0x98, 0x16, 0x29, 0x93, 0x39, 0x21, 0xe2, 0x63, 0xb1, 0x7b, 0xcc, 0xcc, 0x73, 0x36, 0x3a, 0x0e, 0x32, 0x63, 0xb7, 0x74, 0x8d, 0xf9, 0x5c, 0x67, 0xc7, 0xd1, 0x61, 0x58, 0xe7, 0x48, 0x65, 0xe4, 0xe9, 0x2f, 0x6f, 0x39, 0xd1, 0xae, 0x5a, 0x3b, 0xf0, 0x5e, 0x24, 0xac, 0x94, 0x07, 0x96, 0xd1, 0x4f, 0x3d, 0x6f, 0x9a, 0x7b, 0x77, 0x24, 0xf3, 0xc5, 0x7f, 0x1b, 0x1e, 0x45, 0x31, 0x16, 0x75, 0x9d, 0x5d, 0x83, 0xcc, 0x23, 0x3a, 0x47, 0x4e, 0xf3, 0x15, 0x73, 0xd3, 0xdb, 0x55, 0x7d, 0xb2, 0xa5, 0x5a, 0xe6, 0x9d, 0x66, 0xdb, 0x3d, 0xc6, 0xfc, 0x9a, 0xa9, 0x97, 0xd0, 0x86, 0x56, 0x94, 0x24, 0x86, 0x71, 0x71, 0xac, 0xb3, 0x6b, 0xa2, 0x89, 0xac, 0x6c, 0x02, 0x43, 0x92, 0x69, 0x6a, 0x15, 0xee, 0x06, 0x55, 0x53, 0xbe, 0x2d, 0xc7, 0x38, 0x11, 0x97, 0x4d, 0x1a, 0xb3, 0xe5, 0x0f, 0x6d, 0x63, 0x40, 0xe2, 0x98, 0x20, 0x0e, 0x81, 0x5e, 0x6e, 0xd4, 0xb8, 0xb5, 0xab, 0x65, 0xbb, 0x56, 0xa4, 0x0d, 0x58, 0xd5, 0xbe, 0x5b, 0x6e, 0x4b, 0xeb, 0x60, 0xcf, 0x98, 0x23, 0x31, 0x22, 0x71, 0x4c, 0x10, 0xb4, 0x45, 0x3f, 0x05, 0xfe, 0x4a, 0xb9, 0x2b, 0x7a, 0x49, 0x1d, 0x58, 0x5f, 0xf2, 0xd5, 0x2a, 0x56, 0x45, 0x9d, 0x96, 0xb7, 0x88, 0xea, 0xd3, 0x6c, 0xfd, 0xb9, 0xaf, 0xcf, 0x52, 0xe6, 0xc7, 0x3f, 0x54, 0x8f, 0x85, 0x33, 0xe0, 0xbe, 0xc4, 0x31, 0x41, 0x50, 0x82, 0xc1, 0x3c, 0xbc, 0x55, 0x36, 0x53, 0x55, 0x61, 0xac, 0xbf, 0x1d, 0x20, 0x65, 0x55, 0xb4, 0xcb, 0x86, 0x29, 0x96, 0x62, 0xc6, 0x81, 0x7c, 0x04, 0xc6, 0x95, 0x79, 0x52, 0x15, 0xc4, 0x2d, 0x99, 0x82, 0x1a, 0xb5, 0x13, 0xd3, 0x0a, 0x8e, 0x2d, 0x55, 0x44, 0xe1, 0x01, 0x59, 0x4f, 0x88, 0x9d, 0x53, 0xa8, 0x02, 0x46, 0xad, 0x2a, 0x6f, 0x76, 0xe1, 0xed, 0x69, 0x1e, 0x64, 0xed, 0x20, 0xa7, 0xcc, 0x14, 0xf7, 0x54, 0x5f, 0x48, 0xfe, 0x95, 0x38, 0xa6, 0x15, 0xdc, 0x48, 0x97, 0x91, 0x63, 0x4b, 0x7d, 0x75, 0x56, 0x6d, 0xea, 0xcd, 0xda, 0x45, 0xd6, 0xaa, 0x8a, 0xea, 0x46, 0x85, 0x8e, 0x6c, 0x6a, 0x8b, 0xca, 0x54, 0x50, 0xe6, 0x7e, 0x91, 0x9a, 0xbe, 0xd0, 0x4c, 0x1b, 0xc3, 0x44, 0xcc, 0x3d, 0x5a, 0xc5, 0xb4, 0xf8, 0x48, 0x9e, 0xbb, 0x29, 0xba, 0xb8, 0x6f, 0x55, 0x9c, 0xc2, 0xa0, 0x2b, 0xdb, 0x75, 0x59, 0x9d, 0xaa, 0x39, 0xe6, 0x93, 0x80, 0xb9, 0x10, 0xc7, 0x84, 0x71, 0x81, 0xe9, 0x1a, 0xdf, 0x71, 0x86, 0x61, 0x9f, 0x8f, 0x2a, 0xb7, 0xaa, 0x66, 0xad, 0xca, 0x3d, 0x5c, 0x83, 0x59, 0x52, 0x4c, 0x83, 0x4b, 0xcc, 0x31, 0x4c, 0x18, 0x0d, 0xe4, 0x1a, 0x7c, 0x72, 0x0d, 0xf7, 0xd4, 0x41, 0x95, 0x4b, 0xcc, 0xfd, 0x21, 0xb3, 0x66, 0x27, 0x57, 0x30, 0x57, 0xae, 0x61, 0xae, 0x61, 0xa3, 0xc9, 0x76, 0xaa, 0x58, 0x54, 0xb9, 0x2a, 0xff, 0xd0, 0xf3, 0x75, 0xcc, 0x55, 0xec, 0xa9, 0x5d, 0xcb, 0xfa, 0x4b, 0xea, 0xcb, 0x86, 0xc2, 0x01, 0xfc, 0xa5, 0xce, 0x11, 0x4c, 0x47, 0xd8, 0x8d, 0xa2, 0x2e, 0xd0, 0x0b, 0x8a, 0x2a, 0x49, 0x9b, 0xd9, 0x79, 0x63, 0x62, 0x7e, 0x7e, 0xa0, 0xe8, 0xbc, 0x71, 0x11, 0x7a, 0xa3, 0xcd, 0x1c, 0xc1, 0x74, 0x84, 0x52, 0x96, 0xcc, 0xd7, 0x5a, 0x9a, 0x57, 0xc3, 0x92, 0x6b, 0x40, 0x22, 0x7e, 0x7e, 0x42, 0x68, 0xde, 0xfc, 0x3c, 0x01, 0x2c, 0x5e, 0x62, 0x8e, 0x60, 0x3a, 0x82, 0x30, 0xfa, 0x58, 0x7d, 0xcd, 0x87, 0x4a, 0xc6, 0x3a, 0x97, 0xef, 0xb3, 0x8e, 0x39, 0x63, 0x67, 0x47, 0xec, 0x3c, 0x63, 0xf7, 0xef, 0x80, 0xfe, 0x89, 0x33, 0x47, 0x30, 0xab, 0xbf, 0x23, 0xba, 0xcc, 0xc0, 0xc9, 0xce, 0xdf, 0x86, 0x09, 0x89, 0xd2, 0xc2, 0x37, 0x2d, 0xb5, 0xed, 0x33, 0x60, 0x79, 0x0b, 0x4a, 0xd5, 0x00, 0xd6, 0x97, 0x7c, 0x95, 0x34, 0xce, 0x1c, 0xc1, 0x34, 0x8c, 0x23, 0x08, 0xbd, 0x71, 0xdc, 0x14, 0xb4, 0x37, 0xb5, 0x6c, 0x9f, 0x72, 0xcc, 0xfb, 0x6e, 0x55, 0x0a, 0x0f, 0x3c, 0xb9, 0xcc, 0xdc, 0xc6, 0xf8, 0x7a, 0x1e, 0x06, 0xfb, 0x48, 0xbb, 0x66, 0xa7, 0xf5, 0xa2, 0xa6, 0x15, 0x6d, 0x3b, 0x35, 0x4c, 0x24, 0xc6, 0x18, 0x65, 0xf4, 0x2d, 0x9b, 0xbc, 0x82, 0xb9, 0x8d, 0xe9, 0x64, 0x3e, 0x73, 0xa6, 0x39, 0xb6, 0x61, 0x51, 0x2a, 0xab, 0x4a, 0x06, 0xcc, 0xf2, 0x59, 0x57, 0x05, 0x3d, 0x78, 0x6f, 0xe8, 0xde, 0x2b, 0x98, 0xdb, 0x98, 0x0e, 0x35, 0xe4, 0x14, 0xd0, 0xa9, 0x1e, 0x3a, 0x5b, 0x89, 0x3c, 0xfa, 0x89, 0x0f, 0xb7, 0xa5, 0xc5, 0x2c, 0x6b, 0x07, 0xde, 0x72, 0xaf, 0x1d, 0x3c, 0x3b, 0xf0, 0x5e, 0xf6, 0xc9, 0x55, 0xcc, 0x21, 0x26, 0x98, 0xe0, 0x1f, -}; diff --git a/core/embed/bootloader/icon_wipe.h b/core/embed/bootloader/icon_wipe.h deleted file mode 100644 index 574e794b3..000000000 --- a/core/embed/bootloader/icon_wipe.h +++ /dev/null @@ -1,11 +0,0 @@ -// clang-format off -static const uint8_t toi_icon_wipe[] = { - // magic - 'T', 'O', 'I', 'G', - // width (16-bit), height (16-bit) - 0x40, 0x00, 0x40, 0x00, - // compressed data length (32-bit) - 0x2f, 0x01, 0x00, 0x00, - // compressed data - 0xed, 0xd2, 0x31, 0x4e, 0x02, 0x41, 0x14, 0x06, 0xe0, 0xc7, 0x62, 0x58, 0x41, 0x5d, 0x48, 0xac, 0x35, 0x14, 0xf6, 0x5a, 0x98, 0x58, 0xe2, 0x0d, 0xc6, 0x1b, 0x48, 0x6d, 0x21, 0x5a, 0xd8, 0x99, 0xc8, 0x0d, 0xbc, 0x82, 0x37, 0xc0, 0x23, 0x10, 0x2f, 0x00, 0x89, 0x85, 0xa5, 0xdb, 0x6b, 0x82, 0x80, 0x68, 0x24, 0xe0, 0x73, 0xde, 0xcc, 0x12, 0x27, 0xd9, 0x7f, 0x86, 0x9a, 0x84, 0x3f, 0xd9, 0xc9, 0x66, 0xbf, 0xec, 0xec, 0xec, 0x7b, 0x8f, 0x68, 0x9d, 0xd5, 0xc9, 0xf5, 0x12, 0x1f, 0xb6, 0xc2, 0x3e, 0xe2, 0x4a, 0xd0, 0x3f, 0xb9, 0x13, 0xf4, 0x6f, 0xe6, 0xcd, 0x90, 0x4f, 0x99, 0xd5, 0x6e, 0xc0, 0x67, 0xcc, 0xbd, 0xb4, 0xe8, 0xe5, 0x3a, 0xeb, 0xdc, 0x28, 0x8f, 0x46, 0xd4, 0x14, 0x4f, 0xd8, 0xb3, 0xc1, 0x09, 0x75, 0xc5, 0xd5, 0x6c, 0x0f, 0xfb, 0x05, 0x0d, 0xc5, 0x5f, 0xa7, 0xf7, 0xd8, 0xdf, 0xe4, 0xf8, 0x3a, 0xbf, 0x9e, 0x0f, 0xf0, 0x01, 0x67, 0xd9, 0x41, 0x5c, 0xe3, 0xdb, 0x85, 0xc3, 0x3f, 0x68, 0xf3, 0x60, 0xe1, 0xb0, 0xc8, 0x7d, 0xfe, 0x4f, 0x01, 0xf8, 0xd8, 0xf1, 0x18, 0xf8, 0x8f, 0xe3, 0xdb, 0xe8, 0xf8, 0x4e, 0xaa, 0x79, 0x6e, 0xba, 0x7e, 0x98, 0xf7, 0xae, 0xeb, 0xe0, 0x07, 0x3f, 0xac, 0x5c, 0x9a, 0xb5, 0x85, 0x46, 0xcf, 0x24, 0x99, 0xc8, 0x7a, 0x97, 0xf7, 0x49, 0x56, 0xda, 0x07, 0x59, 0xcf, 0xe1, 0xe8, 0x49, 0xb6, 0x8e, 0x64, 0x6d, 0xe4, 0xfd, 0x4b, 0x9e, 0xbf, 0xf3, 0x86, 0x69, 0x62, 0x15, 0x8d, 0xb6, 0xce, 0xf3, 0xc0, 0xde, 0x80, 0x06, 0xca, 0x6c, 0x74, 0xfa, 0xca, 0xde, 0xc4, 0xb8, 0x3d, 0x8d, 0x54, 0x17, 0x36, 0xc5, 0xfd, 0x91, 0xfa, 0x25, 0xa3, 0x82, 0x71, 0x38, 0x60, 0x73, 0xe6, 0xf2, 0x31, 0x19, 0xdf, 0x27, 0xdc, 0xdf, 0x52, 0x76, 0x90, 0x08, 0xf9, 0x55, 0x76, 0xac, 0x31, 0xaa, 0x8e, 0xad, 0x60, 0xc5, 0x16, 0xaa, 0x84, 0xfd, 0xcc, 0x96, 0x65, 0xae, 0xc8, 0x93, 0x27, 0xd9, 0xf8, 0xb4, 0x17, 0xf9, 0x9c, 0x5e, 0xf4, 0xf5, 0x18, 0x7b, 0x99, 0x6a, 0xfa, 0xd5, 0x3a, 0xad, 0xb3, 0x42, 0xf9, 0x03, -}; diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 8570431e2..cdcca3254 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -47,7 +47,7 @@ #include "bootui.h" #include "messages.h" -// #include "mpu.h" +#include "rust_ui.h" const uint8_t BOOTLOADER_KEY_M = 2; const uint8_t BOOTLOADER_KEY_N = 3; @@ -63,6 +63,12 @@ static const uint8_t * const BOOTLOADER_KEYS[] = { #define USB_IFACE_NUM 0 +typedef enum { + CONTINUE = 0, + RETURN = 1, + SHUTDOWN = 2, +} usb_result_t; + static void usb_init_all(secbool usb21_landing) { usb_dev_info_t dev_info = { .device_class = 0x00, @@ -99,8 +105,8 @@ static void usb_init_all(secbool usb21_landing) { usb_start(); } -static secbool bootloader_usb_loop(const vendor_header *const vhdr, - const image_header *const hdr) { +static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, + const image_header *const hdr) { // if both are NULL, we don't have a firmware installed // let's show a webusb landing page in this case usb_init_all((vhdr == NULL && hdr == NULL) ? sectrue : secfalse); @@ -115,6 +121,7 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, } uint16_t msg_id; uint32_t msg_size; + uint32_t response; if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) { // invalid header -> discard continue; @@ -127,35 +134,26 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, process_msg_Ping(USB_IFACE_NUM, msg_size, buf); break; case 5: // WipeDevice - ui_fadeout(); - ui_screen_wipe_confirm(); - ui_fadein(); - int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); + response = ui_screen_wipe_confirm(); if (INPUT_CANCEL == response) { - ui_fadeout(); - ui_screen_firmware_info(vhdr, hdr); - ui_fadein(); send_user_abort(USB_IFACE_NUM, "Wipe cancelled"); - break; + hal_delay(100); + usb_stop(); + usb_deinit(); + return RETURN; } - ui_fadeout(); ui_screen_wipe(); - ui_fadein(); r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf); if (r < 0) { // error - ui_fadeout(); - ui_screen_fail(); - ui_fadein(); + screen_wipe_fail(); usb_stop(); usb_deinit(); - return secfalse; // shutdown - } else { // success - ui_fadeout(); - ui_screen_done(0, sectrue); - ui_fadein(); + return SHUTDOWN; + } else { // success + screen_wipe_success(); usb_stop(); usb_deinit(); - return secfalse; // shutdown + return SHUTDOWN; } break; case 6: // FirmwareErase @@ -164,17 +162,18 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, case 7: // FirmwareUpload r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf); if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort - ui_fadeout(); ui_screen_fail(); - ui_fadein(); usb_stop(); usb_deinit(); - return secfalse; // shutdown + return SHUTDOWN; + } else if (r == UPLOAD_ERR_USER_ABORT) { + hal_delay(100); + usb_stop(); + usb_deinit(); + return RETURN; } else if (r == 0) { // last chunk received ui_screen_install_progress_upload(1000); - ui_fadeout(); ui_screen_done(4, sectrue); - ui_fadein(); ui_screen_done(3, secfalse); hal_delay(1000); ui_screen_done(2, secfalse); @@ -183,8 +182,8 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, hal_delay(1000); usb_stop(); usb_deinit(); - ui_fadeout(); - return sectrue; // jump to firmware + ui_screen_boot_empty(true, true); + return CONTINUE; } break; case 55: // GetFeatures @@ -260,10 +259,52 @@ int main(void) { display_reinit(); + mpu_config_bootloader(); + + 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); + } + + if (sectrue == firmware_present) { + firmware_present = check_vendor_header_lock(&vhdr); + } + + if (sectrue == firmware_present) { + hdr = read_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), + FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE); + if (hdr != (const image_header *)(FIRMWARE_START + vhdr.hdrlen)) { + firmware_present = secfalse; + } + } + if (sectrue == firmware_present) { + firmware_present = check_image_model(hdr); + } + if (sectrue == firmware_present) { + firmware_present = + check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub); + } + if (sectrue == firmware_present) { + firmware_present = + check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, + FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT); + } + #if defined TREZOR_MODEL_T set_core_clock(CLOCK_180_MHZ); display_set_little_endian(); #endif + + ui_screen_boot_empty(firmware_present == sectrue, false); + #ifdef USE_TOUCH touch_power_on(); touch_init(); @@ -276,14 +317,10 @@ int main(void) { rgb_led_init(); #endif - mpu_config_bootloader(); - #if PRODUCTION check_bootloader_version(); #endif - display_clear(); - // was there reboot with request to stay in bootloader? secbool stay_in_bootloader = secfalse; if (stay_in_bootloader_flag == STAY_IN_BOOTLOADER_FLAG) { @@ -310,69 +347,24 @@ int main(void) { } #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); - } - - if (sectrue == firmware_present) { - firmware_present = check_vendor_header_lock(&vhdr); - } - - if (sectrue == firmware_present) { - hdr = read_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), - FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE); - if (hdr != (const image_header *)(FIRMWARE_START + vhdr.hdrlen)) { - firmware_present = secfalse; - } - } - if (sectrue == firmware_present) { - firmware_present = check_image_model(hdr); - } - if (sectrue == firmware_present) { - firmware_present = - check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub); - } - if (sectrue == firmware_present) { - firmware_present = - check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, - FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT); - } - // start the bootloader if no or broken firmware found ... if (firmware_present != sectrue) { - // show intro animation - - // no ui_fadeout(); - we already start from black screen - ui_screen_welcome_first(); - ui_fadein(); - - hal_delay(1000); + // ignore stay in bootloader + stay_in_bootloader = secfalse; + touched = false; - ui_fadeout(); - ui_screen_welcome_second(); - ui_fadein(); + // show intro animation - hal_delay(1000); + ui_set_initial_setup(true); - ui_fadeout(); - ui_screen_welcome_third(); - ui_fadein(); + ui_screen_welcome(); // erase storage ensure(flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL), NULL); // and start the usb loop - if (bootloader_usb_loop(NULL, NULL) != sectrue) { + if (bootloader_usb_loop(NULL, NULL) != CONTINUE) { return 1; } } @@ -380,13 +372,78 @@ int main(void) { // ... or if user touched the screen on start // ... or we have stay_in_bootloader flag to force it if (touched || stay_in_bootloader == sectrue) { - // no ui_fadeout(); - we already start from black screen - ui_screen_firmware_info(&vhdr, hdr); - ui_fadein(); + ui_set_initial_setup(false); + + screen_t screen = SCREEN_INTRO; + + while (true) { + bool continue_to_firmware = false; + uint32_t ui_result = 0; + + switch (screen) { + case SCREEN_INTRO: + ui_result = ui_screen_intro(&vhdr, hdr); + if (ui_result == 1) { + screen = SCREEN_MENU; + } + if (ui_result == 2) { + screen = SCREEN_WAIT_FOR_HOST; + } + break; + case SCREEN_MENU: + ui_result = ui_screen_menu(); + if (ui_result == 1) { // exit menu + screen = SCREEN_INTRO; + } + if (ui_result == 2) { // reboot + ui_screen_boot_empty(true, true); + continue_to_firmware = true; + } + if (ui_result == 3) { // wipe + screen = SCREEN_WIPE_CONFIRM; + } + break; + case SCREEN_WIPE_CONFIRM: + ui_result = screen_wipe_confirm(); + if (ui_result == INPUT_CANCEL) { + // canceled + screen = SCREEN_MENU; + } + if (ui_result == INPUT_CONFIRM) { + ui_screen_wipe(); + secbool r = bootloader_WipeDevice(); + if (r != sectrue) { // error + screen_wipe_fail(); + return 1; + } else { // success + screen_wipe_success(); + return 1; + } + } + break; + case SCREEN_WAIT_FOR_HOST: + screen_connect(); + switch (bootloader_usb_loop(&vhdr, hdr)) { + case CONTINUE: + continue_to_firmware = true; + break; + case RETURN: + screen = SCREEN_INTRO; + break; + case SHUTDOWN: + return 1; + break; + default: + break; + } + break; + default: + break; + } - // and start the usb loop - if (bootloader_usb_loop(&vhdr, hdr) != sectrue) { - return 1; + if (continue_to_firmware) { + break; + } } } @@ -416,7 +473,7 @@ int main(void) { // if all VTRUST flags are unset = ultimate trust => skip the procedure if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) { - // ui_fadeout(); // no fadeout - we start from black screen + ui_fadeout(); ui_screen_boot(&vhdr, hdr); ui_fadein(); @@ -466,3 +523,5 @@ int main(void) { return 0; } + +void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); } diff --git a/core/embed/bootloader/memory.ld b/core/embed/bootloader/memory.ld index 2c9eb7440..5010b5814 100644 --- a/core/embed/bootloader/memory.ld +++ b/core/embed/bootloader/memory.ld @@ -23,7 +23,7 @@ ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); sram_start = ORIGIN(SRAM); sram_end = ORIGIN(SRAM) + LENGTH(SRAM); -_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.exidx) + SIZEOF(.align); +_codelen = SIZEOF(.flash) + SIZEOF(.data); SECTIONS { .header : ALIGN(4) { @@ -36,15 +36,6 @@ SECTIONS { *(.text*); . = ALIGN(4); *(.rodata*); - . = ALIGN(4); - } >FLASH AT>FLASH - - /* exception handling info generated by llvm which should consist of 8 bytes of "cantunwind" */ - .exidx : ALIGN(4) { - *(.ARM.exidx*); - } >FLASH AT>FLASH - - .align : ALIGN(4) { . = ALIGN(512); } >FLASH AT>FLASH @@ -57,6 +48,10 @@ SECTIONS { . = ALIGN(512); } >CCMRAM AT>FLASH + /DISCARD/ : { + *(.ARM.exidx*); + } + .bss : ALIGN(4) { *(.bss*); . = ALIGN(4); diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index eab9c771b..2674198b8 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -33,6 +33,7 @@ #include "bootui.h" #include "messages.h" +#include "rust_ui.h" #include "memzero.h" @@ -199,8 +200,8 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) { // only timeout => let's try again } else { // error - error_shutdown("Error reading", "from USB.", "Try different", - "USB cable."); + error_shutdown("USB ERROR", + "Error reading from USB. Try different USB cable."); } } return; // success @@ -559,33 +560,26 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, &is_upgrade, &is_downgrade_wipe); } - int response = INPUT_CANCEL; + uint32_t response = INPUT_CANCEL; if (sectrue == is_new) { // new installation - auto confirm response = INPUT_CONFIRM; } else if (sectrue == is_upgrade) { // firmware upgrade - ui_fadeout(); - ui_screen_install_confirm_upgrade(&vhdr, &hdr); - ui_fadein(); - response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); + response = ui_screen_install_confirm_upgrade(&vhdr, &hdr); } else { // downgrade with wipe or new firmware vendor - ui_fadeout(); - ui_screen_install_confirm_newvendor_or_downgrade_wipe( + response = ui_screen_install_confirm_newvendor_or_downgrade_wipe( &vhdr, &hdr, is_downgrade_wipe); - ui_fadein(); - response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); } if (INPUT_CANCEL == response) { - ui_fadeout(); - ui_screen_firmware_info(¤t_vhdr, current_hdr); - ui_fadein(); send_user_abort(iface_num, "Firmware install cancelled"); return UPLOAD_ERR_USER_ABORT; } + ui_screen_install_start(); + headers_offset = IMAGE_HEADER_SIZE + vhdr.hdrlen; read_offset = IMAGE_INIT_CHUNK_SIZE; @@ -601,11 +595,6 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, } else { // first block with the headers parsed -> the first chunk is now complete read_offset = 0; - - ui_fadeout(); - ui_screen_install_start(); - ui_fadein(); - // if firmware is not upgrade, erase storage if (sectrue != is_upgrade) { ensure( @@ -677,7 +666,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, return (int)firmware_remaining; } -int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { +secbool bootloader_WipeDevice(void) { static const uint8_t sectors[] = { FLASH_SECTOR_STORAGE_1, FLASH_SECTOR_STORAGE_2, @@ -700,8 +689,12 @@ int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { 22, FLASH_SECTOR_FIRMWARE_EXTRA_END, }; - if (sectrue != - flash_erase_sectors(sectors, sizeof(sectors), ui_screen_wipe_progress)) { + return flash_erase_sectors(sectors, sizeof(sectors), ui_screen_wipe_progress); +} + +int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { + secbool wipe_result = bootloader_WipeDevice(); + if (sectrue != wipe_result) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Could not erase flash"); diff --git a/core/embed/bootloader/messages.h b/core/embed/bootloader/messages.h index 0937f6062..dd4f3df5b 100644 --- a/core/embed/bootloader/messages.h +++ b/core/embed/bootloader/messages.h @@ -66,4 +66,6 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); +secbool bootloader_WipeDevice(void); + #endif diff --git a/core/embed/bootloader_ci/.changelog.d/1049.added b/core/embed/bootloader_ci/.changelog.d/1049.added new file mode 100644 index 000000000..873319b6a --- /dev/null +++ b/core/embed/bootloader_ci/.changelog.d/1049.added @@ -0,0 +1 @@ +Bootloader redesign diff --git a/core/embed/bootloader_ci/messages.c b/core/embed/bootloader_ci/messages.c index c2e0c92e6..78c0bf383 100644 --- a/core/embed/bootloader_ci/messages.c +++ b/core/embed/bootloader_ci/messages.c @@ -199,8 +199,8 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) { // only timeout => let's try again } else { // error - error_shutdown("Error reading", "from USB.", "Try different", - "USB cable."); + error_shutdown("USB ERROR", + "Error reading from USB. Try different USB cable."); } } return; // success diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index 760a9d599..6f157a691 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -186,7 +186,7 @@ int main(void) { // MicroPython default exception handler void __attribute__((noreturn)) nlr_jump_fail(void *val) { - error_shutdown("Internal error", "(UE)", NULL, NULL); + error_shutdown("INTERNAL ERROR!", "(UE)"); } // interrupt handlers @@ -194,29 +194,19 @@ void __attribute__((noreturn)) nlr_jump_fail(void *val) { void NMI_Handler(void) { // Clock Security System triggered NMI if ((RCC->CIR & RCC_CIR_CSSF) != 0) { - error_shutdown("Internal error", "(CS)", NULL, NULL); + error_shutdown("INTERNAL ERROR!", "(CS)"); } } -void HardFault_Handler(void) { - error_shutdown("Internal error", "(HF)", NULL, NULL); -} +void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); } -void MemManage_Handler_MM(void) { - error_shutdown("Internal error", "(MM)", NULL, NULL); -} +void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR!", "(MM)"); } -void MemManage_Handler_SO(void) { - error_shutdown("Internal error", "(SO)", NULL, NULL); -} +void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR!", "(SO)"); } -void BusFault_Handler(void) { - error_shutdown("Internal error", "(BF)", NULL, NULL); -} +void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(BF)"); } -void UsageFault_Handler(void) { - error_shutdown("Internal error", "(UF)", NULL, NULL); -} +void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(UF)"); } __attribute__((noreturn)) void reboot_to_bootloader() { jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, diff --git a/core/embed/rust/rust_ui.h b/core/embed/rust/rust_ui.h index 2bda41a2a..1cd3b6bba 100644 --- a/core/embed/rust/rust_ui.h +++ b/core/embed/rust/rust_ui.h @@ -4,3 +4,25 @@ void loader_uncompress_r(int32_t y_offset, uint16_t fg_color, uint16_t bg_color, uint16_t icon_color, int32_t progress, int32_t indeterminate, const uint8_t* icon_data, uint32_t icon_data_size); + +uint32_t screen_install_confirm(const char* vendor_str, uint8_t vendor_str_len, + const char* version_str, + const uint8_t* fingerprint, bool downgrade, + bool vendor); +uint32_t screen_wipe_confirm(void); +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(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_wipe_success(void); +void screen_wipe_fail(void); +uint32_t screen_install_success(const char* reboot_msg, bool initial_setup, + bool complete_draw); +uint32_t screen_install_fail(void); +void screen_welcome(void); +void screen_boot_empty(bool firmware_present, bool fading); diff --git a/core/embed/rust/src/error.rs b/core/embed/rust/src/error.rs index 579ea8f6a..d3e26e91b 100644 --- a/core/embed/rust/src/error.rs +++ b/core/embed/rust/src/error.rs @@ -1,12 +1,11 @@ -use core::{ - convert::{Infallible, TryInto}, - num::TryFromIntError, -}; - +use core::{convert::Infallible, num::TryFromIntError}; use cstr_core::CStr; #[cfg(feature = "micropython")] -use crate::micropython::{ffi, obj::Obj, qstr::Qstr}; +use { + crate::micropython::{ffi, obj::Obj, qstr::Qstr}, + core::convert::TryInto, +}; #[allow(clippy::enum_variant_names)] // We mimic the Python exception classnames here. #[derive(Clone, Copy, Debug)] @@ -22,7 +21,6 @@ pub enum Error { KeyError(Obj), #[cfg(feature = "micropython")] AttributeError(Qstr), - #[cfg(feature = "micropython")] ValueError(&'static CStr), #[cfg(feature = "micropython")] ValueErrorParam(&'static CStr, Obj), diff --git a/core/embed/rust/src/lib.rs b/core/embed/rust/src/lib.rs index b403a2fd7..0edae7d19 100644 --- a/core/embed/rust/src/lib.rs +++ b/core/embed/rust/src/lib.rs @@ -26,6 +26,7 @@ mod trace; #[cfg(feature = "ui")] #[macro_use] pub mod ui; +pub mod strutil; #[cfg(feature = "debug")] #[panic_handler] diff --git a/core/embed/rust/src/micropython/buffer.rs b/core/embed/rust/src/micropython/buffer.rs index 498f0082a..1c40a1799 100644 --- a/core/embed/rust/src/micropython/buffer.rs +++ b/core/embed/rust/src/micropython/buffer.rs @@ -1,6 +1,6 @@ use core::{convert::TryFrom, ops::Deref, ptr, slice, str}; -use crate::{error::Error, micropython::obj::Obj}; +use crate::{error::Error, micropython::obj::Obj, strutil::hexlify}; use super::ffi; @@ -231,18 +231,6 @@ pub unsafe fn get_buffer_mut<'a>(obj: Obj) -> Result<&'a mut [u8], Error> { } } -fn hexlify(data: &[u8], buffer: &mut [u8]) { - const HEX_LOWER: [u8; 16] = *b"0123456789abcdef"; - let mut i: usize = 0; - for b in data.iter().take(buffer.len() / 2) { - let hi: usize = ((b & 0xf0) >> 4).into(); - let lo: usize = (b & 0x0f).into(); - buffer[i] = HEX_LOWER[hi]; - buffer[i + 1] = HEX_LOWER[lo]; - i += 2; - } -} - pub fn hexlify_bytes(obj: Obj, offset: usize, max_len: usize) -> Result { if !obj.is_bytes() { return Err(Error::TypeError); diff --git a/core/embed/rust/src/strutil.rs b/core/embed/rust/src/strutil.rs new file mode 100644 index 000000000..d1454e878 --- /dev/null +++ b/core/embed/rust/src/strutil.rs @@ -0,0 +1,11 @@ +pub fn hexlify(data: &[u8], buffer: &mut [u8]) { + const HEX_LOWER: [u8; 16] = *b"0123456789abcdef"; + let mut i: usize = 0; + for b in data.iter().take(buffer.len() / 2) { + let hi: usize = ((b & 0xf0) >> 4).into(); + let lo: usize = (b & 0x0f).into(); + buffer[i] = HEX_LOWER[hi]; + buffer[i + 1] = HEX_LOWER[lo]; + i += 2; + } +} diff --git a/core/embed/rust/src/trezorhal/display.rs b/core/embed/rust/src/trezorhal/display.rs index 17e9c5128..a90278ef2 100644 --- a/core/embed/rust/src/trezorhal/display.rs +++ b/core/embed/rust/src/trezorhal/display.rs @@ -175,3 +175,9 @@ pub fn sync() { ffi::display_sync(); } } + +pub fn refresh() { + unsafe { + ffi::display_refresh(); + } +} diff --git a/core/embed/rust/src/ui/component/text/paragraphs.rs b/core/embed/rust/src/ui/component/text/paragraphs.rs index 73897bdc0..75bb54f8d 100644 --- a/core/embed/rust/src/ui/component/text/paragraphs.rs +++ b/core/embed/rust/src/ui/component/text/paragraphs.rs @@ -36,6 +36,13 @@ pub trait ParagraphStrType: AsRef { fn skip_prefix(&self, bytes: usize) -> Self; } +#[cfg(feature = "bootloader")] +impl ParagraphStrType for &str { + fn skip_prefix(&self, chars: usize) -> Self { + &self[chars..] + } +} + pub trait ParagraphSource { /// Determines the output type produced. type StrType: ParagraphStrType; @@ -258,6 +265,8 @@ pub struct Paragraph { /// Try to keep this and the next paragraph on the same page. NOTE: doesn't /// work if two or more subsequent paragraphs have this flag. no_break: bool, + padding_top: i16, + padding_bottom: i16, } impl Paragraph { @@ -268,6 +277,8 @@ impl Paragraph { align: Alignment::Start, break_after: false, no_break: false, + padding_top: PARAGRAPH_TOP_SPACE, + padding_bottom: PARAGRAPH_BOTTOM_SPACE, } } @@ -286,6 +297,16 @@ impl Paragraph { self } + pub const fn with_top_padding(mut self, padding: i16) -> Self { + self.padding_top = padding; + self + } + + pub const fn with_bottom_padding(mut self, padding: i16) -> Self { + self.padding_bottom = padding; + self + } + pub fn content(&self) -> &T { &self.content } @@ -302,13 +323,15 @@ impl Paragraph { align: self.align, break_after: self.break_after, no_break: self.no_break, + padding_top: self.padding_top, + padding_bottom: self.padding_bottom, } } fn layout(&self, area: Rect) -> TextLayout { TextLayout { - padding_top: PARAGRAPH_TOP_SPACE, - padding_bottom: PARAGRAPH_BOTTOM_SPACE, + padding_top: self.padding_top, + padding_bottom: self.padding_bottom, ..TextLayout::new(*self.style) .with_align(self.align) .with_bounds(area) @@ -604,3 +627,42 @@ where self } } + +impl ParagraphSource for Vec, N> { + type StrType = T; + + fn at(&self, index: usize, offset: usize) -> Paragraph { + let para = &self[index]; + para.map(|content| content.skip_prefix(offset)) + } + + fn size(&self) -> usize { + self.len() + } +} + +impl ParagraphSource for [Paragraph; N] { + type StrType = T; + + fn at(&self, index: usize, offset: usize) -> Paragraph { + let para = &self[index]; + para.map(|content| content.skip_prefix(offset)) + } + + fn size(&self) -> usize { + self.len() + } +} + +impl ParagraphSource for Paragraph { + type StrType = T; + + fn at(&self, index: usize, offset: usize) -> Paragraph { + assert_eq!(index, 0); + self.map(|content| content.skip_prefix(offset)) + } + + fn size(&self) -> usize { + 1 + } +} diff --git a/core/embed/rust/src/ui/display/mod.rs b/core/embed/rust/src/ui/display/mod.rs index c7512d8e5..fdeb48118 100644 --- a/core/embed/rust/src/ui/display/mod.rs +++ b/core/embed/rust/src/ui/display/mod.rs @@ -23,10 +23,12 @@ use crate::{ error::Error, time::Duration, trezorhal::{buffers::get_text_buffer, display, qr, time, uzlib::UzlibContext}, - ui::{component::image::Image, lerp::Lerp}, + ui::lerp::Lerp, }; use core::slice; +#[cfg(feature = "dma2d")] +use crate::ui::component::image::Image; pub use crate::ui::display::toif::Icon; #[cfg(any(feature = "model_tt", feature = "model_tr"))] pub use loader::{loader, loader_indeterminate, LOADER_MAX, LOADER_MIN}; @@ -833,6 +835,19 @@ pub fn text_right(baseline: Point, text: &str, font: Font, fg_color: Color, bg_c ); } +pub fn text_top_left(position: Point, text: &str, font: Font, fg_color: Color, bg_color: Color) { + // let w = font.text_width(text); + let h = font.text_height(); + display::text( + position.x, + position.y + h, + text, + font.into(), + fg_color.into(), + bg_color.into(), + ); +} + #[inline(always)] pub fn pixeldata(color: Color) { display::pixeldata(color.into()); @@ -860,6 +875,10 @@ pub fn sync() { display::sync(); } +pub fn refresh() { + display::refresh(); +} + pub fn get_color_table(fg_color: Color, bg_color: Color) -> [Color; 16] { let mut table: [Color; 16] = [Color::from_u16(0); 16]; diff --git a/core/embed/rust/src/ui/geometry.rs b/core/embed/rust/src/ui/geometry.rs index 339706921..077ee9aa8 100644 --- a/core/embed/rust/src/ui/geometry.rs +++ b/core/embed/rust/src/ui/geometry.rs @@ -326,6 +326,15 @@ impl Rect { } } + pub const fn outset(&self, insets: Insets) -> Self { + Self { + x0: self.x0 - insets.left, + y0: self.y0 - insets.top, + x1: self.x1 + insets.right, + y1: self.y1 + insets.bottom, + } + } + pub const fn cut_from_left(&self, width: i16) -> Self { Self { x0: self.x0, diff --git a/core/embed/rust/src/ui/layout/util.rs b/core/embed/rust/src/ui/layout/util.rs index e97ea0cd4..71c68582e 100644 --- a/core/embed/rust/src/ui/layout/util.rs +++ b/core/embed/rust/src/ui/layout/util.rs @@ -197,45 +197,6 @@ impl ParagraphSource for PropsList { } } -impl ParagraphSource for Vec, N> { - type StrType = T; - - fn at(&self, index: usize, offset: usize) -> Paragraph { - let para = &self[index]; - para.map(|content| content.skip_prefix(offset)) - } - - fn size(&self) -> usize { - self.len() - } -} - -impl ParagraphSource for [Paragraph; N] { - type StrType = T; - - fn at(&self, index: usize, offset: usize) -> Paragraph { - let para = &self[index]; - para.map(|content| content.skip_prefix(offset)) - } - - fn size(&self) -> usize { - self.len() - } -} - -impl ParagraphSource for Paragraph { - type StrType = T; - - fn at(&self, index: usize, offset: usize) -> Paragraph { - assert_eq!(index, 0); - self.map(|content| content.skip_prefix(offset)) - } - - fn size(&self) -> usize { - 1 - } -} - impl ParagraphStrType for StrBuffer { fn skip_prefix(&self, chars: usize) -> Self { self.offset(chars) diff --git a/core/embed/rust/src/ui/mod.rs b/core/embed/rust/src/ui/mod.rs index e7aec850f..c44b24dd5 100644 --- a/core/embed/rust/src/ui/mod.rs +++ b/core/embed/rust/src/ui/mod.rs @@ -8,7 +8,8 @@ pub mod display; pub mod event; pub mod geometry; pub mod lerp; -mod util; +pub mod screens; +pub mod util; #[cfg(feature = "micropython")] pub mod layout; diff --git a/core/embed/rust/src/ui/model_tt/bootloader/confirm.rs b/core/embed/rust/src/ui/model_tt/bootloader/confirm.rs new file mode 100644 index 000000000..af38bf7e3 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/bootloader/confirm.rs @@ -0,0 +1,195 @@ +use crate::ui::{ + component::{ + text::paragraphs::{ParagraphVecShort, Paragraphs}, + Child, Component, ComponentExt, Event, EventCtx, Label, Pad, + }, + constant, + constant::screen, + display::{Color, Icon}, + geometry::{Alignment, Insets, Offset, Point, Rect, TOP_CENTER}, + model_tt::{ + bootloader::theme::{ + button_bld_menu, BUTTON_AREA_START, CLOSE, CONTENT_PADDING, CORNER_BUTTON_AREA, + INFO_SMALL, TEXT_TITLE, TITLE_AREA, + }, + component::{Button, ButtonMsg::Clicked}, + constant::WIDTH, + theme::WHITE, + }, +}; + +#[derive(Copy, Clone, ToPrimitive)] +pub enum ConfirmMsg { + Cancel = 1, + Confirm = 2, +} + +pub struct Confirm<'a> { + bg: Pad, + content_pad: Pad, + bg_color: Color, + icon: Option, + title: Option>>, + message: Child>>, + left: Child>, + right: Child>, + info_button: Option>, + close_button: Option>, + info_title: Option>>, + info_text: Option>>, + show_info: bool, + + confirm_left: bool, +} + +impl<'a> Confirm<'a> { + pub fn new( + bg_color: Color, + icon: Option, + left: Button<&'static str>, + right: Button<&'static str>, + confirm_left: bool, + confirm: (Option<&'static str>, Paragraphs>), + info: Option<(&'static str, Paragraphs>)>, + ) -> Self { + let mut instance = Self { + bg: Pad::with_background(bg_color), + content_pad: Pad::with_background(bg_color), + bg_color, + icon, + message: Child::new(confirm.1), + left: Child::new(left), + right: Child::new(right), + close_button: None, + info_button: None, + info_title: None, + info_text: None, + confirm_left, + show_info: false, + title: confirm + .0 + .map(|title| Child::new(Label::new(title, Alignment::Start, TEXT_TITLE))), + }; + if let Some((title, text)) = info { + instance.info_title = Some(Child::new(Label::new(title, Alignment::Start, TEXT_TITLE))); + instance.info_text = Some(text); + instance.info_button = Some( + Button::with_icon(Icon::new(INFO_SMALL)) + .styled(button_bld_menu()) + .with_expanded_touch_area(Insets::uniform(13)), + ); + instance.close_button = Some( + Button::with_icon(Icon::new(CLOSE)) + .styled(button_bld_menu()) + .with_expanded_touch_area(Insets::uniform(13)), + ); + } + instance.bg.clear(); + instance + } +} + +impl<'a> Component for Confirm<'a> { + type Msg = ConfirmMsg; + + fn place(&mut self, bounds: Rect) -> Rect { + self.bg.place(constant::screen()); + self.content_pad.place(Rect::new( + Point::zero(), + Point::new(WIDTH, BUTTON_AREA_START), + )); + let icon_height = if let Some(icon) = self.icon { + icon.toif.height() + } else { + 0 + }; + self.message.place(Rect::new( + Point::new(CONTENT_PADDING, 32 + icon_height), + Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START), + )); + + let button_size = Offset::new(106, 38); + self.left.place(Rect::from_top_left_and_size( + Point::new(CONTENT_PADDING, BUTTON_AREA_START), + button_size, + )); + self.right.place(Rect::from_top_left_and_size( + Point::new(124, BUTTON_AREA_START), + button_size, + )); + self.info_button.place(CORNER_BUTTON_AREA); + self.close_button.place(CORNER_BUTTON_AREA); + self.info_title.place(TITLE_AREA); + self.title.place(TITLE_AREA); + self.info_text.place(Rect::new( + Point::new(CONTENT_PADDING, TITLE_AREA.y1), + Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START), + )); + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if self.show_info { + if let Some(Clicked) = self.close_button.event(ctx, event) { + self.show_info = false; + self.content_pad.clear(); + self.title.request_complete_repaint(ctx); + self.message.request_complete_repaint(ctx); + return None; + } + } else if let Some(Clicked) = self.info_button.event(ctx, event) { + self.show_info = true; + self.info_text.request_complete_repaint(ctx); + self.info_title.request_complete_repaint(ctx); + self.content_pad.clear(); + return None; + } + if let Some(Clicked) = self.left.event(ctx, event) { + return if self.confirm_left { + Some(Self::Msg::Confirm) + } else { + Some(Self::Msg::Cancel) + }; + }; + if let Some(Clicked) = self.right.event(ctx, event) { + return if self.confirm_left { + Some(Self::Msg::Cancel) + } else { + Some(Self::Msg::Confirm) + }; + }; + None + } + + fn paint(&mut self) { + self.bg.paint(); + self.content_pad.paint(); + + if self.show_info { + self.close_button.paint(); + self.info_title.paint(); + self.info_text.paint(); + self.left.paint(); + self.right.paint(); + } else { + self.info_button.paint(); + self.title.paint(); + self.message.paint(); + self.left.paint(); + self.right.paint(); + if let Some(icon) = self.icon { + icon.draw( + Point::new(screen().center().x, 32), + TOP_CENTER, + WHITE, + self.bg_color, + ); + } + } + } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.left.bounds(sink); + self.right.bounds(sink); + } +} diff --git a/core/embed/rust/src/ui/model_tt/bootloader/connect.rs b/core/embed/rust/src/ui/model_tt/bootloader/connect.rs new file mode 100644 index 000000000..379f7cad2 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/bootloader/connect.rs @@ -0,0 +1,50 @@ +use crate::ui::{ + component::{Component, Event, EventCtx, Never, Pad}, + constant::screen, + display::{self, Font}, + geometry::{Offset, Rect}, + model_tt::bootloader::theme::{BLD_BG, BLD_TITLE_COLOR}, +}; + +pub struct Connect { + bg: Pad, + message: &'static str, +} + +impl Connect { + pub fn new(message: &'static str) -> Self { + let mut instance = Self { + bg: Pad::with_background(BLD_BG), + message, + }; + + instance.bg.clear(); + instance + } +} + +impl Component for Connect { + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + self.bg.place(screen()); + bounds + } + + fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { + None + } + + fn paint(&mut self) { + let font = Font::NORMAL; + + self.bg.paint(); + display::text_center( + screen().center() + Offset::y(font.text_height() / 2), + self.message, + Font::NORMAL, + BLD_TITLE_COLOR, + BLD_BG, + ); + } +} diff --git a/core/embed/rust/src/ui/model_tt/bootloader/intro.rs b/core/embed/rust/src/ui/model_tt/bootloader/intro.rs new file mode 100644 index 000000000..fabbc93e2 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/bootloader/intro.rs @@ -0,0 +1,100 @@ +use crate::ui::{ + component::{ + text::paragraphs::{ParagraphVecShort, Paragraphs}, + Child, Component, Event, EventCtx, Label, Pad, + }, + constant::screen, + display::Icon, + geometry::{Alignment, Insets, Point, Rect}, + model_tt::{ + bootloader::theme::{button_bld_menu, button_bld_menu_item, BLD_BG, MENU}, + component::ButtonMsg::Clicked, + }, +}; +use heapless::String; + +use crate::ui::model_tt::{ + bootloader::theme::{CONTENT_PADDING, CORNER_BUTTON_AREA, TEXT_TITLE, TITLE_AREA}, + component::Button, + constant::WIDTH, +}; + +#[repr(u32)] +#[derive(Copy, Clone, ToPrimitive)] +pub enum IntroMsg { + Menu = 1, + Host = 2, +} + +pub struct Intro<'a> { + bg: Pad, + title: Child>>, + menu: Child>, + host: Child>, + text: Child>>, +} + +impl<'a> Intro<'a> { + pub fn new(bld_version: &'static str, content: Paragraphs>) -> Self { + let mut title: String<32> = String::new(); + unwrap!(title.push_str("BOOTLOADER ")); + unwrap!(title.push_str(bld_version)); + + let mut instance = Self { + bg: Pad::with_background(BLD_BG), + title: Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)), + menu: Child::new( + Button::with_icon(Icon::new(MENU)) + .styled(button_bld_menu()) + .with_expanded_touch_area(Insets::uniform(13)), + ), + host: Child::new(Button::with_text("INSTALL FIRMWARE").styled(button_bld_menu_item())), + text: Child::new(content), + }; + + instance.bg.clear(); + instance + } +} + +impl<'a> Component for Intro<'a> { + type Msg = IntroMsg; + + fn place(&mut self, bounds: Rect) -> Rect { + const BUTTON_AREA_START: i16 = 188; + self.bg.place(screen()); + self.title.place(TITLE_AREA); + self.menu.place(CORNER_BUTTON_AREA); + self.host.place(Rect::new( + Point::new(10, BUTTON_AREA_START), + Point::new(10 + 220, BUTTON_AREA_START + 38), + )); + self.text.place(Rect::new( + Point::new(CONTENT_PADDING, 75), + Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START), + )); + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if let Some(Clicked) = self.menu.event(ctx, event) { + return Some(Self::Msg::Menu); + }; + if let Some(Clicked) = self.host.event(ctx, event) { + return Some(Self::Msg::Host); + }; + None + } + + fn paint(&mut self) { + self.bg.paint(); + self.title.paint(); + self.text.paint(); + self.host.paint(); + self.menu.paint(); + } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.menu.bounds(sink); + } +} diff --git a/core/embed/rust/src/ui/model_tt/bootloader/menu.rs b/core/embed/rust/src/ui/model_tt/bootloader/menu.rs new file mode 100644 index 000000000..aa2e30510 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/bootloader/menu.rs @@ -0,0 +1,106 @@ +use crate::ui::{ + component::{Child, Component, Event, EventCtx, Label, Pad}, + constant::{screen, WIDTH}, + display::Icon, + geometry::{Alignment, Insets, Point, Rect}, + model_tt::{ + bootloader::theme::{ + button_bld_menu, button_bld_menu_item, BLD_BG, CLOSE, CONTENT_PADDING, + CORNER_BUTTON_AREA, ERASE, REBOOT, TEXT_TITLE, TITLE_AREA, + }, + component::{Button, ButtonMsg::Clicked, IconText}, + }, +}; +use heapless::String; + +#[repr(u32)] +#[derive(Copy, Clone, ToPrimitive)] +pub enum MenuMsg { + Close = 1, + Reboot = 2, + FactoryReset = 3, +} + +pub struct Menu { + bg: Pad, + title: Child>>, + close: Child>, + reboot: Child>, + reset: Child>, +} + +impl Menu { + pub fn new(bld_version: &'static str) -> Self { + let content_reboot = IconText::new("REBOOT TREZOR", Icon::new(REBOOT)); + let content_reset = IconText::new("FACTORY RESET", Icon::new(ERASE)); + + let mut title: String<32> = String::new(); + unwrap!(title.push_str("BOOTLOADER ")); + unwrap!(title.push_str(bld_version)); + + let mut instance = Self { + bg: Pad::with_background(BLD_BG), + title: Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)), + close: Child::new( + Button::with_icon(Icon::new(CLOSE)) + .styled(button_bld_menu()) + .with_expanded_touch_area(Insets::uniform(13)), + ), + reboot: Child::new( + Button::with_icon_and_text(content_reboot).styled(button_bld_menu_item()), + ), + reset: Child::new( + Button::with_icon_and_text(content_reset).styled(button_bld_menu_item()), + ), + }; + instance.bg.clear(); + instance + } +} + +impl Component for Menu { + type Msg = MenuMsg; + + fn place(&mut self, bounds: Rect) -> Rect { + self.bg.place(screen()); + self.title.place(TITLE_AREA); + self.close.place(CORNER_BUTTON_AREA); + self.reboot.place(Rect::new( + Point::new(CONTENT_PADDING, 64), + Point::new(WIDTH - CONTENT_PADDING, 64 + 38), + )); + self.reset.place(Rect::new( + Point::new(CONTENT_PADDING, 110), + Point::new(WIDTH - CONTENT_PADDING, 110 + 38), + )); + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if let Some(Clicked) = self.close.event(ctx, event) { + return Some(Self::Msg::Close); + } + if let Some(Clicked) = self.reboot.event(ctx, event) { + return Some(Self::Msg::Reboot); + } + if let Some(Clicked) = self.reset.event(ctx, event) { + return Some(Self::Msg::FactoryReset); + } + + None + } + + fn paint(&mut self) { + self.bg.paint(); + self.title.paint(); + self.close.paint(); + self.reboot.paint(); + self.reset.paint(); + } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.close.bounds(sink); + self.reboot.bounds(sink); + self.reset.bounds(sink); + } +} diff --git a/core/embed/rust/src/ui/model_tt/bootloader/mod.rs b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs new file mode 100644 index 000000000..79f4a8875 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs @@ -0,0 +1,513 @@ +use crate::{ + trezorhal::io::io_touch_read, + ui::{ + component::{Component, Event, EventCtx, Never}, + display::{self, Font}, + event::TouchEvent, + geometry::Point, + model_tt::constant, + }, +}; +use heapless::String; +use num_traits::ToPrimitive; + +pub mod confirm; +mod connect; +pub mod intro; +pub mod menu; +pub mod theme; + +use crate::{ + strutil::hexlify, + ui::{ + component::text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt}, + constant::screen, + display::{Color, Icon}, + geometry::{LinearPlacement, CENTER}, + model_tt::{ + bootloader::{ + connect::Connect, + theme::{ + button_install_cancel, button_install_confirm, button_wipe_cancel, + button_wipe_confirm, BLD_BG, BLD_FG, BLD_WIPE_COLOR, ERASE_BIG, LOGO_EMPTY, + RECEIVE, TEXT_WIPE_BOLD, WELCOME_COLOR, + }, + }, + component::{Button, ResultScreen}, + theme::{ + BACKLIGHT_DIM, BACKLIGHT_NORMAL, BG, BLACK, FG, GREY_DARK, ICON_SUCCESS_SMALL, + ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE, + }, + }, + util::{from_c_array, from_c_str}, + }, +}; +use confirm::Confirm; +use intro::Intro; +use menu::Menu; + +pub trait ReturnToC { + fn return_to_c(self) -> u32; +} + +impl ReturnToC for Never { + fn return_to_c(self) -> u32 { + unreachable!() + } +} + +impl ReturnToC for T +where + T: ToPrimitive, +{ + fn return_to_c(self) -> u32 { + self.to_u32().unwrap() + } +} + +fn fadein() { + display::fade_backlight_duration(BACKLIGHT_NORMAL, 500); +} + +fn fadeout() { + display::fade_backlight_duration(BACKLIGHT_DIM, 500); +} + +fn run(frame: &mut F) -> u32 +where + F: Component, + F::Msg: ReturnToC, +{ + frame.place(constant::screen()); + fadeout(); + display::sync(); + frame.paint(); + fadein(); + + loop { + let event = touch_eval(); + if let Some(e) = event { + let mut ctx = EventCtx::new(); + let msg = frame.event(&mut ctx, Event::Touch(e)); + + if let Some(message) = msg { + return message.return_to_c(); + } + display::sync(); + frame.paint(); + } + } +} + +fn show(frame: &mut F, fading: bool) +where + F: Component, +{ + frame.place(screen()); + if fading { + fadeout() + }; + display::sync(); + frame.paint(); + if fading { + fadein() + }; +} + +fn touch_eval() -> Option { + let event = io_touch_read(); + if event == 0 { + return None; + } + let event_type = event >> 24; + let ex = ((event >> 12) & 0xFFF) as i16; + let ey = (event & 0xFFF) as i16; + + TouchEvent::new(event_type, ex as _, ey as _).ok() +} + +#[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, + downgrade: bool, + vendor: bool, +) -> 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 as *const u8, 32); + hexlify(fingerprint_slice, &mut fingerprint_buffer); + core::str::from_utf8_unchecked(fingerprint_buffer.as_ref()) + }; + + let mut version_str: String<64> = String::new(); + unwrap!(version_str.push_str("Firmware version ")); + unwrap!(version_str.push_str(version)); + + let mut vendor_str: String<64> = String::new(); + unwrap!(vendor_str.push_str("by ")); + unwrap!(vendor_str.push_str(text)); + + let title = if downgrade { + "DOWNGRADE FW" + } else if vendor { + "CHANGE FW VENDOR" + } else { + "UPDATE FIRMWARE" + }; + + let mut messages = ParagraphVecShort::new(); + + messages.add(Paragraph::new(&theme::TEXT_NORMAL, version_str.as_ref())); + messages.add(Paragraph::new(&theme::TEXT_NORMAL, vendor_str.as_ref())); + + if vendor || downgrade { + messages + .add(Paragraph::new(&theme::TEXT_BOLD, "Seed will be erased!").with_top_padding(16)); + } + + let message = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_FINGERPRINT, fingerprint_str)); + + let fingerprint = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let left = Button::with_text("CANCEL").styled(button_install_cancel()); + let right = Button::with_text("INSTALL").styled(button_install_confirm()); + + let mut frame = Confirm::new( + BLD_BG, + None, + left, + right, + false, + (Some(title), message), + Some(("FW FINGERPRINT", fingerprint)), + ); + + run(&mut frame) +} + +#[no_mangle] +extern "C" fn screen_wipe_confirm() -> u32 { + let icon = Some(Icon::new(ERASE_BIG)); + + let mut messages = ParagraphVecShort::new(); + + messages.add( + Paragraph::new( + &TEXT_ERROR_NORMAL, + "Are you sure you want to factory reset the device?", + ) + .centered(), + ); + messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Seed and firmware\nwill be erased!").centered()); + + let message = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let left = Button::with_text("RESET").styled(button_wipe_confirm()); + let right = Button::with_text("CANCEL").styled(button_wipe_cancel()); + + let mut frame = Confirm::new( + BLD_WIPE_COLOR, + icon, + left, + right, + true, + (None, message), + None, + ); + + run(&mut frame) +} + +#[no_mangle] +extern "C" fn screen_menu(bld_version: *const cty::c_char) -> u32 { + let bld_version = unwrap!(unsafe { from_c_str(bld_version) }); + + run(&mut Menu::new(bld_version)) +} + +#[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, +) -> 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 fw: String<64> = String::new(); + unwrap!(fw.push_str("Firmware ")); + unwrap!(fw.push_str(version)); + + let mut vendor_: String<64> = String::new(); + unwrap!(vendor_.push_str("by ")); + unwrap!(vendor_.push_str(vendor)); + + let mut messages = ParagraphVecShort::new(); + + messages.add(Paragraph::new(&theme::TEXT_NORMAL, fw.as_ref())); + messages.add(Paragraph::new(&theme::TEXT_NORMAL, vendor_.as_ref())); + + let p = Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_start()); + + let mut frame = Intro::new(bld_version, p); + + run(&mut frame) +} + +fn screen_progress( + text: &str, + progress: u16, + initialize: bool, + fg_color: Color, + bg_color: Color, + icon: Option<(Icon, Color)>, +) { + if initialize { + fadeout(); + display::rect_fill(constant::screen(), bg_color); + } + + display::text_center( + Point::new(constant::WIDTH / 2, 214), + text, + Font::NORMAL, + fg_color, + bg_color, + ); + display::loader(progress, -20, fg_color, bg_color, icon); + if initialize { + 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 { BG }; + let fg_color = if initial_setup { FG } else { BLD_FG }; + + screen_progress( + "Installing firmware...", + progress, + initialize, + fg_color, + bg_color, + Some((Icon::new(RECEIVE), fg_color)), + ) +} + +#[no_mangle] +extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) { + screen_progress( + "Resetting Trezor...", + progress, + initialize, + theme::BLD_FG, + BLD_WIPE_COLOR, + Some((Icon::new(ERASE_BIG), theme::BLD_FG)), + ) +} + +#[no_mangle] +extern "C" fn screen_connect() { + let mut frame = Connect::new("Waiting for host..."); + show(&mut frame, true); +} + +#[no_mangle] +extern "C" fn screen_wipe_success() { + let mut messages = ParagraphVecShort::new(); + + messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Trezor reset").centered()); + messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "successfully.").centered()); + + let m_top = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "PLEASE RECONNECT").centered()); + messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "THE DEVICE").centered()); + + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + WHITE, + BLD_WIPE_COLOR, + Icon::new(ICON_SUCCESS_SMALL), + m_top, + m_bottom, + true, + ); + show(&mut frame, true); +} + +#[no_mangle] +extern "C" fn screen_wipe_fail() { + let mut messages = ParagraphVecShort::new(); + + messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Trezor reset was").centered()); + messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "not successful.").centered()); + let m_top = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut messages = ParagraphVecShort::new(); + + messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "PLEASE RECONNECT").centered()); + messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "THE DEVICE").centered()); + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + WHITE, + BLD_WIPE_COLOR, + Icon::new(ICON_WARN_SMALL), + m_top, + m_bottom, + true, + ); + show(&mut frame, true); +} + +#[no_mangle] +extern "C" fn screen_boot_empty(firmware_present: bool, fading: bool) { + if fading { + fadeout(); + } + + let fg = if firmware_present { GREY_DARK } else { WHITE }; + let bg = if firmware_present { + BLACK + } else { + WELCOME_COLOR + }; + display::rect_fill(constant::screen(), bg); + let icon = Icon::new(LOGO_EMPTY); + icon.draw(screen().center(), CENTER, fg, bg); + + if fading { + fadein(); + } else { + display::set_backlight(BACKLIGHT_NORMAL); + } +} + +#[no_mangle] +extern "C" fn screen_install_fail() { + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_BOLD, "Firmware installation was").centered()); + messages.add(Paragraph::new(&theme::TEXT_BOLD, "not successful.").centered()); + + let m_top = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "PLEASE RECONNECT").centered()); + messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "THE DEVICE").centered()); + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + WHITE, + BLD_BG, + Icon::new(ICON_WARN_SMALL), + m_top, + m_bottom, + true, + ); + show(&mut frame, true); +} + +fn screen_install_success_bld(msg: &'static str, complete_draw: bool) { + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_BOLD, "Firmware installed").centered()); + messages.add(Paragraph::new(&theme::TEXT_BOLD, "successfully.").centered()); + let m_top = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_SUBMSG, msg).centered()); + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + WHITE, + BLD_BG, + Icon::new(ICON_SUCCESS_SMALL), + m_top, + m_bottom, + complete_draw, + ); + show(&mut frame, complete_draw); +} + +fn screen_install_success_initial(msg: &'static str, complete_draw: bool) { + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_WELCOME_BOLD, "Firmware installed").centered()); + messages.add(Paragraph::new(&theme::TEXT_WELCOME_BOLD, "successfully.").centered()); + + let m_top = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_SUBMSG_INITIAL, msg).centered()); + + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + FG, + WELCOME_COLOR, + Icon::new(ICON_SUCCESS_SMALL), + m_top, + m_bottom, + complete_draw, + ); + show(&mut frame, complete_draw); +} + +#[no_mangle] +extern "C" fn screen_install_success( + reboot_msg: *const cty::c_char, + initial_setup: bool, + complete_draw: bool, +) { + let msg = unwrap!(unsafe { from_c_str(reboot_msg) }); + if initial_setup { + screen_install_success_initial(msg, complete_draw) + } else { + screen_install_success_bld(msg, complete_draw) + } +} + +#[no_mangle] +extern "C" fn screen_welcome() { + fadeout(); + display::rect_fill(screen(), WELCOME_COLOR); + + let mut messages = ParagraphVecShort::new(); + messages.add(Paragraph::new(&theme::TEXT_WELCOME, "Get started with").centered()); + messages.add(Paragraph::new(&theme::TEXT_WELCOME, "your trezor at").centered()); + messages.add( + Paragraph::new(&theme::TEXT_WELCOME_BOLD, "trezor.io/start") + .centered() + .with_top_padding(2), + ); + let mut frame = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + show(&mut frame, false); + fadein(); +} diff --git a/core/embed/rust/src/ui/model_tt/bootloader/theme.rs b/core/embed/rust/src/ui/model_tt/bootloader/theme.rs new file mode 100644 index 000000000..e5fc4cf3d --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/bootloader/theme.rs @@ -0,0 +1,304 @@ +use crate::{ + alpha, + ui::{ + component::{text::TextStyle, LineBreaking::BreakWordsNoHyphen}, + constant::WIDTH, + display::{Color, Font}, + geometry::{Offset, Point, Rect}, + model_tt::{ + component::{ButtonStyle, ButtonStyleSheet}, + theme::{BLACK, FG, GREY_DARK, GREY_LIGHT, GREY_MEDIUM, WHITE}, + }, + }, +}; + +pub const BLD_BG: Color = Color::rgb(0x00, 0x17, 0xA3); +pub const BLD_FG: Color = WHITE; +pub const BLD_WIPE_COLOR: Color = Color::rgb(0xAD, 0x2B, 0x2B); +pub const BLD_WIPE_TEXT_COLOR: Color = Color::rgb(0xD6, 0x95, 0x95); + +pub const BLD_WIPE_BTN_COLOR: Color = Color::alpha(BLD_WIPE_COLOR, alpha!(0.3)); +pub const BLD_WIPE_BTN_COLOR_ACTIVE: Color = Color::rgb(0xB9, 0x4B, 0x4B); +pub const BLD_WIPE_CANCEL_BTN_COLOR_ACTIVE: Color = Color::rgb(0xF3, 0xDF, 0xDF); + +pub const BLD_INSTALL_BTN_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.3)); +pub const BLD_INSTALL_BTN_COLOR_ACTIVE: Color = Color::rgb(0xD9, 0xDC, 0xF1); +pub const BLD_INSTALL_CANCEL_BTN_COLOR_ACTIVE: Color = Color::rgb(0x26, 0x3A, 0xB1); + +pub const BLD_COLOR_SUBMSG: Color = Color::rgb(0x80, 0x8B, 0xD1); + +pub const BLD_BTN_MENU_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.22)); +pub const BLD_BTN_MENU_COLOR_ACTIVE: Color = Color::alpha(BLD_BG, alpha!(0.11)); +pub const BLD_BTN_MENUITEM_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.33)); +pub const BLD_BTN_MENUITEM_COLOR_ACTIVE: Color = + Color::rgba(BLD_BG, 0xFF, 0xFF, 0xFF, alpha!(0.11)); +pub const BLD_TITLE_COLOR: Color = Color::rgba(BLD_BG, 0xFF, 0xFF, 0xFF, alpha!(0.75)); + +pub const WELCOME_COLOR: Color = BLACK; + +// Commonly used corner radius (i.e. for buttons). +pub const RADIUS: u8 = 2; + +// Commonly used constants for UI elements. +pub const CONTENT_PADDING: i16 = 10; +pub const TITLE_AREA: Rect = Rect::new(Point::new(15, 14), Point::new(200, 30)); +pub const CORNER_BUTTON_SIZE: i16 = 32; +pub const CORNER_BUTTON_PADDING: i16 = 8; +pub const CORNER_BUTTON_AREA: Rect = Rect::from_top_left_and_size( + Point::new( + WIDTH - CORNER_BUTTON_SIZE - CORNER_BUTTON_PADDING, + CORNER_BUTTON_PADDING, + ), + Offset::uniform(CORNER_BUTTON_SIZE), +); +pub const TITLE_AREA_HEIGHT: i16 = 16; +pub const TITLE_AREA_START_Y: i16 = 8; +pub const BUTTON_AREA_START: i16 = 188; + +// UI icons. +pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/cancel.toif"); +pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/confirm.toif"); + +// BLD icons +pub const CLOSE: &[u8] = include_res!("model_tt/res/close.toif"); +pub const ERASE: &[u8] = include_res!("model_tt/res/erase.toif"); +pub const ERASE_BIG: &[u8] = include_res!("model_tt/res/erase_big.toif"); +pub const REBOOT: &[u8] = include_res!("model_tt/res/reboot.toif"); +pub const MENU: &[u8] = include_res!("model_tt/res/menu.toif"); +pub const RECEIVE: &[u8] = include_res!("model_tt/res/receive.toif"); +pub const LOGO_EMPTY: &[u8] = include_res!("model_tt/res/trezor_empty.toif"); +pub const INFO_SMALL: &[u8] = include_res!("model_tt/res/info_small.toif"); + +pub fn button_install_cancel() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: WHITE, + button_color: BLD_BTN_MENUITEM_COLOR, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: RADIUS, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: WHITE, + button_color: BLD_INSTALL_CANCEL_BTN_COLOR_ACTIVE, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: RADIUS, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: GREY_LIGHT, + button_color: GREY_DARK, + background_color: WHITE, + border_color: WHITE, + border_radius: RADIUS, + border_width: 0, + }, + } +} + +pub fn button_install_confirm() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_BG, + button_color: WHITE, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: RADIUS, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_BG, + button_color: BLD_INSTALL_BTN_COLOR_ACTIVE, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: RADIUS, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: FG, + button_color: GREY_DARK, + background_color: FG, + border_color: FG, + border_radius: RADIUS, + border_width: 0, + }, + } +} + +pub fn button_wipe_cancel() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_WIPE_COLOR, + button_color: WHITE, + background_color: BLD_WIPE_COLOR, + border_color: BLD_WIPE_COLOR, + border_radius: RADIUS, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_WIPE_COLOR, + button_color: BLD_WIPE_CANCEL_BTN_COLOR_ACTIVE, + background_color: BLD_WIPE_COLOR, + border_color: BLD_WIPE_COLOR, + border_radius: RADIUS, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: GREY_LIGHT, + button_color: GREY_DARK, + background_color: WHITE, + border_color: WHITE, + border_radius: RADIUS, + border_width: 0, + }, + } +} + +pub fn button_wipe_confirm() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: WHITE, + button_color: BLD_WIPE_BTN_COLOR, + background_color: BLD_WIPE_COLOR, + border_color: BLD_WIPE_COLOR, + border_radius: RADIUS, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: WHITE, + button_color: BLD_WIPE_BTN_COLOR_ACTIVE, + background_color: BLD_WIPE_COLOR, + border_color: BLD_WIPE_COLOR, + border_radius: RADIUS, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: FG, + button_color: GREY_DARK, + background_color: FG, + border_color: FG, + border_radius: RADIUS, + border_width: 0, + }, + } +} + +pub fn button_bld_menu() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_FG, + button_color: BLD_BTN_MENU_COLOR, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: 4, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_FG, + button_color: BLD_BTN_MENU_COLOR_ACTIVE, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: 4, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: GREY_LIGHT, + button_color: BLD_BTN_MENU_COLOR, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: 4, + border_width: 0, + }, + } +} + +pub fn button_bld_menu_item() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_FG, + button_color: BLD_BTN_MENUITEM_COLOR, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: 4, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: BLD_FG, + button_color: BLD_BTN_MENUITEM_COLOR_ACTIVE, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: 4, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: GREY_LIGHT, + button_color: BLD_BTN_MENUITEM_COLOR, + background_color: BLD_BG, + border_color: BLD_BG, + border_radius: 4, + border_width: 0, + }, + } +} +pub const TEXT_WELCOME: TextStyle = TextStyle::new( + Font::NORMAL, + GREY_MEDIUM, + WELCOME_COLOR, + GREY_MEDIUM, + GREY_MEDIUM, +); +pub const TEXT_WELCOME_BOLD: TextStyle = TextStyle::new(Font::BOLD, FG, WELCOME_COLOR, FG, FG); +pub const TEXT_TITLE: TextStyle = TextStyle::new( + Font::BOLD, + BLD_TITLE_COLOR, + BLD_BG, + BLD_TITLE_COLOR, + BLD_TITLE_COLOR, +); +pub const TEXT_SUBMSG_INITIAL: TextStyle = TextStyle::new( + Font::BOLD, + GREY_MEDIUM, + WELCOME_COLOR, + GREY_MEDIUM, + GREY_MEDIUM, +); + +pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG); +pub const TEXT_FINGERPRINT: TextStyle = + TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG) + .with_line_breaking(BreakWordsNoHyphen); +pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, BLD_FG, BLD_BG, BLD_FG, BLD_FG); +pub const TEXT_WIPE_BOLD: TextStyle = TextStyle::new( + Font::BOLD, + BLD_WIPE_TEXT_COLOR, + BLD_WIPE_COLOR, + BLD_WIPE_TEXT_COLOR, + BLD_WIPE_TEXT_COLOR, +); +pub const TEXT_SUBMSG: TextStyle = TextStyle::new( + Font::BOLD, + BLD_COLOR_SUBMSG, + BLD_BG, + BLD_COLOR_SUBMSG, + BLD_COLOR_SUBMSG, +); diff --git a/core/embed/rust/src/ui/model_tt/component/button.rs b/core/embed/rust/src/ui/model_tt/component/button.rs index 55a4d4914..ba4ed7743 100644 --- a/core/embed/rust/src/ui/model_tt/component/button.rs +++ b/core/embed/rust/src/ui/model_tt/component/button.rs @@ -21,6 +21,7 @@ pub enum ButtonMsg { pub struct Button { area: Rect, + touch_expand: Option, content: ButtonContent, styles: ButtonStyleSheet, state: State, @@ -37,6 +38,7 @@ impl Button { Self { content, area: Rect::zero(), + touch_expand: None, styles: theme::button_default(), state: State::Initial, long_press: None, @@ -69,6 +71,11 @@ impl Button { self } + pub fn with_expanded_touch_area(mut self, expand: Insets) -> Self { + self.touch_expand = Some(expand); + self + } + pub fn with_long_press(mut self, duration: Duration) -> Self { self.long_press = Some(duration); self @@ -234,6 +241,12 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + let touch_area = if let Some(expand) = self.touch_expand { + self.area.outset(expand) + } else { + self.area + }; + match event { Event::Touch(TouchEvent::TouchStart(pos)) => { match self.state { @@ -242,7 +255,7 @@ where } _ => { // Touch started in our area, transform to `Pressed` state. - if self.area.contains(pos) { + if touch_area.contains(pos) { self.set(ctx, State::Pressed); if let Some(duration) = self.long_press { self.long_timer = Some(ctx.request_timer(duration)); @@ -254,7 +267,7 @@ where } Event::Touch(TouchEvent::TouchMove(pos)) => { match self.state { - State::Pressed if !self.area.contains(pos) => { + State::Pressed if !touch_area.contains(pos) => { // Touch is leaving our area, transform to `Released` state. self.set(ctx, State::Released); return Some(ButtonMsg::Released); @@ -269,7 +282,7 @@ where State::Initial | State::Disabled => { // Do nothing. } - State::Pressed if self.area.contains(pos) => { + State::Pressed if touch_area.contains(pos) => { // Touch finished in our area, we got clicked. self.set(ctx, State::Initial); return Some(ButtonMsg::Clicked); @@ -554,7 +567,7 @@ impl IconText { Self { text, icon } } - pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: i32) { + pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: i16) { let width = style.font.text_width(self.text); let height = style.font.text_height(); @@ -570,8 +583,7 @@ impl IconText { if area.width() > (Self::ICON_SPACE + Self::TEXT_MARGIN + width) { //display both icon and text - let start_of_baseline = area.center() + Offset::new(-width / 2, height / 2); - text_pos = Point::new(area.top_left().x + Self::ICON_SPACE, start_of_baseline.y); + text_pos = Point::new(area.top_left().x + Self::ICON_SPACE, text_pos.y); use_text = true; use_icon = true; } else if area.width() > (width + Self::TEXT_MARGIN) { 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 bb3a68e13..4d4a82f76 100644 --- a/core/embed/rust/src/ui/model_tt/component/mod.rs +++ b/core/embed/rust/src/ui/model_tt/component/mod.rs @@ -5,24 +5,27 @@ mod fido; mod fido_icons; mod frame; mod hold_to_confirm; +#[cfg(feature = "dma2d")] mod homescreen; mod keyboard; mod loader; mod number_input; mod page; mod progress; +mod result; mod scroll; mod swipe; mod welcome_screen; pub use button::{ Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg, - CancelInfoConfirmMsg, SelectWordMsg, + CancelInfoConfirmMsg, IconText, SelectWordMsg, }; pub use dialog::{Dialog, DialogMsg, IconDialog}; pub use fido::{FidoConfirm, FidoMsg}; pub use frame::{Frame, NotificationFrame}; pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg}; +#[cfg(feature = "dma2d")] pub use homescreen::{Homescreen, HomescreenMsg, Lockscreen}; pub use keyboard::{ bip39::Bip39Input, @@ -36,6 +39,7 @@ pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet}; pub use number_input::{NumberInputDialog, NumberInputDialogMsg}; pub use page::{SwipeHoldPage, SwipePage}; pub use progress::Progress; +pub use result::ResultScreen; pub use scroll::ScrollBar; pub use swipe::{Swipe, SwipeDirection}; pub use welcome_screen::WelcomeScreen; diff --git a/core/embed/rust/src/ui/model_tt/component/result.rs b/core/embed/rust/src/ui/model_tt/component/result.rs new file mode 100644 index 000000000..7c16eb1b0 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/component/result.rs @@ -0,0 +1,93 @@ +use crate::{ + alpha, + ui::{ + component::{ + text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs}, + Child, Component, Event, EventCtx, Never, Pad, + }, + constant::screen, + display::{self, Color, Icon}, + geometry::{Offset, Point, Rect, CENTER}, + }, +}; + +use crate::ui::model_tt::constant::{HEIGHT, WIDTH}; + +pub struct ResultScreen { + bg: Pad, + small_pad: Pad, + fg_color: Color, + bg_color: Color, + icon: Icon, + message_top: Child>>, + message_bottom: Child>>, +} + +impl ResultScreen { + pub fn new( + fg_color: Color, + bg_color: Color, + icon: Icon, + message_top: Paragraphs>, + message_bottom: Paragraphs>, + complete_draw: bool, + ) -> Self { + let mut instance = Self { + bg: Pad::with_background(bg_color), + small_pad: Pad::with_background(bg_color), + fg_color, + bg_color, + icon, + message_top: Child::new(message_top), + message_bottom: Child::new(message_bottom), + }; + + if complete_draw { + instance.bg.clear(); + } else { + instance.small_pad.clear(); + } + instance + } +} + +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, 149))); + + let bottom_area = Rect::new(Point::new(15, 151), Point::new(WIDTH - 15, HEIGHT)); + + self.small_pad.place(bottom_area); + self.message_bottom.place(bottom_area); + + bounds + } + + fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { + None + } + + fn paint(&mut self) { + self.bg.paint(); + self.small_pad.paint(); + + self.icon.draw( + Point::new(screen().center().x, 45), + CENTER, + self.fg_color, + self.bg_color, + ); + display::rect_fill( + Rect::from_top_left_and_size(Point::new(12, 149), Offset::new(216, 1)), + Color::alpha(self.bg_color, alpha!(0.2)), + ); + self.message_top.paint(); + self.message_bottom.paint(); + } +} diff --git a/core/embed/rust/src/ui/model_tt/constant.rs b/core/embed/rust/src/ui/model_tt/constant.rs index ceed7fe46..9648dd16e 100644 --- a/core/embed/rust/src/ui/model_tt/constant.rs +++ b/core/embed/rust/src/ui/model_tt/constant.rs @@ -9,6 +9,8 @@ pub const LOADER_OUTER: f32 = 60_f32; pub const LOADER_INNER: f32 = 42_f32; pub const LOADER_ICON_MAX_SIZE: i16 = 64; +pub const BACKLIGHT_NORMAL: i32 = 150; + pub const fn size() -> Offset { Offset::new(WIDTH, HEIGHT) } diff --git a/core/embed/rust/src/ui/model_tt/mod.rs b/core/embed/rust/src/ui/model_tt/mod.rs index 8d508e39c..8308f1b73 100644 --- a/core/embed/rust/src/ui/model_tt/mod.rs +++ b/core/embed/rust/src/ui/model_tt/mod.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "bootloader")] +pub mod bootloader; pub mod component; pub mod constant; pub mod event; @@ -5,3 +7,4 @@ pub mod theme; #[cfg(feature = "micropython")] pub mod layout; +pub mod screens; diff --git a/core/embed/rust/src/ui/model_tt/res/close.toif b/core/embed/rust/src/ui/model_tt/res/close.toif new file mode 100644 index 000000000..a53d508b3 Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/close.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/erase.toif b/core/embed/rust/src/ui/model_tt/res/erase.toif new file mode 100644 index 000000000..1daa5f2b5 Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/erase.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/erase_big.toif b/core/embed/rust/src/ui/model_tt/res/erase_big.toif new file mode 100644 index 000000000..5d2508a18 Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/erase_big.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/info_small.toif b/core/embed/rust/src/ui/model_tt/res/info_small.toif new file mode 100644 index 000000000..bad082376 Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/info_small.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/menu.toif b/core/embed/rust/src/ui/model_tt/res/menu.toif new file mode 100644 index 000000000..b69042148 Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/menu.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/reboot.toif b/core/embed/rust/src/ui/model_tt/res/reboot.toif new file mode 100644 index 000000000..d45654cbc Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/reboot.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/receive.toif b/core/embed/rust/src/ui/model_tt/res/receive.toif new file mode 100644 index 000000000..85446359a Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/receive.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/success_bld.toif b/core/embed/rust/src/ui/model_tt/res/success_bld.toif new file mode 100644 index 000000000..dc80a59e5 Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/success_bld.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/trezor_empty.toif b/core/embed/rust/src/ui/model_tt/res/trezor_empty.toif new file mode 100644 index 000000000..9747b207b Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/trezor_empty.toif differ diff --git a/core/embed/rust/src/ui/model_tt/res/warn_bld.toif b/core/embed/rust/src/ui/model_tt/res/warn_bld.toif new file mode 100644 index 000000000..df86e21db Binary files /dev/null and b/core/embed/rust/src/ui/model_tt/res/warn_bld.toif differ diff --git a/core/embed/rust/src/ui/model_tt/screens.rs b/core/embed/rust/src/ui/model_tt/screens.rs new file mode 100644 index 000000000..50b9442a7 --- /dev/null +++ b/core/embed/rust/src/ui/model_tt/screens.rs @@ -0,0 +1,104 @@ +#[cfg(feature = "micropython")] +use crate::micropython::buffer::StrBuffer; +use crate::ui::{ + component::{ + text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt}, + Component, + }, + display::Icon, + geometry::LinearPlacement, + model_tt::{ + component::ResultScreen, + constant, + theme::{FATAL_ERROR_COLOR, ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE}, + }, +}; + +#[cfg(not(feature = "micropython"))] +// SAFETY: Actually safe but see below +unsafe fn get_str(text: &str) -> &str { + text +} +#[cfg(feature = "micropython")] +// SAFETY: The caller is responsible for ensuring that the StrBuffer does not +// escape the lifetime of the original &str. +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) { + // 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_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_BOLD, "PLEASE CONTACT\nTREZOR SUPPORT".into()).centered()); + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + WHITE, + FATAL_ERROR_COLOR, + Icon::new(ICON_WARN_SMALL), + 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(); + + 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_BOLD, "PLEASE UNPLUG\nTHE DEVICE".into()).centered()); + let m_bottom = + Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); + + let mut frame = ResultScreen::new( + WHITE, + FATAL_ERROR_COLOR, + Icon::new(ICON_WARN_SMALL), + m_top, + m_bottom, + true, + ); + 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 d262d5f16..bb18afa82 100644 --- a/core/embed/rust/src/ui/model_tt/theme.rs +++ b/core/embed/rust/src/ui/model_tt/theme.rs @@ -42,6 +42,8 @@ pub const GREY_MEDIUM: Color = Color::rgb(0x45, 0x45, 0x45); // button pressed pub const GREY_DARK: Color = Color::rgb(0x1A, 0x1A, 0x1A); // button pub const VIOLET: Color = Color::rgb(0x95, 0x00, 0xCA); +pub const FATAL_ERROR_COLOR: Color = Color::rgb(0xAD, 0x2B, 0x2B); + // Commonly used corner radius (i.e. for buttons). pub const RADIUS: u8 = 2; @@ -64,6 +66,8 @@ pub const ICON_LIST_CURRENT: &[u8] = include_res!("model_tt/res/current.toif"); pub const ICON_LIST_CHECK: &[u8] = include_res!("model_tt/res/check.toif"); pub const ICON_LOCK: &[u8] = include_res!("model_tt/res/lock.toif"); pub const ICON_LOGO: &[u8] = include_res!("model_tt/res/logo.toif"); +pub const ICON_SUCCESS_SMALL: &[u8] = include_res!("model_tt/res/success_bld.toif"); +pub const ICON_WARN_SMALL: &[u8] = include_res!("model_tt/res/warn_bld.toif"); // Large, three-color icons. pub const WARN_COLOR: Color = YELLOW; @@ -397,6 +401,10 @@ pub fn textstyle_number(num: i32) -> &'static TextStyle { _ => &TEXT_NORMAL, } } +pub const TEXT_ERROR_NORMAL: TextStyle = + TextStyle::new(Font::NORMAL, FG, FATAL_ERROR_COLOR, GREY_LIGHT, GREY_LIGHT); +pub const TEXT_ERROR_BOLD: TextStyle = + TextStyle::new(Font::BOLD, FG, FATAL_ERROR_COLOR, GREY_LIGHT, GREY_LIGHT); pub const TEXT_NORMAL_OFF_WHITE: TextStyle = TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT); diff --git a/core/embed/rust/src/ui/screens.rs b/core/embed/rust/src/ui/screens.rs new file mode 100644 index 000000000..0460d0319 --- /dev/null +++ b/core/embed/rust/src/ui/screens.rs @@ -0,0 +1,40 @@ +//! Reexporting the `screens` module according to the +//! current feature (Trezor model) + +#[cfg(all(feature = "model_tr", not(feature = "model_tt")))] +pub use super::model_tr::screens::*; +#[cfg(feature = "model_tt")] +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) }) + }; + + 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) }) + }; + + screen_fatal_error(msg, file); +} diff --git a/core/embed/rust/src/ui/util.rs b/core/embed/rust/src/ui/util.rs index c31135c1b..acea051a0 100644 --- a/core/embed/rust/src/ui/util.rs +++ b/core/embed/rust/src/ui/util.rs @@ -5,6 +5,8 @@ use crate::ui::{ geometry::{Offset, Point, CENTER}, }; +use cstr_core::CStr; + pub trait ResultExt { fn assert_if_debugging_ui(self, message: &str); } @@ -38,6 +40,46 @@ pub fn u32_to_str(num: u32, buffer: &mut [u8]) -> Option<&str> { } } +/// Constructs a string from a C string. +/// +/// # Safety +/// +/// The caller is responsible that the pointer is valid, which means that: +/// (a) it is not null, +/// (b) it points to a memory containing a valid C string (zero-terminated +/// sequence of characters), and +/// (c) that the pointer has appropriate lifetime. +pub unsafe fn from_c_str<'a>(c_str: *const cty::c_char) -> Option<&'a str> { + unsafe { + let bytes = CStr::from_ptr(c_str).to_bytes(); + if bytes.is_ascii() { + Some(core::str::from_utf8_unchecked(bytes)) + } else { + None + } + } +} + +/// Construct str from a C array. +/// +/// # Safety +/// +/// The caller is responsible that the pointer is valid, which means that: +/// (a) it is not null, +/// (b) it points to a memory containing array of characters, with length `len`, +/// and +/// (c) that the pointer has appropriate lifetime. +pub unsafe fn from_c_array<'a>(c_str: *const cty::c_char, len: usize) -> Option<&'a str> { + unsafe { + let slice = core::slice::from_raw_parts(c_str as *const u8, len); + if slice.is_ascii() { + Some(core::str::from_utf8_unchecked(slice)) + } else { + None + } + } +} + #[cfg(feature = "ui_debug")] static mut DISABLE_ANIMATION: bool = false; diff --git a/core/embed/trezorhal/common.c b/core/embed/trezorhal/common.c index d8864b033..3de831926 100644 --- a/core/embed/trezorhal/common.c +++ b/core/embed/trezorhal/common.c @@ -23,11 +23,15 @@ #include "common.h" #include "display.h" +#ifdef FANCY_FATAL_ERROR +#include "rust_ui.h" +#endif #include "flash.h" #include "rand.h" #include "stm32.h" #include "supervise.h" +#include "mini_printf.h" #include "stm32f4xx_ll_utils.h" #ifdef RGB16 @@ -39,13 +43,16 @@ // from util.s extern void shutdown_privileged(void); -void shutdown(void) { +void __attribute__((noreturn)) shutdown(void) { #ifdef USE_SVC_SHUTDOWN svc_shutdown(); #else // It won't work properly unless called from the privileged mode shutdown_privileged(); #endif + + for (;;) + ; } void __attribute__((noreturn)) @@ -53,6 +60,13 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func) { display_orientation(0); display_backlight(255); + +#ifdef FANCY_FATAL_ERROR + char buf[256] = {0}; + mini_snprintf(buf, sizeof(buf), "%s: %d", file, line); + screen_fatal_error_c(msg, buf); + display_refresh(); +#else display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_printf("\nFATAL ERROR:\n"); if (expr) { @@ -73,58 +87,28 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, rev[4]); #endif display_printf("\nPlease contact Trezor support.\n"); +#endif shutdown(); - for (;;) - ; } void __attribute__((noreturn)) -error_shutdown(const char *line1, const char *line2, const char *line3, - const char *line4) { +error_shutdown(const char *label, const char *msg) { display_orientation(0); -#ifdef TREZOR_FONT_NORMAL_ENABLE - display_clear(); - display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR); - int y = 32; - if (line1) { - display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - y += 32; - } - if (line2) { - display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - y += 32; - } - if (line3) { - display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - y += 32; - } - if (line4) { - display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - y += 32; - } - y += 32; - display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE, - COLOR_FATAL_ERROR); +#ifdef FANCY_FATAL_ERROR + screen_error_shutdown_c(label, msg); + display_refresh(); #else display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); - if (line1) { - display_printf("%s\n", line1); - } - if (line2) { - display_printf("%s\n", line2); + if (label) { + display_printf("%s\n", label); } - if (line3) { - display_printf("%s\n", line3); - } - if (line4) { - display_printf("%s\n", line4); + if (msg) { + display_printf("%s\n", msg); } display_printf("\nPlease unplug the device.\n"); #endif display_backlight(255); shutdown(); - for (;;) - ; } #ifndef NDEBUG @@ -157,7 +141,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)", NULL, NULL); + error_shutdown("Internal error", "(SS)"); } uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; @@ -197,3 +181,13 @@ void ensure_compatible_settings(void) { display_set_slow_pwm(); #endif } + +void show_wipe_code_screen(void) { + error_shutdown( + "DEVICE WIPED!", + "You have entered the wipe code. All private data has been erased."); +} +void show_pin_too_many_screen(void) { + error_shutdown("DEVICE WIPED!", + "Too many wrong PIN attempts. Storage has been wiped."); +} diff --git a/core/embed/trezorhal/common.h b/core/embed/trezorhal/common.h index 770e7ec97..52aab3b0f 100644 --- a/core/embed/trezorhal/common.h +++ b/core/embed/trezorhal/common.h @@ -51,14 +51,16 @@ #define STAY_IN_BOOTLOADER_FLAG 0x0FC35A96 -void shutdown(void); +void __attribute__((noreturn)) shutdown(void); void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void __attribute__((noreturn)) -error_shutdown(const char *line1, const char *line2, const char *line3, - const char *line4); +error_shutdown(const char *label, const char *msg); + +void show_wipe_code_screen(void); +void show_pin_too_many_screen(void); #define ensure(expr, msg) \ (((expr) == sectrue) \ diff --git a/core/embed/trezorhal/image.c b/core/embed/trezorhal/image.c index 44d536d46..6c6c043ed 100644 --- a/core/embed/trezorhal/image.c +++ b/core/embed/trezorhal/image.c @@ -103,19 +103,22 @@ secbool check_image_model(const image_header *const hdr) { return sectrue; } -secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m, - uint8_t key_n, const uint8_t *const *keys) { - // check header signature +void get_image_fingerprint(const image_header *const hdr, uint8_t *const out) { BLAKE2S_CTX ctx; - uint8_t fingerprint[32]; - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); blake2s_Update(&ctx, hdr, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE); for (int i = 0; i < IMAGE_SIG_SIZE; i++) { blake2s_Update(&ctx, (const uint8_t *)"\x00", 1); } + blake2s_Final(&ctx, out, BLAKE2S_DIGEST_LENGTH); +} - blake2s_Final(&ctx, fingerprint, BLAKE2S_DIGEST_LENGTH); +secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m, + uint8_t key_n, const uint8_t *const *keys) { + // check header signature + + uint8_t fingerprint[32]; + get_image_fingerprint(hdr, fingerprint); ed25519_public_key pub; if (sectrue != compute_pubkey(key_m, key_n, keys, hdr->sigmask, pub)) diff --git a/core/embed/trezorhal/image.h b/core/embed/trezorhal/image.h index 21c1aa64b..ff29c4516 100644 --- a/core/embed/trezorhal/image.h +++ b/core/embed/trezorhal/image.h @@ -107,4 +107,6 @@ secbool __wur check_image_contents(const image_header *const hdr, uint32_t firstskip, const uint8_t *sectors, int blocks); +void get_image_fingerprint(const image_header *const hdr, uint8_t *const out); + #endif diff --git a/core/embed/trezorhal/touch/ft6x36.c b/core/embed/trezorhal/touch/ft6x36.c index 96b8690d2..f1b383c7b 100644 --- a/core/embed/trezorhal/touch/ft6x36.c +++ b/core/embed/trezorhal/touch/ft6x36.c @@ -133,7 +133,7 @@ static void _i2c_init(void) { i2c_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_OK != HAL_I2C_Init(&i2c_handle)) { - ensure(secfalse, NULL); + ensure(secfalse, "Touch screen panel was not loaded properly."); return; } } @@ -211,7 +211,7 @@ void touch_set_mode(void) { sectrue * (HAL_OK == HAL_I2C_Master_Transmit( &i2c_handle, TOUCH_ADDRESS, touch_panel_config, sizeof(touch_panel_config), 10)), - NULL); + "Touch screen panel was not loaded properly."); } void touch_power_on(void) { diff --git a/core/embed/unix/common.c b/core/embed/unix/common.c index 57d9e4944..6f4c7ee35 100644 --- a/core/embed/unix/common.c +++ b/core/embed/unix/common.c @@ -25,15 +25,22 @@ #include "common.h" #include "display.h" +#ifdef FANCY_FATAL_ERROR +#include "rust_ui.h" +#endif #include "memzero.h" extern void main_clean_exit(); -void __shutdown(void) { +void __attribute__((noreturn)) __shutdown(void) { printf("SHUTDOWN\n"); main_clean_exit(3); + for (;;) + ; } +void __attribute__((noreturn)) shutdown(void) { __shutdown(); } + #ifdef RGB16 #define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) #else @@ -46,6 +53,13 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func) { display_orientation(0); 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); + display_refresh(); +#else display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_printf("\nFATAL ERROR:\n"); printf("\nFATAL ERROR:\n"); @@ -74,42 +88,35 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, #endif display_printf("\n\n\nHint:\nIsn't the emulator already running?\n"); printf("Hint:\nIsn't the emulator already running?\n"); +#endif hal_delay(3000); - __shutdown(); - for (;;) - ; + shutdown(); } void __attribute__((noreturn)) -error_shutdown(const char *line1, const char *line2, const char *line3, - const char *line4) { +error_shutdown(const char *label, const char *msg) { +#ifdef FANCY_FATAL_ERROR + screen_error_shutdown_c(label, msg); + display_refresh(); +#else display_clear(); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR); int y = 32; - if (line1) { - display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - printf("%s\n", line1); + if (label) { + display_text(8, y, label, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("%s\n", label); y += 32; } - if (line2) { - display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - printf("%s\n", line2); - y += 32; - } - if (line3) { - display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - printf("%s\n", line3); - y += 32; - } - if (line4) { - display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); - printf("%s\n", line4); + if (msg) { + display_text(8, y, msg, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("%s\n", msg); y += 32; } y += 32; display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); printf("\nPlease unplug the device.\n"); +#endif display_backlight(255); hal_delay(5000); exit(4); @@ -153,3 +160,13 @@ void emulator_poll_events(void) { 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."); +} +void show_pin_too_many_screen(void) { + error_shutdown("DEVICE WIPED!", + "Too many wrong PIN attempts. Storage has been wiped."); +} diff --git a/core/embed/unix/common.h b/core/embed/unix/common.h index 9641f3b29..89d7da71d 100644 --- a/core/embed/unix/common.h +++ b/core/embed/unix/common.h @@ -40,12 +40,15 @@ }) #endif +void __attribute__((noreturn)) shutdown(void); + void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void __attribute__((noreturn)) -error_shutdown(const char *line1, const char *line2, const char *line3, - const char *line4); +error_shutdown(const char *label, const char *msg); +void show_wipe_code_screen(void); +void show_pin_too_many_screen(void); #define ensure(expr, msg) \ (((expr) == sectrue) \ diff --git a/legacy/common.c b/legacy/common.c index 77fe4b85a..f87bff509 100644 --- a/legacy/common.c +++ b/legacy/common.c @@ -115,3 +115,12 @@ uint32_t drbg_random32(void) { drbg_generate((uint8_t *)&value, sizeof(value)); return value; } + +void show_wipe_code_screen(void) { + error_shutdown("You have entered the", "wipe code. All private", + "data has been erased.", NULL); +} +void show_pin_too_many_screen(void) { + error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", + NULL); +} diff --git a/legacy/common.h b/legacy/common.h index 44ae32d9d..399818ba3 100644 --- a/legacy/common.h +++ b/legacy/common.h @@ -33,6 +33,8 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line, void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); +void show_wipe_code_screen(void); +void show_pin_too_many_screen(void); #define ensure(expr, msg) \ (((expr) == sectrue) \ diff --git a/storage/storage.c b/storage/storage.c index 80e5040eb..b8bac967b 100644 --- a/storage/storage.c +++ b/storage/storage.c @@ -992,8 +992,7 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) { static void ensure_not_wipe_code(const uint8_t *pin, size_t pin_len) { if (sectrue != is_not_wipe_code(pin, pin_len)) { storage_wipe(); - error_shutdown("You have entered the", "wipe code. All private", - "data has been erased.", NULL); + show_wipe_code_screen(); } } @@ -1028,8 +1027,7 @@ static secbool unlock(const uint8_t *pin, size_t pin_len, wait_random(); if (ctr >= PIN_MAX_TRIES) { storage_wipe(); - error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", - NULL); + show_pin_too_many_screen(); return secfalse; } @@ -1091,8 +1089,7 @@ static secbool unlock(const uint8_t *pin, size_t pin_len, wait_random(); if (ctr + 1 >= PIN_MAX_TRIES) { storage_wipe(); - error_shutdown("Too many wrong PIN", "attempts. Storage has", - "been wiped.", NULL); + show_pin_too_many_screen(); } return secfalse; } diff --git a/storage/tests/c/common.c b/storage/tests/c/common.c index 252b1bbfe..82234756b 100644 --- a/storage/tests/c/common.c +++ b/storage/tests/c/common.c @@ -46,12 +46,5 @@ void __fatal_error(const char *expr, const char *msg, const char *file, __shutdown(); } -void error_shutdown(const char *line1, const char *line2, const char *line3, - const char *line4) { - // For testing do not treat pin_fails_check_max as a fatal error. - (void)line1; - (void)line2; - (void)line3; - (void)line4; - return; -} +void show_wipe_code_screen(void) {} +void show_pin_too_many_screen(void) {} diff --git a/storage/tests/c/common.h b/storage/tests/c/common.h index b24d9ebfe..845dbf0c0 100644 --- a/storage/tests/c/common.h +++ b/storage/tests/c/common.h @@ -24,8 +24,9 @@ void __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); -void error_shutdown(const char *line1, const char *line2, const char *line3, - const char *line4); + +void show_wipe_code_screen(void); +void show_pin_too_many_screen(void); #define ensure(expr, msg) \ (((expr) == sectrue) \