diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 6f7d0a9bd4..ed5fd7fa31 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -174,7 +174,7 @@ env.Replace( '-fstack-protector-strong ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS=['-Tbuild/bootloader/memory.ld', '-Wl,--gc-sections', '-Wl,-Map=build/bootloader/bootloader.map', '-Wl,--warn-common', '-Wl,--print-memory-usage'], + LINKFLAGS=['-Tbuild/bootloader/memory.ld', '-Wl,--gc-sections', '-Wl,-Map=build/bootloader/bootloader.map', '-Wl,--warn-common', '-Wl,--print-memory-usage', '-Wl,--undefined=__errno'], CPPPATH=ALLPATHS, CPPDEFINES=[ 'BOOTLOADER', diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c index 64c1c73796..24bfd34157 100644 --- a/core/embed/projects/bootloader/main.c +++ b/core/embed/projects/bootloader/main.c @@ -65,6 +65,9 @@ #ifdef USE_BLE #include #endif +#ifdef USE_POWERCTL +#include +#endif #ifdef USE_BLE #include "wire/wire_iface_ble.h" @@ -157,6 +160,9 @@ static void drivers_deinit(void) { #endif #endif display_deinit(DISPLAY_JUMP_BEHAVIOR); +#ifdef USE_POWERCTL + powerctl_deinit(); +#endif } static secbool check_vendor_header_lock(const vendor_header *const vhdr) { @@ -336,6 +342,10 @@ int bootloader_main(void) { firmware_present_backup = firmware_present; } +#ifdef USE_POWERCTL + powerctl_init(); +#endif + #if PRODUCTION && !defined STM32U5 // for STM32U5, this check is moved to boardloader ensure_bootloader_min_version(); diff --git a/core/embed/projects/bootloader/workflow/wf_bootloader.c b/core/embed/projects/bootloader/workflow/wf_bootloader.c index ef35362acb..58faa213ff 100644 --- a/core/embed/projects/bootloader/workflow/wf_bootloader.c +++ b/core/embed/projects/bootloader/workflow/wf_bootloader.c @@ -23,6 +23,13 @@ #include #include +#ifdef USE_POWERCTL +#include +#endif + +#include +#include + #include "antiglitch.h" #include "bootui.h" #include "rust_ui_bootloader.h" @@ -53,6 +60,14 @@ workflow_result_t workflow_menu(const vendor_header* const vhdr, workflow_ble_pairing_request(vhdr, hdr); continue; } +#endif +#ifdef USE_POWERCTL + if (menu_result == MENU_POWER_OFF) { // reboot + display_fade(display_get_backlight(), 0, 200); + powerctl_hibernate(); + // in case hibernation failed, continue with menu + continue; + } #endif if (menu_result == MENU_REBOOT) { // reboot jump_allow_1(); diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml index 7e147e4531..c54fdfd9c8 100644 --- a/core/embed/rust/Cargo.toml +++ b/core/embed/rust/Cargo.toml @@ -44,6 +44,7 @@ usb = [] optiga = [] ble = [] tropic = [] +powerctl = [] translations = ["crypto"] test = [ "backlight", diff --git a/core/embed/rust/rust_ui_bootloader.h b/core/embed/rust/rust_ui_bootloader.h index 7402d2b8b5..db61551674 100644 --- a/core/embed/rust/rust_ui_bootloader.h +++ b/core/embed/rust/rust_ui_bootloader.h @@ -67,6 +67,7 @@ typedef enum { MENU_REBOOT = 0x11223344, MENU_WIPE = 0x55667788, MENU_BLUETOOTH = 0x99AABBCC, + MENU_POWER_OFF = 0x751A5BEF, } menu_result_t; void screen_menu(bool initial_setup, secbool firmware_present, c_layout_t* layout); diff --git a/core/embed/rust/src/ui/layout_bolt/bootloader/menu.rs b/core/embed/rust/src/ui/layout_bolt/bootloader/menu.rs index 78943814ec..906979f9c9 100644 --- a/core/embed/rust/src/ui/layout_bolt/bootloader/menu.rs +++ b/core/embed/rust/src/ui/layout_bolt/bootloader/menu.rs @@ -27,6 +27,7 @@ pub enum MenuMsg { Reboot = 0x11223344, FactoryReset = 0x55667788, Bluetooth = 0x99AABBCC, + PowerOff = 0x751A5BEF, } pub struct Menu { @@ -36,6 +37,7 @@ pub struct Menu { reboot: Button, reset: Button, bluetooth: Button, + poweroff: Button, } impl Menu { @@ -43,6 +45,7 @@ impl Menu { let content_reboot = IconText::new("REBOOT TREZOR", Icon::new(REFRESH24)); let content_reset = IconText::new("FACTORY RESET", Icon::new(FIRE24)); let content_bluetooth = IconText::new("BLUETOOTH", Icon::new(FIRE24)); + let content_poweroff = IconText::new("POWER OFF", Icon::new(FIRE24)); let mut instance = Self { bg: Pad::with_background(BLD_BG), @@ -59,6 +62,7 @@ impl Menu { reset: Button::with_icon_and_text(content_reset).styled(button_bld()), bluetooth: Button::with_icon_and_text(content_bluetooth).styled(button_bld()), + poweroff: Button::with_icon_and_text(content_poweroff).styled(button_bld()), }; instance.bg.clear(); instance @@ -89,6 +93,8 @@ impl Component for Menu { self.reset.place(self.get_button_pos(1)); #[cfg(feature = "ble")] self.bluetooth.place(self.get_button_pos(2)); + #[cfg(feature = "powerctl")] + self.poweroff.place(self.get_button_pos(3)); bounds } @@ -106,6 +112,10 @@ impl Component for Menu { if let Some(Clicked) = self.bluetooth.event(ctx, event) { return Some(Self::Msg::Bluetooth); } + #[cfg(feature = "powerctl")] + if let Some(Clicked) = self.poweroff.event(ctx, event) { + return Some(Self::Msg::PowerOff); + } None } @@ -118,5 +128,7 @@ impl Component for Menu { self.reset.render(target); #[cfg(feature = "ble")] self.bluetooth.render(target); + #[cfg(feature = "powerctl")] + self.poweroff.render(target); } } diff --git a/core/embed/sys/powerctl/unix/powerctl.c b/core/embed/sys/powerctl/unix/powerctl.c new file mode 100644 index 0000000000..3457707521 --- /dev/null +++ b/core/embed/sys/powerctl/unix/powerctl.c @@ -0,0 +1,31 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +bool powerctl_init(void) { return true; } + +void powerctl_deinit(void) {} + +bool powerctl_hibernate(void) { + exit(1); + return true; +} diff --git a/core/site_scons/models/T3W1/emulator.py b/core/site_scons/models/T3W1/emulator.py index 89e841eea4..449ae528dc 100644 --- a/core/site_scons/models/T3W1/emulator.py +++ b/core/site_scons/models/T3W1/emulator.py @@ -105,6 +105,13 @@ def configure( features_available.append("ble") defines += [("USE_BLE", "1")] + sources += [ + "embed/sys/powerctl/unix/powerctl.c", + ] + defines += [("USE_POWERCTL", "1")] + paths += ["embed/sys/powerctl/inc"] + features_available.append("powerctl") + features_available.append("backlight") defines += [("USE_BACKLIGHT", "1")] diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py index dc70835927..00c366ba43 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py @@ -243,6 +243,7 @@ def configure( ] paths += ["embed/sys/powerctl/inc"] defines += [("USE_POWERCTL", "1")] + features_available.append("powerctl") env.get("ENV")["LINKER_SCRIPT"] = linker_script diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py index 8e99a4f499..6fccad6796 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py @@ -250,6 +250,7 @@ def configure( ] paths += ["embed/sys/powerctl/inc"] defines += [("USE_POWERCTL", "1")] + features_available.append("powerctl") env.get("ENV")["LINKER_SCRIPT"] = linker_script diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py index 54270b32d1..42361ab68d 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py @@ -250,6 +250,7 @@ def configure( ] paths += ["embed/sys/powerctl/inc"] defines += [("USE_POWERCTL", "1")] + features_available.append("powerctl") env.get("ENV")["LINKER_SCRIPT"] = linker_script