diff --git a/common/protob/messages-management.proto b/common/protob/messages-management.proto index e2b14bf8f5..79e3bce954 100644 --- a/common/protob/messages-management.proto +++ b/common/protob/messages-management.proto @@ -124,6 +124,8 @@ message Features { optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf 144x144, 2 = jpg 240x240 optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host? optional string internal_model = 44; // internal model name + optional uint32 unit_color = 45; // color of the unit/device + optional bool unit_btconly = 46; // unit/device is intended as bitcoin only } /** diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 5cd381ad7f..52d7738f61 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -74,6 +74,7 @@ CPPPATH_MOD += [ ] SOURCE_MOD += [ + 'embed/lib/unit_variant.c', 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display.c', diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 6519d4f7fa..ebb5391aea 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -173,6 +173,7 @@ CPPPATH_MOD += [ 'vendor/micropython/lib/uzlib', ] SOURCE_MOD += [ + 'embed/lib/unit_variant.c', 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display.c', diff --git a/core/SConscript.unix b/core/SConscript.unix index 65d57f8148..078b6c4df7 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -171,6 +171,7 @@ CPPPATH_MOD += [ 'vendor/micropython/lib/uzlib', ] SOURCE_MOD += [ + 'embed/lib/unit_variant.c', 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display.c', diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 3f66c88d91..c0c0421cc5 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -56,6 +56,7 @@ #include "bootui.h" #include "messages.h" #include "rust_ui.h" +#include "unit_variant.h" const uint8_t BOOTLOADER_KEY_M = 2; const uint8_t BOOTLOADER_KEY_N = 3; @@ -343,6 +344,8 @@ int bootloader_main(void) { rgb_led_init(); #endif + unit_variant_init(); + #if PRODUCTION check_bootloader_version(); #endif diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index b35f06470f..488861a98b 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -28,6 +28,7 @@ #include "flash.h" #include "image.h" #include "secbool.h" +#include "unit_variant.h" #include "usb.h" #include "version.h" @@ -305,6 +306,10 @@ static void send_msg_features(uint8_t iface_num, } else { MSG_SEND_ASSIGN_VALUE(firmware_present, false); } + if (unit_variant_present()) { + MSG_SEND_ASSIGN_VALUE(unit_color, unit_variant_get_color()); + MSG_SEND_ASSIGN_VALUE(unit_btconly, unit_variant_get_btconly()); + } MSG_SEND(Features); } diff --git a/core/embed/bootloader/protob/messages.pb.h b/core/embed/bootloader/protob/messages.pb.h index 5c8b66766f..777f5e22e2 100644 --- a/core/embed/bootloader/protob/messages.pb.h +++ b/core/embed/bootloader/protob/messages.pb.h @@ -93,6 +93,10 @@ typedef struct _Features { char fw_vendor[256]; bool has_internal_model; char internal_model[17]; + bool has_unit_color; + uint32_t unit_color; + bool has_unit_btconly; + bool unit_btconly; } Features; typedef struct _FirmwareErase { @@ -144,7 +148,7 @@ extern "C" { /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, ""} +#define Features_init_default {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} #define Ping_init_default {false, ""} #define Success_init_default {false, ""} #define Failure_init_default {false, _FailureType_MIN, false, ""} @@ -155,7 +159,7 @@ extern "C" { #define FirmwareUpload_init_default {{{NULL}, NULL}, false, {0, {0}}} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, ""} +#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} #define Ping_init_zero {false, ""} #define Success_init_zero {false, ""} #define Failure_init_zero {false, _FailureType_MIN, false, ""} @@ -186,6 +190,8 @@ extern "C" { #define Features_fw_patch_tag 24 #define Features_fw_vendor_tag 25 #define Features_internal_model_tag 44 +#define Features_unit_color_tag 45 +#define Features_unit_btconly_tag 46 #define FirmwareErase_length_tag 1 #define FirmwareRequest_offset_tag 1 #define FirmwareRequest_length_tag 2 @@ -222,7 +228,9 @@ X(a, STATIC, OPTIONAL, UINT32, fw_major, 22) \ X(a, STATIC, OPTIONAL, UINT32, fw_minor, 23) \ X(a, STATIC, OPTIONAL, UINT32, fw_patch, 24) \ X(a, STATIC, OPTIONAL, STRING, fw_vendor, 25) \ -X(a, STATIC, OPTIONAL, STRING, internal_model, 44) +X(a, STATIC, OPTIONAL, STRING, internal_model, 44) \ +X(a, STATIC, OPTIONAL, UINT32, unit_color, 45) \ +X(a, STATIC, OPTIONAL, BOOL, unit_btconly, 46) #define Features_CALLBACK NULL #define Features_DEFAULT NULL @@ -299,7 +307,7 @@ extern const pb_msgdesc_t FirmwareUpload_msg; #define ButtonAck_size 0 #define ButtonRequest_size 2 #define Failure_size 260 -#define Features_size 477 +#define Features_size 487 #define FirmwareErase_size 6 #define FirmwareRequest_size 12 #define GetFeatures_size 0 diff --git a/core/embed/bootloader/protob/messages.proto b/core/embed/bootloader/protob/messages.proto index a8438df5cc..23b22d6e4d 100644 --- a/core/embed/bootloader/protob/messages.proto +++ b/core/embed/bootloader/protob/messages.proto @@ -57,6 +57,8 @@ message Features { optional string fw_vendor = 25; // reported firmware vendor if in bootloader mode // optional bytes fw_vendor_keys = 26; // obsoleted, use fw_vendor optional string internal_model = 44; // internal model name + optional uint32 unit_color = 45; // color of the unit/device + optional bool unit_btconly = 46; // unit/device is intended as bitcoin only } /** diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils.c b/core/embed/extmod/modtrezorutils/modtrezorutils.c index f265b9942f..0eecb3e5f0 100644 --- a/core/embed/extmod/modtrezorutils/modtrezorutils.c +++ b/core/embed/extmod/modtrezorutils/modtrezorutils.c @@ -34,6 +34,7 @@ #include "blake2s.h" #include "common.h" #include "flash.h" +#include "unit_variant.h" #include "usb.h" #include TREZOR_BOARD #include "model.h" @@ -211,6 +212,32 @@ STATIC mp_obj_t mod_trezorutils_firmware_vendor(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_firmware_vendor_obj, mod_trezorutils_firmware_vendor); +/// def unit_color() -> int | None: +/// """ +/// Returns the color of the unit. +/// """ +STATIC mp_obj_t mod_trezorutils_unit_color(void) { + if (!unit_variant_present()) { + return mp_const_none; + } + return mp_obj_new_int(unit_variant_get_color()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_unit_color_obj, + mod_trezorutils_unit_color); + +/// def unit_btconly() -> bool | None: +/// """ +/// Returns True if the unit is BTConly. +/// """ +STATIC mp_obj_t mod_trezorutils_unit_btconly(void) { + if (!unit_variant_present()) { + return mp_const_none; + } + return unit_variant_get_btconly() ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_unit_btconly_obj, + mod_trezorutils_unit_btconly); + /// def reboot_to_bootloader() -> None: /// """ /// Reboots to bootloader. @@ -248,6 +275,10 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { MP_ROM_PTR(&mod_trezorutils_firmware_vendor_obj)}, {MP_ROM_QSTR(MP_QSTR_reboot_to_bootloader), MP_ROM_PTR(&mod_trezorutils_reboot_to_bootloader_obj)}, + {MP_ROM_QSTR(MP_QSTR_unit_color), + MP_ROM_PTR(&mod_trezorutils_unit_color_obj)}, + {MP_ROM_QSTR(MP_QSTR_unit_btconly), + MP_ROM_PTR(&mod_trezorutils_unit_btconly_obj)}, // various built-in constants {MP_ROM_QSTR(MP_QSTR_SCM_REVISION), MP_ROM_PTR(&mod_trezorutils_revision_obj)}, diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index b788f7b99b..8e51394338 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -63,6 +63,7 @@ #ifdef USE_SD_CARD #include "sdcard.h" #endif +#include "unit_variant.h" #ifdef SYSTEM_VIEW #include "systemview.h" @@ -100,6 +101,8 @@ int main(void) { #if !defined TREZOR_MODEL_1 parse_boardloader_capabilities(); + unit_variant_init(); + #if PRODUCTION || BOOTLOADER_QA check_and_replace_bootloader(); #endif diff --git a/core/embed/lib/unit_variant.c b/core/embed/lib/unit_variant.c new file mode 100644 index 0000000000..d766f6098f --- /dev/null +++ b/core/embed/lib/unit_variant.c @@ -0,0 +1,35 @@ +#include "unit_variant.h" +#include "flash.h" + +static uint8_t unit_variant_color = 0; +static bool unit_variant_btconly = false; +static bool unit_variant_ok = false; + +static void unit_variant_0x01(const uint8_t *data) { + unit_variant_color = data[1]; + unit_variant_btconly = data[2] == 1; + unit_variant_ok = true; +} + +void unit_variant_init(void) { + uint8_t data[FLASH_OTP_BLOCK_SIZE]; + + secbool result = flash_otp_read(FLASH_OTP_BLOCK_DEVICE_VARIANT, 0, data, + FLASH_OTP_BLOCK_SIZE); + + if (sectrue == result) { + switch (data[0]) { + case 0x01: + unit_variant_0x01(data); + break; + default: + break; + } + } +} + +uint8_t unit_variant_get_color(void) { return unit_variant_color; } + +bool unit_variant_get_btconly(void) { return unit_variant_btconly; } + +bool unit_variant_present(void) { return unit_variant_ok; } diff --git a/core/embed/lib/unit_variant.h b/core/embed/lib/unit_variant.h new file mode 100644 index 0000000000..110af26602 --- /dev/null +++ b/core/embed/lib/unit_variant.h @@ -0,0 +1,12 @@ +#ifndef _UNIT_VARIANT_H +#define _UNIT_VARIANT_H + +#include +#include + +void unit_variant_init(void); +bool unit_variant_present(void); +uint8_t unit_variant_get_color(void); +bool unit_variant_get_btconly(void); + +#endif //_UNIT_VARIANT_H diff --git a/core/embed/trezorhal/flash.h b/core/embed/trezorhal/flash.h index 039409f8ff..8222894054 100644 --- a/core/embed/trezorhal/flash.h +++ b/core/embed/trezorhal/flash.h @@ -112,6 +112,7 @@ secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); #define FLASH_OTP_BLOCK_BOOTLOADER_VERSION 1 #define FLASH_OTP_BLOCK_VENDOR_HEADER_LOCK 2 #define FLASH_OTP_BLOCK_RANDOMNESS 3 +#define FLASH_OTP_BLOCK_DEVICE_VARIANT 4 secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen); diff --git a/core/mocks/generated/trezorutils.pyi b/core/mocks/generated/trezorutils.pyi index 5cc799868e..28c7250876 100644 --- a/core/mocks/generated/trezorutils.pyi +++ b/core/mocks/generated/trezorutils.pyi @@ -60,6 +60,20 @@ def firmware_vendor() -> str: """ +# extmod/modtrezorutils/modtrezorutils.c +def unit_color() -> int | None: + """ + Returns the color of the unit. + """ + + +# extmod/modtrezorutils/modtrezorutils.c +def unit_btconly() -> bool | None: + """ + Returns True if the unit is BTConly. + """ + + # extmod/modtrezorutils/modtrezorutils.c def reboot_to_bootloader() -> None: """ diff --git a/core/src/apps/base.py b/core/src/apps/base.py index 584a1d50cc..28d13bfbc8 100644 --- a/core/src/apps/base.py +++ b/core/src/apps/base.py @@ -63,6 +63,8 @@ def get_features() -> Features: unlocked=config.is_unlocked(), busy=busy_expiry_ms() > 0, homescreen_format=HomescreenFormat.Jpeg240x240, + unit_color=utils.unit_color(), + unit_btconly=utils.unit_btconly(), ) if utils.BITCOIN_ONLY: diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 865b5e67d8..8cd432f993 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -2110,6 +2110,8 @@ if TYPE_CHECKING: homescreen_format: "HomescreenFormat | None" hide_passphrase_from_host: "bool | None" internal_model: "str | None" + unit_color: "int | None" + unit_btconly: "bool | None" def __init__( self, @@ -2155,6 +2157,8 @@ if TYPE_CHECKING: homescreen_format: "HomescreenFormat | None" = None, hide_passphrase_from_host: "bool | None" = None, internal_model: "str | None" = None, + unit_color: "int | None" = None, + unit_btconly: "bool | None" = None, ) -> None: pass diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py index 5ba1bf8f6f..243405fa8b 100644 --- a/core/src/trezor/utils.py +++ b/core/src/trezor/utils.py @@ -16,6 +16,8 @@ from trezorutils import ( # noqa: F401 halt, memcpy, reboot_to_bootloader, + unit_btconly, + unit_color, ) from typing import TYPE_CHECKING diff --git a/docs/core/misc/memory.md b/docs/core/misc/memory.md index 4d28ee30c1..1f1c595d95 100644 --- a/docs/core/misc/memory.md +++ b/docs/core/misc/memory.md @@ -37,7 +37,7 @@ | block 1 | 0x1FFF7820 - 0x1FFF783F | 32 B | bootloader downgrade protection | block 2 | 0x1FFF7840 - 0x1FFF785F | 32 B | vendor keys lock | block 3 | 0x1FFF7860 - 0x1FFF787F | 32 B | entropy/randomness -| block 4 | 0x1FFF7880 - 0x1FFF789F | 32 B | unused +| block 4 | 0x1FFF7880 - 0x1FFF789F | 32 B | device variant information | block 5 | 0x1FFF78A0 - 0x1FFF78BF | 32 B | unused | block 6 | 0x1FFF78C0 - 0x1FFF78DF | 32 B | unused | block 7 | 0x1FFF78E0 - 0x1FFF78FF | 32 B | unused diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index b99cd9cd54..1d26e30152 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -3161,6 +3161,8 @@ class Features(protobuf.MessageType): 42: protobuf.Field("homescreen_format", "HomescreenFormat", repeated=False, required=False, default=None), 43: protobuf.Field("hide_passphrase_from_host", "bool", repeated=False, required=False, default=None), 44: protobuf.Field("internal_model", "string", repeated=False, required=False, default=None), + 45: protobuf.Field("unit_color", "uint32", repeated=False, required=False, default=None), + 46: protobuf.Field("unit_btconly", "bool", repeated=False, required=False, default=None), } def __init__( @@ -3208,6 +3210,8 @@ class Features(protobuf.MessageType): homescreen_format: Optional["HomescreenFormat"] = None, hide_passphrase_from_host: Optional["bool"] = None, internal_model: Optional["str"] = None, + unit_color: Optional["int"] = None, + unit_btconly: Optional["bool"] = None, ) -> None: self.capabilities: Sequence["Capability"] = capabilities if capabilities is not None else [] self.major_version = major_version @@ -3251,6 +3255,8 @@ class Features(protobuf.MessageType): self.homescreen_format = homescreen_format self.hide_passphrase_from_host = hide_passphrase_from_host self.internal_model = internal_model + self.unit_color = unit_color + self.unit_btconly = unit_btconly class LockDevice(protobuf.MessageType):