feat(core): use Cargo as the build system for C code
What changed, and why it matters
This is a massive Trezor firmware commit that replaces the old SCons-based build system with Cargo (Rust's build tool) for compiling the embedded C code. It adds many new Cargo.toml files, build.rs scripts, and a custom xbuild helper crate, but does not change the actual security logic of the wallet. The main risk is that a build-system change of this size could accidentally alter compiler flags, included source files, or linker settings, which might affect the produced binary. There is no direct vulnerability shown in the diff, and the commit message explicitly says it is a feature with no changelog entry.
Treat this as a build-infrastructure change rather than a security patch. Review the new xbuild crate for correct propagation of security-relevant compiler flags (stack protection, LTO, optimization, TrustZone/CMSE flags, short-enums consistency), verify that the produced binaries match expected source sets and linker scripts, and run the existing hardware-in-the-loop and emulator test suites before release. No immediate user action is required.
Security signals we found
Large build-system refactor with potential for accidental changes in compiler flags, source inclusion, or linker scripts
New custom build helper (xbuild) now controls C compilation, bindgen, and binary embedding
No direct changes to crypto, secure storage, or protocol handling code observed
No vendor security disclosure, CVE, or researcher attribution present
Evidence from the diff
The commit migrates the Trezor Core embedded firmware build from SCons to Cargo. It introduces a Cargo workspace under core/embed, adds per-crate build.rs scripts that invoke a new xbuild crate to compile C sources, and defines feature flags mapping to hardware models and MCU families. The diff shows build configuration, dependency declarations, and source-list selection, but no changes to cryptographic, storage, USB, or bootloader runtime logic. The Makefile clippy target is redirected from embed/rust to embed/rust-staticlib. Verified references do not indicate any security incident or disclosure.
Changed components
core/Makefilecore/embed build configuration (Cargo workspace, build.rs files)core/embed/xbuild custom build helpercore/embed/projects/{boardloader,bootloader,bootloader_ci,firmware,kernel,prodtest,secmon,unix}core/embed/{models,rtl,sys,sec,io,upymod,rust,rust-staticlib}Inspect captured patch +416836 / −276
diff --git a/core/Makefile b/core/Makefile
index 71d8f624..22dcdbeb 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -279,7 +279,7 @@ pyright:
clippy:
export BUILD_DIR=$(abspath $(UNIX_BUILD_DIR)) ; \
- cd embed/rust ; cargo clippy $(TESTOPTS) --all-features --target=$(RUST_TARGET)
+ cd embed/rust-staticlib ; cargo clippy $(TESTOPTS) --all-features --target=$(RUST_TARGET)
audit_rust: ## run cargo audit on rust dependencies
cd embed/rust ; cargo audit
diff --git a/core/embed/.cargo/config.toml b/core/embed/.cargo/config.toml
new file mode 100644
index 00000000..a4d08cb7
--- /dev/null
+++ b/core/embed/.cargo/config.toml
@@ -0,0 +1,48 @@
+[build]
+target-dir = "../build-xtask"
+#rustc-wrapper = "sccache"
+
+[alias]
+xtask = "run -p xtask --"
+
+[target.x86_64-unknown-linux-gnu]
+
+[target.aarch64-apple-darwin]
+
+[target.thumbv7em-none-eabihf]
+linker = "arm-none-eabi-gcc"
+rustflags = [
+ "-C",
+ "target-cpu=cortex-m4",
+ "-C",
+ "link-arg=-mthumb",
+ "-C",
+ "link-arg=-mcpu=cortex-m4",
+ "-C",
+ "link-arg=-mfloat-abi=hard",
+ "-C",
+ "link-arg=-mfpu=fpv4-sp-d16",
+ # Adds an ELF section with Rust functions' stack sizes. See the following links for more details:
+ # - https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/emit-stack-sizes.html
+ # - https://blog.japaric.io/stack-analysis/
+ # - https://github.com/japaric/stack-sizes/
+ "-Z",
+ "emit-stack-sizes",
+]
+
+[target.thumbv8m.main-none-eabihf]
+linker = "arm-none-eabi-gcc"
+rustflags = [
+ "-C",
+ "target-cpu=cortex-m33",
+ "-C",
+ "link-arg=-mthumb",
+ "-C",
+ "link-arg=-mcpu=cortex-m33",
+ "-C",
+ "link-arg=-mfloat-abi=hard",
+ "-C",
+ "link-arg=-mfpu=fpv5-sp-d16",
+ "-Z",
+ "emit-stack-sizes",
+]
diff --git a/core/embed/Cargo.lock b/core/embed/Cargo.lock
new file mode 100644
index 00000000..c6c25a9b
--- /dev/null
+++ b/core/embed/Cargo.lock
@@ -0,0 +1,1030 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addr2line"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "alloc-traits"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483"
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "backtrace"
+version = "0.3.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-link",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.72.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
+name = "boardloader"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "xbuild",
+]
+
+[[package]]
+name = "bootloader"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "trezor_lib",
+ "xbuild",
+]
+
+[[package]]
+name = "bootloader_ci"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "xbuild",
+]
+
+[[package]]
+name = "bstr"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "camino"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "cargo-platform"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
+
+[[package]]
+name = "color-eyre"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d"
+dependencies = [
+ "backtrace",
+ "eyre",
+ "indenter",
+ "once_cell",
+ "owo-colors",
+]
+
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+
+[[package]]
+name = "easer"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fba524f8b83c9c5bde02c2bb1627de9d1f81980489a6d54168cdfd08c258f917"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "eyre"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
+dependencies = [
+ "indenter",
+ "once_cell",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "firmware"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "trezor_lib",
+ "upymod",
+ "xbuild",
+]
+
+[[package]]
+name = "gimli"
+version = "0.32.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
+
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
+[[package]]
+name = "globset"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "log",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "hash32"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "heapless"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed"
+dependencies = [
+ "hash32",
+ "stable_deref_trait",
+ "ufmt",
+ "ufmt-write",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "indenter"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
+
+[[package]]
+name = "io"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "sec",
+ "sys",
+ "xbuild",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
+
+[[package]]
+name = "kernel"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "trezor_lib",
+ "xbuild",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.177"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "minicbor"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "734daad4ff3b880f23dc2a675dd74553fa8e583367aa7523f96a16e96a516b62"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "models"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "xbuild",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+ "libm",
+]
+
+[[package]]
+name = "object"
+version = "0.37.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "owo-colors"
+version = "4.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d"
+
+[[package]]
+name = "pareen"
+version = "0.3.3"
+dependencies = [
+ "easer",
+ "num-traits",
+]
+
+[[package]]
+name = "pathdiff"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "prodtest"
+version = "0.0.0"
+dependencies = [
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "trezor_lib",
+ "xbuild",
+]
+
+[[package]]
+name = "qrcodegen"
+version = "1.8.0"
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "rtl"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "models",
+ "xbuild",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
+name = "rustix"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
+[[package]]
+name = "sec"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "models",
+ "rtl",
+ "sys",
+ "xbuild",
+]
+
+[[package]]
+name = "secmon"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "xbuild",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "static-alloc"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e1e06c73b06b04d730f68ecb5f805e86b8d509cf80072a28128160025fbf928"
+dependencies = [
+ "alloc-traits",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sys"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "models",
+ "rtl",
+ "xbuild",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
+dependencies = [
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "trezor-tjpgdec"
+version = "0.1.0"
+
+[[package]]
+name = "trezor_lib"
+version = "0.1.0"
+dependencies = [
+ "bindgen",
+ "cc",
+ "cfg-if",
+ "cty",
+ "easer",
+ "glob",
+ "heapless",
+ "hex",
+ "io",
+ "log",
+ "minicbor",
+ "num-derive",
+ "num-traits",
+ "pareen",
+ "qrcodegen",
+ "serde_json",
+ "spin",
+ "static-alloc",
+ "trezor-tjpgdec",
+ "ufmt",
+ "unsize",
+ "upymod",
+ "without-alloc",
+ "xbuild",
+ "zeroize",
+]
+
+[[package]]
+name = "trezor_lib_staticlib"
+version = "0.1.0"
+dependencies = [
+ "trezor_lib",
+]
+
+[[package]]
+name = "ufmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a64846ec02b57e9108d6469d98d1648782ad6bb150a95a9baac26900bbeab9d"
+dependencies = [
+ "ufmt-macros",
+ "ufmt-write",
+]
+
+[[package]]
+name = "ufmt-macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d337d3be617449165cb4633c8dece429afd83f84051024079f97ad32a9663716"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ufmt-write"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unix"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "sys",
+ "trezor_lib",
+ "upymod",
+ "xbuild",
+]
+
+[[package]]
+name = "unsize"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fa7a7a734c1a5664a662ddcea0b6c9472a21da8888c957c7f1eaa09dba7a939"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "upymod"
+version = "0.0.0"
+dependencies = [
+ "color-eyre",
+ "io",
+ "models",
+ "rtl",
+ "sec",
+ "xbuild",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "without-alloc"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375db0478b203b950ef10d1cce23cdbe5f30c2454fd9e7673ff56656df23adbb"
+dependencies = [
+ "alloc-traits",
+ "unsize",
+]
+
+[[package]]
+name = "xbuild"
+version = "0.1.0"
+dependencies = [
+ "bindgen",
+ "cc",
+ "color-eyre",
+ "globset",
+ "pathdiff",
+ "pkg-config",
+ "serde_json",
+ "zlib-rs",
+]
+
+[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "cargo_metadata",
+ "clap",
+ "owo-colors",
+ "serde_json",
+ "tempfile",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+
+[[package]]
+name = "zlib-rs"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513"
diff --git a/core/embed/Cargo.toml b/core/embed/Cargo.toml
new file mode 100644
index 00000000..fa68580a
--- /dev/null
+++ b/core/embed/Cargo.toml
@@ -0,0 +1,102 @@
+cargo-features = ["panic-immediate-abort"]
+
+[workspace]
+members = [
+ "models",
+ "rtl",
+ "sys",
+ "sec",
+ "io",
+ "upymod",
+ "rust",
+ "rust-staticlib",
+ "projects/boardloader",
+ "projects/bootloader",
+ "projects/bootloader_ci",
+ "projects/secmon",
+ "projects/kernel",
+ "projects/prodtest",
+ "projects/unix",
+ "projects/firmware",
+ "xbuild",
+ "xtask",
+]
+
+resolver = "3"
+
+[profile.dev]
+panic = "abort"
+split-debuginfo = "off"
+debug = 2
+
+[profile.debug-opt] # size optimized debug build
+inherits = "dev"
+panic = "abort"
+opt-level = "z"
+lto = true
+codegen-units = 1
+split-debuginfo = "off"
+debug = 2
+
+[profile.release]
+panic = "immediate-abort"
+opt-level = "z"
+lto = true
+codegen-units = 1
+split-debuginfo = "off"
+debug = 2
+
+[profile.release.package.trezor-tjpgdec]
+opt-level = 3
+
+[profile.test]
+split-debuginfo = "off"
+debug = 2
+
+[workspace.dependencies]
+cfg-if = "1.0"
+cty = "0.2.2"
+easer = { version = "0.3.0", default-features = false, features = ["libm"] }
+heapless = { version = "0.9.2", features = ["ufmt"], default-features = false }
+log = { version = "0.4.29", features = ["max_level_trace", "release_max_level_off"] }
+minicbor = { version = "1.0.0", default-features = false }
+num-derive = "0.4.2"
+num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
+pareen = { version = "0.3.3", path = "../../rust/pareen", default-features = false, features = ["libm", "easer"] }
+qrcodegen = { version = "1.8.0", path = "../vendor/QR-Code-generator/rust-no-heap" }
+spin = { version = "0.9.8", features = ["rwlock"], default-features = false }
+static-alloc = "0.2.6"
+trezor-tjpgdec = { version = "0.1.0", path = "../../rust/trezor-tjpgdec" }
+ufmt = "0.2.0"
+unsize = "1.1.0"
+without-alloc = "0.2.2"
+zeroize = { version = "1.8.2", default-features = false }
+
+models = { path = "models" }
+rtl = { path = "rtl" }
+sys = { path = "sys" }
+sec = { path = "sec" }
+io = { path = "io" }
+upymod = { path = "upymod" }
+trezor_lib = { path = "rust", default-features = false }
+
+# xbuild and xtask dependencies
+
+anyhow = "1.0"
+bindgen = { version = "0.72.1", default-features = false, features = ["runtime"] }
+cargo_metadata = "0.23.1"
+cc = "1.0.69"
+clap = { version = "4.6.0", default-features = false }
+color-eyre = { version = "0.6.5", default-features = false, features = ["track-caller"] }
+glob = "0.3.0"
+globset = "0.4.18"
+hex = "0.4.3"
+owo-colors = "4.3.0"
+pathdiff = "0.2.3"
+pkg-config = "0.3.28"
+rand = { version = "0.10.1", default-features = false }
+serde_json = "1.0.145"
+tempfile = { version = "3.25.0", default-features = false }
+zlib-rs = "0.6.3"
+
+xbuild = { path = "xbuild" }
diff --git a/core/embed/io/Cargo.toml b/core/embed/io/Cargo.toml
new file mode 100644
index 00000000..edbc0fe5
--- /dev/null
+++ b/core/embed/io/Cargo.toml
@@ -0,0 +1,114 @@
+[package]
+name = "io"
+version = "0.0.0"
+edition = "2024"
+links = "io"
+
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+sec.workspace = true
+sys.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = ["sec/model_d001", "touch_stmpe811"]
+model_d002 = ["sec/model_d002", "backlight_pin", "touch_sitronix"]
+model_t2t1 = ["sec/model_t2t1", "backlight_tps61043", "touch_ft6x36_t2t1"]
+model_t2b1 = ["sec/model_t2b1"]
+model_t3b1 = ["sec/model_t3b1"]
+model_t3t1 = ["sec/model_t3t1", "backlight_tps61043", "touch_ft6x36_t3t1"]
+model_t3w1 = ["sec/model_t3w1", "backlight_tps61062", "touch_ft3168"]
+
+
+# --------------------------------------------------------------------------
+# MCU features
+# --------------------------------------------------------------------------
+
+mcu_stm32f427 = ["sec/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["sec/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32u58 = ["sec/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["sec/mcu_stm32u5g", "mcu_stm32u5"]
+
+# --------------------------------------------------------------------------
+# Privilege mode features
+# --------------------------------------------------------------------------
+
+kernel_mode = ["sec/kernel_mode"]
+secure_mode = ["sec/secure_mode"]
+
+# --------------------------------------------------------------------------
+# Selectable components
+# --------------------------------------------------------------------------
+
+app_loading = ["sys/app_loading"]
+backlight = []
+ble = ["nrf"]
+button = []
+display = []
+dma2d = []
+emulator = ["sec/emulator"]
+fancy_fatal_error = []
+haptic = ["sys/i2c_bus"]
+ipc = ["sys/ipc"]
+nfc = []
+nrf = []
+nrf_auth = ["sec/nrf_auth"]
+hw_jpeg_decoder = []
+lockable_bootloader = ["sec/lockable_bootloader"]
+pmic = ["sys/i2c_bus"]
+power_manager = ["pmic", "sys/i2c_bus"]
+production = ["sec/production"]
+raspi_emulator = []
+rgb_led = []
+sbu = []
+sd_card = []
+smp = []
+suspend = ["sec/suspend"]
+touch = ["sys/i2c_bus"]
+touch_wakeup = []
+usb_iface_debug = ["usb"]
+usb_iface_vcp = ["usb"]
+usb_iface_webauthn = ["usb"]
+usb_iface_wire = ["usb"]
+
+test = [
+ "mcu_stm32u5g",
+ "model_t3w1",
+ "emulator",
+ "kernel_mode",
+ "secure_mode",
+ "sec/secret",
+]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+mcu_stm32u5 = ["mcu_stm32"]
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32 = []
+usb = []
+
+# Features for selecting driver implementations
+
+backlight_tps61043 = []
+backlight_tps61062 = []
+backlight_pin = []
+
+touch_ft6x36_t2t1 = []
+touch_ft6x36_t3t1 = []
+touch_ft3168 = []
+touch_stmpe811 = []
+touch_sitronix = []
+
+
+
+
diff --git a/core/embed/io/app_loader/build.rs b/core/embed/io/app_loader/build.rs
new file mode 100644
index 00000000..df59e728
--- /dev/null
+++ b/core/embed/io/app_loader/build.rs
@@ -0,0 +1,27 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("app_loader/inc");
+
+ // USE_APP_LOADING is defined in sys layer
+
+ if cfg!(not(feature = "emulator")) {
+ lib.add_define("THREAD_LOCAL", Some("__attribute__((section(\".tls\")))"));
+ }
+
+ lib.add_sources([
+ "app_loader/app_arena.c",
+ "app_loader/app_task.c",
+ "app_loader/app_cache.c",
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("app_loader/unix/elf_loader.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("app_loader/stm32/app_loader.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/backlight/build.rs b/core/embed/io/backlight/build.rs
new file mode 100644
index 00000000..ee43a85d
--- /dev/null
+++ b/core/embed/io/backlight/build.rs
@@ -0,0 +1,33 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("backlight/inc");
+
+ lib.add_define("USE_BACKLIGHT", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "backlight_tps61043") {
+ if cfg!(feature = "mcu_stm32") {
+ lib.add_source("backlight/stm32/tps61043.c");
+ } else {
+ bail_unsupported!();
+ }
+ } else if cfg!(feature = "backlight_tps61062") {
+ if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("backlight/stm32u5/tps61062.c");
+ } else {
+ bail_unsupported!();
+ }
+ } else if cfg!(feature = "backlight_pin") {
+ if cfg!(feature = "mcu_stm32") {
+ lib.add_source("backlight/stm32/backlight_pin.c");
+ } else {
+ bail_unsupported!();
+ }
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/ble/build.rs b/core/embed/io/ble/build.rs
new file mode 100644
index 00000000..17c90a70
--- /dev/null
+++ b/core/embed/io/ble/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("ble/inc");
+
+ lib.add_define("USE_BLE", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources(["ble/unix/ble.c"]);
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources(["ble/stm32/ble.c"]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/build.rs b/core/embed/io/build.rs
new file mode 100644
index 00000000..c41d119e
--- /dev/null
+++ b/core/embed/io/build.rs
@@ -0,0 +1,84 @@
+use xbuild::{Result, build_mods};
+
+#[path = "app_loader/build.rs"]
+mod app_loader;
+#[path = "backlight/build.rs"]
+mod backlight;
+#[path = "ble/build.rs"]
+mod ble;
+#[path = "button/build.rs"]
+mod button;
+#[path = "display/build.rs"]
+mod display;
+#[path = "gfx/build.rs"]
+mod gfx;
+#[path = "haptic/build.rs"]
+mod haptic;
+#[path = "nfc/build.rs"]
+mod nfc;
+#[path = "notify/build.rs"]
+mod notify;
+#[path = "nrf/build.rs"]
+mod nrf;
+#[path = "power_manager/build.rs"]
+mod power_manager;
+#[path = "rgb_led/build.rs"]
+mod rgb_led;
+#[path = "sbu/build.rs"]
+mod sbu;
+#[path = "sdcard/build.rs"]
+mod sdcard;
+#[path = "suspend/build.rs"]
+mod suspend;
+#[path = "touch/build.rs"]
+mod touch;
+#[path = "translations/build.rs"]
+mod translations;
+#[path = "tsqueue/build.rs"]
+mod tsqueue;
+#[path = "usb/build.rs"]
+mod usb;
+
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ lib.import_lib("sec")?;
+
+ build_mods!(
+ lib,
+ [
+ app_loader if cfg!(feature = "app_loading"),
+ backlight if cfg!(feature = "backlight"),
+ ble if cfg!(feature = "ble"),
+ button if cfg!(feature = "button"),
+ display,
+ gfx,
+ haptic if cfg!(feature = "haptic"),
+ notify,
+ nfc if cfg!(feature = "nfc"),
+ nrf if cfg!(feature = "nrf"),
+ power_manager if cfg!(any(feature = "power_manager", feature = "pmic")),
+ rgb_led if cfg!(feature = "rgb_led"),
+ sbu if cfg!(feature = "sbu"),
+ sdcard if cfg!(feature = "sd_card"),
+ suspend if cfg!(feature = "suspend"),
+ touch if cfg!(feature = "touch"),
+ translations,
+ tsqueue,
+ usb if cfg!(feature = "usb"),
+ ]
+ );
+
+ if cfg!(not(feature = "emulator")) && cfg!(not(feature = "kernel_mode")) {
+ // Add syscall stubs when linking in in unprivileged mode
+ lib.add_source("../sys/syscall/stm32/syscall_stubs.c");
+ }
+
+ if cfg!(feature = "test") {
+ // Add syscall stubs when linking in the emulator, which doesn't have a
+ // real kernel to link against.
+ lib.add_source("src/test_setup.c");
+ }
+
+ Ok(())
+ })
+}
diff --git a/core/embed/io/button/build.rs b/core/embed/io/button/build.rs
new file mode 100644
index 00000000..d59cdf35
--- /dev/null
+++ b/core/embed/io/button/build.rs
@@ -0,0 +1,23 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("button/inc");
+
+ lib.add_define("USE_BUTTON", Some("1"));
+
+ lib.add_source("button/button_poll.c");
+
+ if cfg!(feature = "usb_iface_debug") {
+ lib.add_source("button/button_debug.c");
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("button/unix/button.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("button/stm32/button.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/coreapp/build.rs b/core/embed/io/coreapp/build.rs
new file mode 100644
index 00000000..118eb70c
--- /dev/null
+++ b/core/embed/io/coreapp/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("coreapp/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources([
+ "task/unix/coreapp.c",
+ ]);
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_sources([
+ "task/stm32/coreapp.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/display/build.rs b/core/embed/io/display/build.rs
new file mode 100644
index 00000000..2f58a786
--- /dev/null
+++ b/core/embed/io/display/build.rs
@@ -0,0 +1,181 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("display/inc");
+
+ lib.add_define("USE_DISPLAY", Some("1"));
+
+ if cfg!(feature = "emulator") && cfg!(feature = "raspi_emulator") {
+ lib.add_define("TREZOR_EMULATOR_RASPI", Some("1"));
+ }
+
+ lib.add_source("display/display_utils.c");
+
+ if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("display/stm32f4/compatibility.c");
+ }
+
+ if cfg!(feature = "model_t3w1") {
+ define_display_t3w1(lib)?;
+ } else if cfg!(feature = "model_t3t1") {
+ define_display_t3t1(lib)?;
+ } else if cfg!(feature = "model_t2t1") {
+ define_display_t2t1(lib)?;
+ } else if cfg!(feature = "model_t2b1") || cfg!(feature = "model_t3b1") {
+ define_display_t2b1_t3b1(lib)?;
+ } else if cfg!(feature = "model_d001") {
+ define_display_d001(lib)?;
+ } else if cfg!(feature = "model_d002") {
+ define_display_d002(lib)?;
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
+
+fn define_display_t3w1(lib: &mut CLibrary) -> Result<()> {
+ lib.add_defines([
+ ("UI_COLOR_32BIT", Some("1")),
+ ("FRAMEBUFFER", Some("1")),
+ ("USE_RGB_COLORS", Some("1")),
+ ("DISPLAY_RESX", Some("380")),
+ ("DISPLAY_RESY", Some("520")),
+ ("TERMINAL_FONT_SCALE", Some("2")),
+ ("TERMINAL_X_PADDING", Some("4")),
+ ("TERMINAL_Y_PADDING", Some("12")),
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("display/unix/display_driver.c");
+ } else if cfg!(feature = "mcu_stm32u5g") {
+ lib.add_sources([
+ "display/ltdc_dsi/display_driver.c",
+ "display/ltdc_dsi/panels/lx250a2401a/lx250a2401a.c",
+ "display/ltdc_dsi/display_fb.c",
+ "display/ltdc_dsi/display_fb_rgb888.c",
+ "display/ltdc_dsi/display_gfxmmu.c",
+ "display/fb_queue/fb_queue.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+ Ok(())
+}
+
+fn define_display_t3t1(lib: &mut CLibrary) -> Result<()> {
+ lib.add_defines([
+ ("FRAMEBUFFER", Some("1")),
+ ("USE_RGB_COLORS", Some("1")),
+ ("DISPLAY_RESX", Some("240")),
+ ("DISPLAY_RESY", Some("240")),
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("display/unix/display_driver.c");
+ } else if cfg!(feature = "mcu_stm32u58") {
+ lib.add_sources([
+ "display/bg_copy/stm32u5/bg_copy.c",
+ "display/fb_queue/fb_queue.c",
+ "display/st-7789/display_driver.c",
+ "display/st-7789/display_fb.c",
+ "display/st-7789/display_io.c",
+ "display/st-7789/display_panel.c",
+ "display/st-7789/panels/lx154a2482.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+ Ok(())
+}
+
+fn define_display_t2t1(lib: &mut CLibrary) -> Result<()> {
+ lib.add_defines([
+ ("USE_RGB_COLORS", Some("1")),
+ ("DISPLAY_RESX", Some("240")),
+ ("DISPLAY_RESY", Some("240")),
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("display/unix/display_driver.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_sources([
+ "display/st-7789/display_nofb.c",
+ "display/st-7789/display_driver.c",
+ "display/st-7789/display_io.c",
+ "display/st-7789/display_panel.c",
+ "display/st-7789/panels/tf15411a.c",
+ "display/st-7789/panels/154a.c",
+ "display/st-7789/panels/lx154a2411.c",
+ "display/st-7789/panels/lx154a2422.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+ Ok(())
+}
+
+fn define_display_t2b1_t3b1(lib: &mut CLibrary) -> Result<()> {
+ lib.add_defines([
+ ("FRAMEBUFFER", Some("1")),
+ ("DISPLAY_RESX", Some("128")),
+ ("DISPLAY_RESY", Some("64")),
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_private_define("DISPLAY_MONO", Some("1"));
+ lib.add_source("display/unix/display_driver.c");
+ } else if cfg!(feature = "mcu_stm32u58") || cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("display/vg-2864/display_driver.c");
+ } else {
+ bail_unsupported!();
+ }
+ Ok(())
+}
+
+fn define_display_d001(lib: &mut CLibrary) -> Result<()> {
+ lib.add_defines([
+ ("FRAMEBUFFER", Some("1")),
+ ("USE_RGB_COLORS", Some("1")),
+ ("DISPLAY_RESX", Some("240")),
+ ("DISPLAY_RESY", Some("320")),
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("display/unix/display_driver.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_sources([
+ "display/stm32f429i-disc1/display_driver.c",
+ "display/stm32f429i-disc1/display_ltdc.c",
+ "display/stm32f429i-disc1/ili9341_spi.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+ Ok(())
+}
+
+fn define_display_d002(lib: &mut CLibrary) -> Result<()> {
+ lib.add_defines([
+ ("FRAMEBUFFER", Some("1")),
+ ("UI_COLOR_32BIT", Some("1")),
+ ("USE_RGB_COLORS", Some("1")),
+ ("DISPLAY_RESX", Some("240")),
+ ("DISPLAY_RESY", Some("240")),
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("display/unix/display_driver.c");
+ } else if cfg!(feature = "mcu_stm32u5g") {
+ lib.add_sources([
+ "display/ltdc_dsi/display_driver.c",
+ "display/ltdc_dsi/panels/stm32u5a9j-dk/stm32u5a9j-dk.c",
+ "display/ltdc_dsi/display_fb.c",
+ "display/ltdc_dsi/display_fb_rgb888.c",
+ "display/fb_queue/fb_queue.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+ Ok(())
+}
diff --git a/core/embed/io/gfx/build.rs b/core/embed/io/gfx/build.rs
new file mode 100644
index 00000000..b9420739
--- /dev/null
+++ b/core/embed/io/gfx/build.rs
@@ -0,0 +1,48 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("gfx/inc");
+
+ if cfg!(feature = "fancy_fatal_error") {
+ lib.add_define("FANCY_FATAL_ERROR", Some("1"));
+ }
+
+ lib.add_source("gfx/bitblt/gfx_bitblt_mono8.c");
+ lib.add_source("gfx/bitblt/gfx_bitblt_rgb565.c");
+ lib.add_source("gfx/bitblt/gfx_bitblt_rgba8888.c");
+ lib.add_source("gfx/bitblt/gfx_bitblt.c");
+
+ lib.add_source("gfx/terminal/terminal.c");
+ lib.add_source("gfx/terminal/font_bitmap.c");
+
+ lib.add_source("gfx/gfx_draw.c");
+ lib.add_source("gfx/gfx_color.c");
+ lib.add_source("gfx/rsod.c");
+
+ if cfg!(feature = "emulator") {
+ // No DMA2D implementation
+ } else if cfg!(feature = "mcu_stm32") {
+ if cfg!(feature = "dma2d") {
+ lib.add_define("USE_DMA2D", Some("1"));
+ lib.add_source("gfx/bitblt/stm32/dma2d_bitblt.c");
+ }
+ } else {
+ bail_unsupported!();
+ }
+
+ if cfg!(feature = "hw_jpeg_decoder") {
+ lib.add_define("USE_HW_JPEG_DECODER", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("gfx/jpegdec/unix/jpegdec.c");
+
+ lib.import_external_lib("libjpeg", false)?;
+ } else if cfg!(feature = "mcu_stm32u5g") {
+ lib.add_source("gfx/jpegdec/stm32u5/jpegdec.c");
+ } else {
+ bail_unsupported!();
+ }
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/haptic/build.rs b/core/embed/io/haptic/build.rs
new file mode 100644
index 00000000..d784f4d8
--- /dev/null
+++ b/core/embed/io/haptic/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("haptic/inc");
+
+ lib.add_define("USE_HAPTIC", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("haptic/unix/haptic.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("haptic/drv262x/drv262x.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/nfc/build.rs b/core/embed/io/nfc/build.rs
new file mode 100644
index 00000000..0941758f
--- /dev/null
+++ b/core/embed/io/nfc/build.rs
@@ -0,0 +1,48 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("nfc/inc");
+
+ lib.add_define("USE_NFC", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ // No sources for the emulator
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources_with_attrs(
+ [
+ "nfc/st25/nfc.c",
+ "nfc/st25/ndef.c",
+ "nfc/st25/card_emulation.c",
+ "nfc/st25/rfal002/source/st25r3916/rfal_rfst25r3916.c",
+ "nfc/st25/rfal002/source/rfal_analogConfig.c",
+ "nfc/st25/rfal002/source/rfal_nfc.c",
+ "nfc/st25/rfal002/source/rfal_nfca.c",
+ "nfc/st25/rfal002/source/rfal_nfcb.c",
+ "nfc/st25/rfal002/source/rfal_nfcf.c",
+ "nfc/st25/rfal002/source/rfal_nfcv.c",
+ "nfc/st25/rfal002/source/rfal_isoDep.c",
+ "nfc/st25/rfal002/source/rfal_nfcDep.c",
+ "nfc/st25/rfal002/source/rfal_st25tb.c",
+ "nfc/st25/rfal002/source/rfal_t1t.c",
+ "nfc/st25/rfal002/source/rfal_t2t.c",
+ "nfc/st25/rfal002/source/rfal_iso15693_2.c",
+ "nfc/st25/rfal002/source/rfal_crc.c",
+ "nfc/st25/rfal002/source/st25r3916/st25r3916.c",
+ "nfc/st25/rfal002/source/st25r3916/st25r3916_com.c",
+ "nfc/st25/rfal002/source/st25r3916/st25r3916_led.c",
+ "nfc/st25/rfal002/source/st25r3916/st25r3916_irq.c",
+ ],
+ Some(
+ xbuild::CompileAttrs::new()
+ .with_include("nfc/st25/")
+ .with_include("nfc/st25/rfal002/source")
+ .with_include("nfc/st25/rfal002/source/st25r3916")
+ .with_include("nfc/st25/rfal002/include/"),
+ ),
+ );
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/notify/build.rs b/core/embed/io/notify/build.rs
new file mode 100644
index 00000000..21c03b4f
--- /dev/null
+++ b/core/embed/io/notify/build.rs
@@ -0,0 +1,8 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("notify/inc");
+ lib.add_source("notify/notify.c");
+
+ Ok(())
+}
diff --git a/core/embed/io/nrf/build.rs b/core/embed/io/nrf/build.rs
new file mode 100644
index 00000000..33f8a689
--- /dev/null
+++ b/core/embed/io/nrf/build.rs
@@ -0,0 +1,36 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("nrf/inc");
+
+ lib.add_define("USE_NRF", Some("1"));
+
+ // TODO: remove this hack when nrf related code in trezor_lib is
+ // moved to this crate
+ lib.add_private_include("../rust");
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources(["nrf/unix/nrf.c"]);
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources([
+ "nrf/stm32u5/nrf.c",
+ "nrf/stm32u5/nrf_spi.c",
+ "nrf/stm32u5/nrf_update.c",
+ "nrf/crc8.c",
+ ]);
+
+ if cfg!(feature = "smp") {
+ lib.add_define("USE_SMP", Some("1"));
+
+ lib.add_sources(["nrf/stm32u5/nrf_uart.c", "nrf/stm32u5/nrf_test.c"]);
+ }
+
+ if cfg!(feature = "nrf_auth") {
+ lib.add_define("USE_NRF_AUTH", Some("1"));
+ }
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/power_manager/build.rs b/core/embed/io/power_manager/build.rs
new file mode 100644
index 00000000..174bf7b0
--- /dev/null
+++ b/core/embed/io/power_manager/build.rs
@@ -0,0 +1,44 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("power_manager/inc");
+
+ lib.add_define("USE_PMIC", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("power_manager/npm1300/npm1300.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ if cfg!(not(feature = "power_manager")) {
+ // if only PMIC is needed, we don't need the rest of
+ //the power manager sources
+ return Ok(());
+ }
+
+ lib.add_define("USE_POWER_MANAGER", Some("1"));
+
+ lib.add_source("power_manager/power_manager_poll.c");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("power_manager/unix/power_manager.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources([
+ "power_manager/stm32u5/power_manager.c",
+ "power_manager/stm32u5/power_monitoring.c",
+ "power_manager/stm32u5/power_states.c",
+ "power_manager/battery/battery.c",
+ "power_manager/battery/fuel_gauge.c",
+ "power_manager/battery/battery_model.c",
+ "power_manager/stwlc38/stwlc38.c",
+ "power_manager/stwlc38/stwlc38_patching.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/rgb_led/build.rs b/core/embed/io/rgb_led/build.rs
new file mode 100644
index 00000000..c6a31fb3
--- /dev/null
+++ b/core/embed/io/rgb_led/build.rs
@@ -0,0 +1,21 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("rgb_led/inc");
+
+ lib.add_define("USE_RGB_LED", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("rgb_led/unix/rgb_led.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ // TODO: do we really need this??
+ lib.add_source("rgb_led/stm32/rgb_led.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("rgb_led/stm32u5/rgb_led_lp.c");
+ lib.add_source("rgb_led/stm32u5/rgb_led_effects.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/sbu/build.rs b/core/embed/io/sbu/build.rs
new file mode 100644
index 00000000..97cba609
--- /dev/null
+++ b/core/embed/io/sbu/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("sbu/inc");
+
+ lib.add_define("USE_SBU", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("sbu/unix/sbu.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("sbu/stm32/sbu.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/sdcard/build.rs b/core/embed/io/sdcard/build.rs
new file mode 100644
index 00000000..5214eb26
--- /dev/null
+++ b/core/embed/io/sdcard/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("sdcard/inc");
+
+ lib.add_define("USE_SD_CARD", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("sdcard/unix/sdcard.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("sdcard/stm32f4/sdcard.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("sdcard/stm32u5/sdcard.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/src/lib.rs b/core/embed/io/src/lib.rs
new file mode 100644
index 00000000..98bc18a2
--- /dev/null
+++ b/core/embed/io/src/lib.rs
@@ -0,0 +1,24 @@
+#![cfg_attr(not(test), no_std)]
+#![no_main]
+#![feature(custom_test_frameworks)]
+#![reexport_test_harness_main = "test_main"]
+
+#[cfg(test)]
+#[unsafe(no_mangle)]
+pub fn main() -> i32 {
+ unsafe extern "C" {
+ safe fn rust_tests_c_setup();
+ }
+
+ // Initialize the C part of the library before running any tests
+ rust_tests_c_setup();
+
+ // Call the Rust test harness main function
+ // The function panics if any test fails.
+ // Asserting that it returns () to ensure that if a future Rust version
+ // changes the signature and behavior, we'll be notified.
+ assert_eq!(test_main(), ());
+
+ // Return 0 to indicate success
+ 0
+}
diff --git a/core/embed/io/src/test_setup.c b/core/embed/io/src/test_setup.c
new file mode 100644
index 00000000..708908ec
--- /dev/null
+++ b/core/embed/io/src/test_setup.c
@@ -0,0 +1,26 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+// Provide definitions of the system exit functions so that they can be
+// called without linking the sys crate. This is needed when compiling the
+// tests for the crates that don't depend on sys, such as the crypto crate.
+
+#include <sys/system.h>
+
+void rust_tests_c_setup(void) { system_init(NULL); }
diff --git a/core/embed/io/suspend/build.rs b/core/embed/io/suspend/build.rs
new file mode 100644
index 00000000..7ab1c624
--- /dev/null
+++ b/core/embed/io/suspend/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("suspend/inc");
+
+ // `USE_SUSPEND` is defined in sec layer
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources(["suspend/stm32u5/suspend_io.c", "suspend/stm32u5/suspend.c"]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/touch/build.rs b/core/embed/io/touch/build.rs
new file mode 100644
index 00000000..5415730b
--- /dev/null
+++ b/core/embed/io/touch/build.rs
@@ -0,0 +1,42 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("touch/inc");
+
+ lib.add_define("USE_TOUCH", Some("1"));
+
+ lib.add_source("touch/touch_poll.c");
+
+ if cfg!(feature = "usb_iface_debug") {
+ lib.add_source("touch/touch_debug.c");
+ }
+
+ if cfg!(feature = "touch_wakeup") {
+ if cfg!(not(feature = "suspend")) {
+ bail_unsupported!();
+ }
+ lib.add_define("USE_TOUCH_WAKEUP", Some("1"));
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("touch/unix/touch.c");
+ } else if cfg!(feature = "touch_ft3168") {
+ lib.add_define("TOUCH_WAKEUP_ENABLED", Some("0"));
+ lib.add_sources(["touch/ft3168/ft3168.c", "touch/ft3168/panels/lx250a2410a.c"]);
+ } else if cfg!(feature = "touch_ft6x36_t3t1") {
+ lib.add_sources([
+ "touch/ft6x36/ft6x36.c",
+ "touch/ft6x36/panels/lx154a2422cpt23.c",
+ ]);
+ } else if cfg!(feature = "touch_ft6x36_t2t1") {
+ lib.add_source("touch/ft6x36/ft6x36.c");
+ } else if cfg!(feature = "touch_stmpe811") {
+ lib.add_sources(["touch/stmpe811/stmpe811.c", "touch/stmpe811/touch.c"]);
+ } else if cfg!(feature = "touch_sitronix") {
+ lib.add_sources(["touch/sitronix/touch.c", "touch/sitronix/sitronix.c"]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/io/translations/build.rs b/core/embed/io/translations/build.rs
new file mode 100644
index 00000000..b3550593
--- /dev/null
+++ b/core/embed/io/translations/build.rs
@@ -0,0 +1,8 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("translations/inc");
+ lib.add_source("translations/translations.c");
+
+ Ok(())
+}
diff --git a/core/embed/io/tsqueue/build.rs b/core/embed/io/tsqueue/build.rs
new file mode 100644
index 00000000..df03e923
--- /dev/null
+++ b/core/embed/io/tsqueue/build.rs
@@ -0,0 +1,8 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("tsqueue/inc");
+ lib.add_source("tsqueue/tsqueue.c");
+
+ Ok(())
+}
diff --git a/core/embed/io/usb/build.rs b/core/embed/io/usb/build.rs
new file mode 100644
index 00000000..ee83f884
--- /dev/null
+++ b/core/embed/io/usb/build.rs
@@ -0,0 +1,45 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("usb/inc");
+
+ lib.add_define("USE_USB", Some("1"));
+
+ if cfg!(feature = "usb_iface_wire") {
+ lib.add_define("USE_USB_IFACE_WIRE", Some("1"));
+ }
+
+ if cfg!(feature = "usb_iface_debug") {
+ lib.add_define("USE_USB_IFACE_DEBUG", Some("1"));
+ lib.add_define("DEBUGLINK", Some("1"));
+ }
+
+ if cfg!(feature = "usb_iface_webauthn") {
+ lib.add_define("USE_USB_IFACE_WEBAUTHN", Some("1"));
+ }
+
+ if cfg!(feature = "usb_iface_vcp") {
+ lib.add_define("USE_USB_IFACE_VCP", Some("1"));
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources(["usb/unix/sock.c", "usb/unix/usb.c", "usb/usb_config.c"]);
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_sources([
+ "usb/stm32/usb_class_hid.c",
+ "usb/stm32/usb_class_vcp.c",
+ "usb/stm32/usb_class_webusb.c",
+ "usb/stm32/usb.c",
+ "usb/stm32/usb_rbuf.c",
+ "usb/stm32/usbd_conf.c",
+ "usb/stm32/usbd_core.c",
+ "usb/stm32/usbd_ctlreq.c",
+ "usb/stm32/usbd_ioreq.c",
+ "usb/usb_config.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/models/Cargo.toml b/core/embed/models/Cargo.toml
new file mode 100644
index 00000000..d132e0d1
--- /dev/null
+++ b/core/embed/models/Cargo.toml
@@ -0,0 +1,77 @@
+[package]
+name = "models"
+version = "0.0.0"
+edition = "2024"
+links = "models"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = []
+model_d002 = []
+model_t2t1 = []
+model_t2b1 = []
+model_t3b1 = []
+model_t3t1 = []
+model_t3w1 = []
+
+# --------------------------------------------------------------------------
+# MCU features
+# --------------------------------------------------------------------------
+
+mcu_stm32f427 = ["mcu_stm32f4"]
+mcu_stm32f429 = ["mcu_stm32f4"]
+mcu_stm32u58 = ["mcu_stm32u5"]
+mcu_stm32u5g = ["mcu_stm32u5"]
+
+# --------------------------------------------------------------------------
+# Privilege mode features
+# --------------------------------------------------------------------------
+
+kernel_mode = []
+secure_mode = []
+secmon_layout = []
+
+# --------------------------------------------------------------------------
+# Executable type featurs (for legacy C definitions)
+# --------------------------------------------------------------------------
+
+boardloader = []
+bootloader = []
+secmon = []
+kernel = []
+prodtest = []
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+asan = []
+emulator = []
+production = []
+
+test = [
+ "emulator",
+ "mcu_stm32u5g",
+ "model_t3w1",
+]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32u5 = ["mcu_stm32"]
+mcu_stm32 = []
+
+
+
diff --git a/core/embed/models/_dummy.c b/core/embed/models/_dummy.c
new file mode 100644
index 00000000..077ed559
--- /dev/null
+++ b/core/embed/models/_dummy.c
@@ -0,0 +1 @@
+void models_dummy_(void) {}
diff --git a/core/embed/models/build.rs b/core/embed/models/build.rs
new file mode 100644
index 00000000..6ea0ed0c
--- /dev/null
+++ b/core/embed/models/build.rs
@@ -0,0 +1,346 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ lib.add_include(".");
+
+ lib.add_flags([
+ "-std=gnu11",
+ "-Wall",
+ "-Werror",
+ "-Wdouble-promotion",
+ "-Wuninitialized",
+ "-Wpointer-arith",
+ "-Wno-unused-parameter",
+ "-Wno-sign-compare",
+ "-Wno-implicit-fallthrough",
+ "-Wno-enum-conversion",
+ "-Wno-type-limits",
+ "-Wno-shift-negative-value",
+ "-fno-common",
+ "-fsingle-precision-constant",
+ "-fdata-sections",
+ "-ffunction-sections",
+ "-g3",
+ "-ggdb",
+ ]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_flags(["-fstack-protector-all", "-fno-omit-frame-pointer", "-O1"]);
+
+ if cfg!(feature = "asan") {
+ lib.add_flags([
+ "-fsanitize=address,undefined",
+ "-fno-optimize-sibling-calls",
+ ]);
+ }
+ } else if cfg!(feature = "mcu_stm32") {
+ // arm-none-eabi-gcc uses short enums (-fshort-enums) by default,
+ // while clang does not, which causes bindgen to generate incorrect
+ // bindings for enums. Therefore, we need to explicitly enable short
+ // here. The options is propagated to clang when bindgen is run.
+
+ lib.add_flags(["-nostdlib", "-fshort-enums", "-Os"]);
+
+ if cfg!(feature = "bootloader")
+ || cfg!(feature = "boardloader")
+ || cfg!(feature = "kernel")
+ || cfg!(feature = "secmon")
+ || cfg!(feature = "prodtest")
+ {
+ lib.add_flags(["-ffreestanding"]);
+ }
+
+ if cfg!(feature = "bootloader") || cfg!(feature = "boardloader") {
+ lib.add_flag("-fstack-protector-strong");
+ } else {
+ lib.add_flag("-fstack-protector-all");
+ }
+
+ if cfg!(feature = "mcu_stm32f4") {
+ lib.add_flags([
+ "-mthumb",
+ "-mcpu=cortex-m4",
+ "-mfloat-abi=hard",
+ "-mfpu=fpv4-sp-d16",
+ "-mtune=cortex-m4",
+ ]);
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_flags([
+ "-mthumb",
+ "-mcpu=cortex-m33",
+ "-mfloat-abi=hard",
+ "-mfpu=fpv5-sp-d16",
+ "-mtune=cortex-m33",
+ ]);
+
+ if cfg!(feature = "secure_mode") {
+ lib.add_flag("-mcmse");
+ }
+ } else {
+ bail_unsupported!();
+ }
+ } else {
+ bail_unsupported!();
+ }
+
+ if cfg!(feature = "kernel_mode") {
+ lib.add_define("KERNEL_MODE", Some("1"));
+ }
+
+ if cfg!(feature = "secure_mode") {
+ lib.add_define("SECURE_MODE", Some("1"));
+ }
+
+ if cfg!(feature = "secmon_layout") {
+ lib.add_define("USE_SECMON_LAYOUT", Some("1"));
+ }
+
+ if cfg!(feature = "production") {
+ lib.add_define("PRODUCTION", None);
+ }
+
+ if cfg!(feature = "boardloader") {
+ lib.add_define("BOARDLOADER", None);
+ }
+
+ if cfg!(feature = "bootloader") {
+ lib.add_define("BOOTLOADER", None);
+ }
+
+ if cfg!(feature = "secmon") {
+ lib.add_define("SECMON", None);
+ }
+
+ if cfg!(feature = "kernel") {
+ lib.add_define("KERNEL", None);
+ }
+
+ if cfg!(feature = "prodtest") {
+ lib.add_define("TREZOR_PRODTEST", None);
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_define("TREZOR_EMULATOR", None);
+ }
+
+ if cfg!(feature = "model_t2t1") {
+ define_model_t2t1(lib)?;
+ } else if cfg!(feature = "model_t2b1") {
+ define_model_t2b1(lib)?;
+ } else if cfg!(feature = "model_t3b1") {
+ define_model_t3b1(lib)?;
+ } else if cfg!(feature = "model_t3t1") {
+ define_model_t3t1(lib)?;
+ } else if cfg!(feature = "model_t3w1") {
+ define_model_t3w1(lib)?;
+ } else if cfg!(feature = "model_d001") {
+ define_model_d001(lib)?;
+ } else if cfg!(feature = "model_d002") {
+ define_model_d002(lib)?;
+ } else {
+ bail_unsupported!();
+ }
+
+ // Compile some dummy source file to ensure the library is created
+ // (=> metadata are passed to higher-level crates)
+ lib.add_source("_dummy.c");
+
+ Ok(())
+ })
+}
+
+fn model_to_num(model: &str) -> u32 {
+ let model_bytes = model.as_bytes();
+ (model_bytes[3] as u32) << 24
+ | (model_bytes[2] as u32) << 16
+ | (model_bytes[1] as u32) << 8
+ | (model_bytes[0] as u32)
+}
+
+fn define_model_t3w1(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ "\"T3W1/boards/t3w1-unix.h\""
+ } else {
+ "\"T3W1/boards/trezor_t3w1_revC.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_T3W1", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"T3W1/model_T3W1.h\"")),
+ ("VERSIONS_HEADER", Some("\"T3W1/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"T3W1/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"T3W1/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("T3W1").to_string().as_str())),
+ ("HW_REVISION", Some("1")),
+ ("USE_BOOTARGS_RSOD", Some("1")),
+ ("HSE_VALUE", Some("32000000")),
+ ("LSI_VALUE", Some("250")),
+ ("USE_HSE", Some("1")),
+ ("USE_LSE", Some("1")),
+ ("USE_LSI", Some("1")),
+ ("USE_OEM_KEYS_CHECK", Some("1")),
+ ("FIXED_HW_DEINIT", Some("1")),
+ ]);
+
+ Ok(())
+}
+
+fn define_model_t3t1(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ "\"T3T1/boards/t3t1-unix.h\""
+ } else {
+ "\"T3T1/boards/trezor_t3t1_revE.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_T3T1", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"T3T1/model_T3T1.h\"")),
+ ("VERSIONS_HEADER", Some("\"T3T1/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"T3T1/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"T3T1/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("T3T1").to_string().as_str())),
+ ("HW_REVISION", Some("0")),
+ ("USE_OEM_KEYS_CHECK", Some("1")),
+ ]);
+
+ Ok(())
+}
+
+fn define_model_t3b1(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ "\"T3B1/boards/t3b1-unix.h\""
+ } else {
+ "\"T3B1/boards/trezor_t3b1_revB.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_T3B1", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"T3B1/model_T3B1.h\"")),
+ ("VERSIONS_HEADER", Some("\"T3B1/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"T3B1/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"T3B1/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("T3B1").to_string().as_str())),
+ ("HW_REVISION", Some("0")),
+ ("USE_OEM_KEYS_CHECK", Some("1")),
+ ]);
+
+ Ok(())
+}
+
+fn define_model_t2t1(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ "\"T2T1/boards/t2t1-unix.h\""
+ } else {
+ "\"T2T1/boards/trezor_t.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_T2T1", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"T2T1/model_T2T1.h\"")),
+ ("VERSIONS_HEADER", Some("\"T2T1/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"T2T1/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"T2T1/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("T2T1").to_string().as_str())),
+ ("HW_REVISION", Some("0")),
+ ("HSE_VALUE", Some("8000000")),
+ ("USE_HSE", Some("1")),
+ ]);
+
+ Ok(())
+}
+
+fn define_model_t2b1(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ "\"T2B1/boards/t2b1-unix.h\""
+ } else {
+ "\"T2B1/boards/trezor_r_v10.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_T2B1", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"T2B1/model_T2B1.h\"")),
+ ("VERSIONS_HEADER", Some("\"T2B1/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"T2B1/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"T2B1/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("T2B1").to_string().as_str())),
+ ("HW_REVISION", Some("10")),
+ ("HSE_VALUE", Some("8000000")),
+ ("USE_HSE", Some("1")),
+ ]);
+
+ Ok(())
+}
+
+fn define_model_d001(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ bail_unsupported!();
+ } else {
+ "\"D001/boards/stm32f429i-disc1.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_D001", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"D001/model_D001.h\"")),
+ ("VERSIONS_HEADER", Some("\"D001/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"D001/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"D001/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("D001").to_string().as_str())),
+ ("HW_REVISION", Some("0")),
+ ("HSE_VALUE", Some("8000000")),
+ ("USE_HSE", Some("1")),
+ ]);
+
+ Ok(())
+}
+
+fn define_model_d002(lib: &mut CLibrary) -> Result<()> {
+ let board_header = if cfg!(feature = "emulator") {
+ bail_unsupported!()
+ } else {
+ "\"D002/boards/stm32u5g9j-dk.h\""
+ };
+
+ lib.add_defines([
+ ("TREZOR_MODEL_D002", None),
+ ("TREZOR_BOARD", Some(board_header)),
+ ("MODEL_HEADER", Some("\"D002/model_D002.h\"")),
+ ("VERSIONS_HEADER", Some("\"D002/versions.h\"")),
+ ("OTP_LAYOUT_HEADER", Some("\"D002/otp_layout.h\"")),
+ (
+ "UNIT_PROPERTIES_CONTENT_HEADER",
+ Some("\"D002/unit_properties_content.h\""),
+ ),
+ ("HW_MODEL", Some(model_to_num("D002").to_string().as_str())),
+ ("HW_REVISION", Some("0")),
+ ("HSE_VALUE", Some("16000000")),
+ ("USE_HSE", Some("1")),
+ ("USE_BOOTARGS_RSOD", Some("1")),
+ ]);
+
+ Ok(())
+}
diff --git a/core/embed/models/src/lib.rs b/core/embed/models/src/lib.rs
new file mode 100644
index 00000000..0c9ac1ac
--- /dev/null
+++ b/core/embed/models/src/lib.rs
@@ -0,0 +1 @@
+#![no_std]
diff --git a/core/embed/projects/boardloader/Cargo.toml b/core/embed/projects/boardloader/Cargo.toml
new file mode 100644
index 00000000..931e7a18
--- /dev/null
+++ b/core/embed/projects/boardloader/Cargo.toml
@@ -0,0 +1,148 @@
+[package]
+name = "boardloader"
+version = "0.0.0"
+edition = "2024"
+links = "boardloader"
+
+[[bin]]
+name = "boardloader"
+path = "src/main.rs"
+test = false
+bench = false
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+
+[dependencies]
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = [
+ "io/model_d001",
+ "mcu_stm32f429",
+ "dma2d",
+ "pvd",
+ "sdram",
+ ]
+
+model_d002 = [
+ "io/model_d002",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "secret",
+ "secure_aes",
+ "tamper",
+ ]
+
+model_t2t1 = [
+ "io/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "pvd",
+ "sd_card_update",
+ ]
+
+model_t2b1 = [
+ "io/model_t2b1",
+ "mcu_stm32f427",
+ "pvd",
+ "secret",
+ ]
+
+model_t3b1 = [
+ "io/model_t3b1",
+ "mcu_stm32u58",
+ "hash_processor",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+ "secure_aes",
+ "tamper",
+ ]
+
+model_t3t1 = [
+ "io/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "hash_processor",
+ "lockable_bootloader",
+ "pvd",
+ "sd_card_update",
+ "secret",
+ "secure_aes",
+ "tamper",
+ ]
+
+model_t3w1 = [
+ "io/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "pmic",
+ "secret",
+ "secure_aes",
+ "tamper",
+ ]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+bootloader_devel = ["sec/bootloader_devel"]
+clippy = []
+emulator = ["io/emulator"]
+dbg_console_swo = ["dbg_console"]
+dbg_console_system_view = ["dbg_console", "sys/system_view"]
+production = ["io/production"]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "io/display",
+ "io/kernel_mode",
+ "io/secure_mode",
+ "models/boardloader",
+ "rtl/ed25519_no_precomp",
+ ]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = []
+mcu_stm32u58 = ["io/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone"]
+
+backlight = ["io/backlight"]
+boot_ucb = ["sec/boot_ucb"]
+dbg_console = ["sys/dbg_console"]
+dma2d = ["io/dma2d"]
+hash_processor = ["sec/hash_processor"]
+lockable_bootloader = ["io/lockable_bootloader"]
+pmic = ["io/pmic"]
+pvd = ["sys/pvd"]
+sd_card_update = ["io/sd_card"]
+sdram = ["sys/sdram"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+tamper = ["sec/tamper"]
+
diff --git a/core/embed/projects/boardloader/build.rs b/core/embed/projects/boardloader/build.rs
new file mode 100644
index 00000000..3e0e1d68
--- /dev/null
+++ b/core/embed/projects/boardloader/build.rs
@@ -0,0 +1,17 @@
+use xbuild::Result;
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("boardloader", |lib| {
+ lib.import_lib("io")?;
+
+ lib.add_include(".");
+
+ lib.add_sources(["main.c", "bld_version.c"]);
+
+ if cfg!(feature = "sd_card_update") {
+ lib.add_source("sd_update.c");
+ }
+
+ Ok(())
+ })
+}
diff --git a/core/embed/projects/boardloader/src/main.rs b/core/embed/projects/boardloader/src/main.rs
new file mode 100644
index 00000000..ead0a014
--- /dev/null
+++ b/core/embed/projects/boardloader/src/main.rs
@@ -0,0 +1,7 @@
+#![no_std]
+#![no_main]
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
diff --git a/core/embed/projects/bootloader/Cargo.toml b/core/embed/projects/bootloader/Cargo.toml
new file mode 100644
index 00000000..16987ee1
--- /dev/null
+++ b/core/embed/projects/bootloader/Cargo.toml
@@ -0,0 +1,246 @@
+[package]
+name = "bootloader"
+version = "0.0.0"
+edition = "2024"
+links = "bootloader"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+trezor_lib.workspace = true
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = [
+ "io/model_d001",
+ "mcu_stm32f429",
+ "dma2d",
+ "pvd",
+ "sdram",
+ "touch",
+ "layout_bolt_d001",
+ ]
+
+model_d002 = [
+ "io/model_d002",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "secmon_verification",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ "layout_bolt_d002",
+]
+
+model_t2t1 = [
+ "io/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "dma2d",
+ "pvd",
+ "touch",
+ "layout_bolt",
+]
+
+model_t2b1 = [
+ "io/model_t2b1",
+ "mcu_stm32f427",
+ "button",
+ "consumption_mask",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+ "ui_empty_lock",
+ "layout_caesar",
+]
+
+model_t3b1 = [
+ "io/model_t3b1",
+ "mcu_stm32u58",
+ "button",
+ "consumption_mask",
+ "hash_processor",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "layout_caesar",
+]
+
+model_t3t1 = [
+ "io/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ "layout_delizia",
+]
+
+model_t3w1 = [
+ "io/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "backup_ram",
+ "ble",
+ "boot_ucb",
+ "button",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "iwdg",
+ "lockable_bootloader",
+ "mcu_attestation",
+ "power_manager",
+ "rgb_led",
+ "rtc",
+ "secmon_verification",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "suspend",
+ "tamper",
+ "telemetry",
+ "touch",
+ "touch_wakeup",
+ "layout_eckhart",
+]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+bootloader_devel = ["sec/bootloader_devel"]
+emulator = ["io/emulator"]
+clippy = ["trezor_lib/clippy"]
+dbg_console_swo = ["dbg_console", "sys/dbg_console_swo"]
+dbg_console_vcp = ["dbg_console", "sys/dbg_console_vcp", "io/usb_iface_vcp"]
+dbg_console_system_view = ["dbg_console", "sys/dbg_console_system_view"]
+debug = ["trezor_lib/debug"]
+debuglink = ["trezor_lib/debuglink", "io/usb_iface_debug"]
+disable_animation = []
+production = ["io/production"]
+ui_debug = ["trezor_lib/ui_debug"]
+ui_debug_overlay = ["trezor_lib/ui_debug_overlay"]
+ui_performance_overlay = ["trezor_lib/ui_performance_overlay"]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "io/display",
+ "io/fancy_fatal_error",
+ "io/kernel_mode",
+ "io/secure_mode",
+ "io/usb_iface_wire",
+ "models/bootloader",
+ "rtl/ed25519_no_precomp",
+
+ "trezor_lib/with_new_crates", # only for transitional period
+
+ "trezor_lib/crypto",
+ "trezor_lib/ui",
+ "trezor_lib/bootloader",
+ "trezor_lib/usb",
+ ]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = []
+mcu_stm32u58 = ["io/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone"]
+
+backlight = ["io/backlight", "trezor_lib/backlight"]
+backup_ram = ["sec/backup_ram"]
+ble = ["io/ble", "trezor_lib/ble", "nrf", "nrf_auth"]
+nrf = ["io/nrf", "trezor_lib/nrf"]
+nrf_auth = ["io/nrf_auth"]
+boot_ucb = ["sec/boot_ucb", "trezor_lib/boot_ucb"]
+button = ["io/button", "trezor_lib/button"]
+consumption_mask = ["sec/consumption_mask"]
+dbg_console = ["sys/dbg_console"]
+dma2d = ["io/dma2d", "trezor_lib/dma2d"]
+haptic = ["io/haptic", "trezor_lib/haptic"]
+hash_processor = ["sec/hash_processor"]
+iwdg = ["sec/iwdg"]
+lockable_bootloader = ["io/lockable_bootloader"]
+mcu_attestation = ["sec/mcu_attestation"]
+power_manager = ["io/power_manager", "trezor_lib/power_manager", "trezor_lib/pmic"]
+pvd = ["sys/pvd"]
+rgb_led = ["io/rgb_led", "trezor_lib/rgb_led"]
+rtc = ["sys/rtc"]
+sdram = ["sys/sdram"]
+secmon_verification = ["sec/secmon_verification"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+storage_hw_key = ["sec/storage_hw_key"]
+suspend = ["io/suspend"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry", "trezor_lib/telemetry"]
+touch = ["io/touch", "trezor_lib/touch"]
+touch_wakeup = ["io/touch_wakeup", "trezor_lib/touch_wakeup"]
+ui_empty_lock = ["trezor_lib/ui_empty_lock"]
+
+layout_bolt_d001 = [
+ "trezor_lib/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+]
+
+layout_bolt_d002 = [
+ "trezor_lib/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_color_32bit",
+]
+
+layout_bolt = [
+ "trezor_lib/layout_bolt",
+ "trezor_lib/display_rgb565",
+ ]
+
+layout_caesar = [
+ "trezor_lib/layout_caesar",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_mono",
+ ]
+
+layout_delizia = [
+ "trezor_lib/layout_delizia",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+ ]
+
+layout_eckhart = [
+ "trezor_lib/layout_eckhart",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_color_32bit",
+ ]
diff --git a/core/embed/projects/bootloader/build.rs b/core/embed/projects/bootloader/build.rs
new file mode 100644
index 00000000..bf854564
--- /dev/null
+++ b/core/embed/projects/bootloader/build.rs
@@ -0,0 +1,78 @@
+use xbuild::Result;
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("bootloader", |lib| {
+ lib.import_lib("io")?;
+
+ lib.add_includes([".", "protob"]);
+
+ lib.add_include("../../rust"); // Cyclic dependency
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("emulator.c");
+ }
+
+ lib.add_defines([
+ ("PB_FIELD_16BIT", Some("1")),
+ ("PB_ENCODE_ARRAYS_UNPACKED", Some("1")),
+ ("PB_VALIDATE_UTF8", Some("1")),
+ ]);
+
+ lib.add_sources([
+ "bootui.c",
+ "fw_check.c",
+ "main.c",
+ "ui_helpers.c",
+ "version_check.c",
+ "workflow/wf_firmware_update.c",
+ "workflow/wf_wipe_device.c",
+ "workflow/wf_get_features.c",
+ "workflow/wf_initialize.c",
+ "workflow/wf_ping.c",
+ "workflow/wf_bootloader.c",
+ "workflow/wf_empty_device.c",
+ "workflow/wf_auto_update.c",
+ "workflow/wf_host_control.c",
+ "workflow/wf_ble_pairing_request.c",
+ "wire/codec_v1.c",
+ "wire/wire_iface_usb.c",
+ "wire/wire_iface_ble.c",
+ "protob/protob.c",
+ "protob/pb/messages.pb.c",
+ ]);
+
+ if cfg!(not(feature = "emulator")) {
+ if cfg!(feature = "boot_ucb") {
+ lib.add_source("header_pq.c");
+ } else {
+ lib.add_source("header.S");
+ }
+ }
+
+ if cfg!(feature = "lockable_bootloader") {
+ lib.add_source("workflow/wf_unlock_bootloader.c");
+ }
+
+ if cfg!(feature = "disable_animation") {
+ lib.add_define("DISABLE_ANIMATION", Some("1"));
+ }
+
+ if cfg!(feature = "debuglink") {
+ lib.add_sources([
+ "workflow/debuglink.c",
+ "wire/debug_iface_usb.c",
+ "protob/protob_debug.c",
+ "protob/pb/messages-debug.pb.c",
+ ]);
+ }
+
+ // nanopb library
+ lib.add_include("../../../vendor/nanopb");
+ lib.add_sources_in_dir(
+ "../../../vendor/nanopb/",
+ ["pb_common.c", "pb_decode.c", "pb_encode.c"],
+ );
+
+ Ok(())
+ })
+}
diff --git a/core/embed/projects/bootloader/src/main.rs b/core/embed/projects/bootloader/src/main.rs
new file mode 100644
index 00000000..f56c4ae3
--- /dev/null
+++ b/core/embed/projects/bootloader/src/main.rs
@@ -0,0 +1,4 @@
+#![no_std]
+#![no_main]
+
+use trezor_lib as _;
diff --git a/core/embed/projects/bootloader_ci/Cargo.toml b/core/embed/projects/bootloader_ci/Cargo.toml
new file mode 100644
index 00000000..6137ab16
--- /dev/null
+++ b/core/embed/projects/bootloader_ci/Cargo.toml
@@ -0,0 +1,171 @@
+[package]
+name = "bootloader_ci"
+version = "0.0.0"
+edition = "2024"
+links = "bootloader_ci"
+
+[[bin]]
+name = "bootloader_ci"
+path = "src/main.rs"
+test = false
+bench = false
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = [
+ "io/model_d001",
+ "mcu_stm32f429",
+ "dma2d",
+ "pvd",
+ "sdram",
+ "touch",
+]
+
+model_d002 = [
+ "io/model_d002",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "secret",
+ "secure_aes",
+ "tamper",
+ "touch",
+]
+
+model_t2t1 = [
+ "io/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "dma2d",
+ "pvd",
+ "touch",
+]
+
+model_t2b1 = [
+ "io/model_t2b1",
+ "mcu_stm32f427",
+ "button",
+ "consumption_mask",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+]
+
+model_t3b1 = [
+ "io/model_t3b1",
+ "mcu_stm32u58",
+ "button",
+ "consumption_mask",
+ "hash_processor",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+ "secure_aes",
+ "tamper",
+]
+
+model_t3t1 = [
+ "io/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "haptic",
+ "hash_processor",
+ "lockable_bootloader",
+ "pvd",
+ "secret",
+ "secure_aes",
+ "tamper",
+ "touch",
+]
+
+model_t3w1 = [
+ "io/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "backup_ram",
+ "boot_ucb",
+ "button",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "iwdg",
+ "lockable_bootloader",
+ "rgb_led",
+ "secret",
+ "secure_aes",
+ "tamper",
+ "telemetry",
+ "touch",
+]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+bootloader_devel = ["sec/bootloader_devel"]
+clippy = []
+emulator = ["io/emulator"]
+dbg_console_swo = ["dbg_console"]
+dbg_console_vcp = ["dbg_console", "io/usb_iface_vcp"]
+dbg_console_system_view = ["dbg_console", "sys/system_view"]
+production = ["io/production"]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "io/display",
+ "io/kernel_mode",
+ "io/secure_mode",
+ "io/usb_iface_wire",
+ "models/bootloader",
+ "rtl/ed25519_no_precomp",
+]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = ["io/mcu_stm32f4"]
+mcu_stm32u58 = ["io/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone"]
+
+backlight = ["io/backlight"]
+backup_ram = ["sec/backup_ram"]
+boot_ucb = ["sec/boot_ucb"]
+button = ["io/button"]
+consumption_mask = ["sec/consumption_mask"]
+dbg_console = ["sys/dbg_console"]
+dma2d = ["io/dma2d"]
+haptic = ["io/haptic"]
+hash_processor = ["sec/hash_processor"]
+iwdg = ["sec/iwdg"]
+lockable_bootloader = ["io/lockable_bootloader"]
+power_manager = ["io/power_manager"]
+pvd = ["sys/pvd"]
+rgb_led = ["io/rgb_led"]
+sdram = ["sys/sdram"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+suspend = ["io/suspend"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry"]
+touch = ["io/touch"]
diff --git a/core/embed/projects/bootloader_ci/build.rs b/core/embed/projects/bootloader_ci/build.rs
new file mode 100644
index 00000000..e1f246c0
--- /dev/null
+++ b/core/embed/projects/bootloader_ci/build.rs
@@ -0,0 +1,41 @@
+use xbuild::Result;
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("bootloader", |lib| {
+ lib.import_lib("io")?;
+
+ lib.add_includes([".", "protob"]);
+
+ lib.add_defines([
+ ("PB_FIELD_16BIT", Some("1")),
+ ("PB_ENCODE_ARRAYS_UNPACKED", Some("1")),
+ ("PB_VALIDATE_UTF8", Some("1")),
+ ]);
+
+ lib.add_sources([
+ "bootui.c",
+ "main.c",
+ "messages.c",
+ "version_check.c",
+ "protob/pb/messages.pb.c",
+ ]);
+
+ if cfg!(not(feature = "emulator")) {
+ if cfg!(feature = "boot_ucb") {
+ lib.add_source("../bootloader/header_pq.c");
+ } else {
+ lib.add_source("../bootloader/header.S");
+ }
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("emulator.c");
+ }
+
+ let nanopb_dir = "../../../vendor/nanopb";
+ lib.add_include(nanopb_dir);
+ lib.add_sources_in_dir(nanopb_dir, ["pb_common.c", "pb_decode.c", "pb_encode.c"]);
+
+ Ok(())
+ })
+}
diff --git a/core/embed/projects/bootloader_ci/fw_check.h b/core/embed/projects/bootloader_ci/fw_check.h
new file mode 120000
index 00000000..70d8abab
--- /dev/null
+++ b/core/embed/projects/bootloader_ci/fw_check.h
@@ -0,0 +1 @@
+../bootloader/fw_check.h
\ No newline at end of file
diff --git a/core/embed/projects/bootloader_ci/src/main.rs b/core/embed/projects/bootloader_ci/src/main.rs
new file mode 100644
index 00000000..ead0a014
--- /dev/null
+++ b/core/embed/projects/bootloader_ci/src/main.rs
@@ -0,0 +1,7 @@
+#![no_std]
+#![no_main]
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
diff --git a/core/embed/projects/bootloader_ci/wire b/core/embed/projects/bootloader_ci/wire
new file mode 120000
index 00000000..7ff692be
--- /dev/null
+++ b/core/embed/projects/bootloader_ci/wire
@@ -0,0 +1 @@
+../bootloader/wire
\ No newline at end of file
diff --git a/core/embed/projects/firmware/Cargo.toml b/core/embed/projects/firmware/Cargo.toml
new file mode 100644
index 00000000..40384af2
--- /dev/null
+++ b/core/embed/projects/firmware/Cargo.toml
@@ -0,0 +1,292 @@
+[package]
+name = "firmware"
+version = "0.0.0"
+edition = "2024"
+links = "firmware"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+trezor_lib.workspace = true
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+upymod.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = [
+ "upymod/model_d001",
+ "mcu_stm32f429",
+ "dma2d",
+ "touch",
+ "layout_bolt_d001",
+]
+
+model_d002 = [
+ "upymod/model_d002",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "secmon_layout",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ "layout_bolt_d002",
+]
+
+model_t2t1 = [
+ "upymod/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "dma2d",
+ "touch",
+ "layout_bolt",
+ "sd_card",
+]
+
+model_t2b1 = [
+ "upymod/model_t2b1",
+ "mcu_stm32f427",
+ "button",
+ "consumption_mask",
+ "lockable_bootloader",
+ #"optiga", # selected from xtask
+ "secret",
+ "layout_caesar",
+]
+
+model_t3b1 = [
+ "upymod/model_t3b1",
+ "mcu_stm32u58",
+ "button",
+ "consumption_mask",
+ "hash_processor",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "layout_caesar",
+]
+
+model_t3t1 = [
+ "upymod/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "lockable_bootloader",
+ "sd_card",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ "layout_delizia",
+]
+
+model_t3w1 = [
+ "upymod/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "ble",
+ "backup_ram",
+ "boot_ucb",
+ "button",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "iwdg",
+ "lockable_bootloader",
+ "mcu_attestation",
+ # "optiga", # selected from xtask
+ "power_manager",
+ "secmon_layout",
+ "secret",
+ "secure_aes",
+ "serial_number",
+ "storage_hw_key",
+ "suspend",
+ "tamper",
+ "telemetry",
+ "thp",
+ "touch",
+ "touch_wakeup",
+ # "tropic", # selected from xtask
+ "layout_eckhart",
+ "rgb_led",
+]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+block_on_vcp = ["sys/block_on_vcp"]
+bootloader_devel = ["sec/bootloader_devel"]
+benchmark = ["upymod/benchmark", "rtl/aes_gcm"]
+clippy = ["trezor_lib/clippy"]
+dbg_console = ["sys/dbg_console", "trezor_lib/dbg_console"]
+debug = ["trezor_lib/debug"]
+debuglink = ["trezor_lib/debuglink", "io/usb_iface_debug"]
+dev_keys = ["trezor_lib/dev_keys"]
+disable_animation = ["upymod/disable_animation"]
+emulator = ["io/emulator", "upymod/emulator"]
+force_bootloader_upgrade = []
+micropy_enable_source_lines = ["upymod/enable_source_lines"]
+n4w1 = ["upymod/n4w1"]
+frozen = ["upymod/frozen"]
+log_stack_usage = ["upymod/log_stack_usage"]
+optiga_testing = ["sec/optiga_testing"]
+production = ["io/production"]
+pyopt = ["upymod/pyopt"]
+storage_insecure_testing_mode = ["sec/storage_insecure_testing_mode"]
+ui_debug = ["trezor_lib/ui_debug"]
+ui_debug_overlay = ["trezor_lib/ui_debug_overlay"]
+ui_performance_overlay = ["trezor_lib/ui_performance_overlay"]
+universal_fw = ["trezor_lib/universal_fw", "upymod/universal_fw"]
+unsafe_fw = []
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "io/display",
+ "io/fancy_fatal_error",
+ "io/usb_iface_wire",
+ "rtl/secp256k1_zkp",
+
+ "trezor_lib/with_new_crates", # only for transitional period
+ "trezor_lib/with_upymod", # only for transitional period
+
+ "trezor_lib/crypto",
+ "trezor_lib/micropython",
+ "trezor_lib/protobuf",
+ "trezor_lib/ui",
+ "trezor_lib/storage",
+ "trezor_lib/translations",
+ "trezor_lib/usb",
+]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "upymod/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "upymod/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32u58 = ["io/mcu_stm32u58", "upymod/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "upymod/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone", "mcu_stm32"]
+mcu_stm32 = []
+
+app_loading = ["upymod/app_loading", "trezor_lib/app_loading", "io/ipc"]
+backlight = ["io/backlight", "upymod/backlight", "trezor_lib/backlight"]
+backup_ram = ["sec/backup_ram"]
+ble = ["io/ble", "upymod/ble", "trezor_lib/ble", "nrf", "nrf_auth"]
+boot_ucb = ["sec/boot_ucb", "trezor_lib/boot_ucb"]
+button = ["io/button", "upymod/button", "trezor_lib/button"]
+consumption_mask = ["sec/consumption_mask"]
+dma2d = ["io/dma2d", "trezor_lib/dma2d"]
+haptic = ["io/haptic", "upymod/haptic", "trezor_lib/haptic"]
+hash_processor = ["sec/hash_processor"]
+iwdg = ["sec/iwdg"]
+lockable_bootloader = ["io/lockable_bootloader"]
+mcu_attestation = ["sec/mcu_attestation", "upymod/mcu_attestation"]
+nrf = ["io/nrf", "trezor_lib/nrf"]
+nrf_auth = ["io/nrf_auth"]
+optiga = ["sec/optiga", "upymod/optiga", "trezor_lib/optiga"]
+power_manager = [
+ "io/power_manager",
+ "upymod/power_manager",
+ "trezor_lib/power_manager",
+ "trezor_lib/pmic",
+]
+rgb_led = ["io/rgb_led", "upymod/rgb_led", "trezor_lib/rgb_led"]
+sd_card = ["io/sd_card", "upymod/sd_card", "trezor_lib/sd_card"]
+secmon_layout = ["models/secmon_layout"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+serial_number = ["upymod/serial_number", "trezor_lib/serial_number"]
+suspend = ["io/suspend"]
+storage_hw_key = ["sec/storage_hw_key"]
+thp = ["upymod/thp", "rtl/aes_gcm"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry", "upymod/telemetry", "trezor_lib/telemetry"]
+touch = ["io/touch", "upymod/touch", "trezor_lib/touch"]
+touch_wakeup = ["io/touch_wakeup", "upymod/touch_wakeup", "trezor_lib/touch_wakeup"]
+tropic = ["sec/tropic", "upymod/tropic", "trezor_lib/tropic"]
+
+layout_bolt_d001 = [
+ "trezor_lib/layout_bolt",
+ "upymod/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_jpeg",
+]
+
+layout_bolt_d002 = [
+ "trezor_lib/layout_bolt",
+ "upymod/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_jpeg",
+]
+
+layout_bolt = [
+ "trezor_lib/layout_bolt",
+ "upymod/layout_bolt",
+ "trezor_lib/display_rgb565",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_jpeg",
+]
+
+layout_caesar = [
+ "trezor_lib/layout_caesar",
+ "upymod/layout_caesar",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_mono",
+]
+
+layout_delizia = [
+ "trezor_lib/layout_delizia",
+ "upymod/layout_delizia",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_image_buffer",
+ "trezor_lib/ui_overlay",
+ "trezor_lib/ui_jpeg",
+ "trezor_lib/ui_font_kerning",
+]
+
+layout_eckhart = [
+ "trezor_lib/layout_eckhart",
+ "upymod/layout_eckhart",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_image_buffer",
+ "trezor_lib/ui_color_32bit",
+ "trezor_lib/ui_overlay",
+ "trezor_lib/ui_jpeg",
+ "trezor_lib/ui_font_kerning",
+ "trezor_lib/hw_jpeg_decoder",
+ "io/hw_jpeg_decoder",
+
+]
diff --git a/core/embed/projects/firmware/build.rs b/core/embed/projects/firmware/build.rs
new file mode 100644
index 00000000..24ba6128
--- /dev/null
+++ b/core/embed/projects/firmware/build.rs
@@ -0,0 +1,83 @@
+use std::{env, path::PathBuf};
+
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("firmware", |lib| {
+ lib.import_lib("io")?;
+ lib.import_lib("upymod")?;
+
+ lib.add_includes(["."]);
+
+ lib.add_include("../../rust"); // Cyclic dependency
+
+ lib.add_sources(["main.c", "header.S", "boot_image_embdata.c"]);
+
+ if cfg!(feature = "mcu_stm32") {
+ lib.add_source("stm32/coreapp_header.S");
+ } else {
+ bail_unsupported!()
+ }
+
+ if cfg!(feature = "app_loading") {
+ lib.add_source("../../api/trezor_api_v1_impl.c");
+ }
+
+ if cfg!(feature = "force_bootloader_upgrade") {
+ lib.add_define("FORCE_BOOTLOADER_UPGRADE", Some("1"));
+ }
+
+ lib.embed_binary(
+ xbuild::vendor_header_path("../../models", "firmware")?,
+ "vendorheader",
+ )?;
+
+ embed_bootloader_binary(lib)?;
+ embed_kernel_binary(lib)?;
+
+ if cfg!(feature = "nrf") {
+ embed_nrf_app_binary(lib)?;
+ }
+
+ Ok(())
+ })
+}
+
+fn embed_kernel_binary(lib: &mut CLibrary) -> Result<()> {
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+ let kernel = out_dir.join("../../../kernel.bin");
+ lib.embed_binary(&kernel, "kernel")
+}
+
+fn embed_bootloader_binary(lib: &mut CLibrary) -> Result<()> {
+ let model_id = xbuild::current_model_id()?;
+ let model_dir = format!("../../models/{}", model_id);
+ let suffix = if cfg!(feature = "bootloader_devel") {
+ "_devel"
+ } else {
+ ""
+ };
+
+ let bootloader = format!("{model_dir}/bootloaders/bootloader_{model_id}{suffix}.bin");
+
+ if cfg!(feature = "boot_ucb") {
+ // embed uncompressed bootloader image
+ lib.embed_binary(bootloader, "bootloader")?;
+ } else {
+ lib.embed_compressed_binary(bootloader, "bootloader")?;
+ }
+
+ Ok(())
+}
+
+fn embed_nrf_app_binary(lib: &mut CLibrary) -> Result<()> {
+ let model_id = xbuild::current_model_id()?;
+ let model_dir = format!("../../models/{}", model_id);
+ let suffix = if cfg!(feature = "bootloader_devel") {
+ "-dev"
+ } else {
+ ""
+ };
+ let nrf_app = format!("{model_dir}/trezor-ble{suffix}.bin");
+ lib.embed_binary(&nrf_app, "nrf_app")
+}
diff --git a/core/embed/projects/firmware/src/main.rs b/core/embed/projects/firmware/src/main.rs
new file mode 100644
index 00000000..f56c4ae3
--- /dev/null
+++ b/core/embed/projects/firmware/src/main.rs
@@ -0,0 +1,4 @@
+#![no_std]
+#![no_main]
+
+use trezor_lib as _;
diff --git a/core/embed/projects/kernel/Cargo.toml b/core/embed/projects/kernel/Cargo.toml
new file mode 100644
index 00000000..c7fb58a2
--- /dev/null
+++ b/core/embed/projects/kernel/Cargo.toml
@@ -0,0 +1,216 @@
+[package]
+name = "kernel"
+version = "0.0.0"
+edition = "2024"
+links = "kernel"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+trezor_lib.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = [
+ "io/model_d001",
+ "mcu_stm32f429",
+ "dma2d",
+ "pvd",
+ "sdram",
+ "secure_mode",
+ "touch",
+]
+
+model_d002 = [
+ "io/model_d002",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "secmon_layout",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "touch",
+]
+
+model_t2t1 = [
+ "io/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "dma2d",
+ "pvd",
+ "sd_card",
+ "secure_mode",
+ "touch",
+ ]
+
+model_t2b1 = [
+ "io/model_t2b1",
+ "mcu_stm32f427",
+ "button",
+ "consumption_mask",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "pvd",
+ "secret",
+ "secure_mode",
+ ]
+
+model_t3b1 = [
+ "io/model_t3b1",
+ "mcu_stm32u58",
+ "button",
+ "consumption_mask",
+ "hash_processor",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "pvd",
+ "secret",
+ "secure_aes",
+ "secure_mode",
+ "storage_hw_key",
+ "tamper",
+ ]
+
+model_t3t1 = [
+ "io/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "pvd",
+ "sd_card",
+ "secret",
+ "secure_aes",
+ "secure_mode",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ ]
+
+model_t3w1 = [
+ "io/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "backup_ram",
+ "boot_ucb",
+ "ble",
+ "button",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "hw_jpeg_decoder",
+ "lockable_bootloader",
+ "mcu_attestation",
+ # "optiga", # selected from xtask
+ "power_manager",
+ "rgb_led",
+ "rtc",
+ "secmon_layout",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "suspend",
+ "smp",
+ "tamper",
+ "telemetry",
+ "touch",
+ "touch_wakeup",
+ # "tropic", # selected from xtask
+ ]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+app_loading = ["io/app_loading", "io/ipc"]
+bootloader_devel = ["sec/bootloader_devel"]
+clippy = []
+emulator = ["io/emulator"]
+block_on_vcp = ["sys/block_on_vcp"]
+dbg_console_swo = ["dbg_console", "sys/dbg_console_swo"]
+dbg_console_vcp = ["dbg_console", "sys/dbg_console_vcp", "io/usb_iface_vcp"]
+dbg_console_system_view = ["dbg_console", "sys/dbg_console_system_view"]
+debuglink = ["io/usb_iface_debug"]
+force_bootloader_upgrade = []
+optiga_testing = ["sec/optiga_testing"]
+production = ["sys/production"]
+storage_insecure_testing_mode = ["sec/storage_insecure_testing_mode"]
+universal_fw = ["io/usb_iface_webauthn"]
+unsafe_fw = []
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "sys/applets",
+ "io/display",
+ "io/kernel_mode",
+ "io/usb_iface_wire",
+ "sec/rdi",
+ "sec/storage",
+ "models/kernel",
+ "rtl/aes_gcm",
+ "trezor_lib/with_new_crates", # only for transitional period
+ ]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = []
+mcu_stm32u58 = ["io/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone"]
+
+secure_mode = ["io/secure_mode"]
+
+backlight = ["io/backlight"]
+backup_ram = ["sec/backup_ram"]
+boot_ucb = ["sec/boot_ucb"]
+ble = ["io/ble", "nrf", "nrf_auth"]
+button = ["io/button"]
+consumption_mask = ["sec/consumption_mask"]
+dbg_console = ["sys/dbg_console"]
+dma2d = ["io/dma2d"]
+haptic = ["io/haptic"]
+hash_processor = ["sec/hash_processor"]
+hw_jpeg_decoder = ["io/hw_jpeg_decoder"]
+lockable_bootloader = ["io/lockable_bootloader"]
+mcu_attestation = ["sec/mcu_attestation"]
+nrf = ["io/nrf"]
+nrf_auth = ["io/nrf_auth"]
+optiga = ["sec/optiga"]
+power_manager = ["io/power_manager"]
+pvd = ["sys/pvd"]
+rgb_led = ["io/rgb_led"]
+rtc = ["sys/rtc"]
+sd_card = ["io/sd_card"]
+sdram = ["sys/sdram"]
+secmon_layout = ["models/secmon_layout"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+smp = ["io/smp", "trezor_lib/smp", "trezor_lib/nrf"]
+storage_hw_key = ["sec/storage_hw_key"]
+suspend = ["io/suspend"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry"]
+touch = ["io/touch"]
+touch_wakeup = ["io/touch_wakeup"]
+tropic = ["sec/tropic"]
diff --git a/core/embed/projects/kernel/build.rs b/core/embed/projects/kernel/build.rs
new file mode 100644
index 00000000..8782e657
--- /dev/null
+++ b/core/embed/projects/kernel/build.rs
@@ -0,0 +1,56 @@
+use std::{env, path::PathBuf};
+
+use xbuild::{CLibrary, Result};
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("kernel", |lib| {
+ lib.import_lib("io")?;
+
+ lib.add_source("main.c");
+
+ lib.add_sources_in_dir(
+ "../../sys/syscall/stm32",
+ [
+ "syscall_context.c",
+ "syscall_dispatch.c",
+ "syscall_ipc.c",
+ "syscall_probe.c",
+ "syscall_verifiers.c",
+ ],
+ );
+
+ lib.embed_binary(
+ xbuild::vendor_header_path("../../models", "kernel")?,
+ "vendorheader",
+ )?;
+
+ if cfg!(feature = "secmon_layout") {
+ embed_secmon_binary(lib)?;
+ }
+
+ Ok(())
+ })
+}
+
+fn embed_secmon_binary(lib: &mut CLibrary) -> Result<()> {
+ let model_id = xbuild::current_model_id()?;
+ let dir = PathBuf::from(format!("../../models/{}/secmon", model_id));
+
+ if cfg!(feature = "bootloader_devel") {
+ if cfg!(feature = "unsafe_fw") {
+ lib.add_object(dir.join("secmon_api_DEV.o"));
+ lib.embed_binary(dir.join("secmon_DEV.bin"), "secmon")?;
+ } else {
+ // Take recently built secmon from the output directory
+ let dir = PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../..");
+ lib.add_object(dir.join("secmon_api.o"));
+ lib.embed_binary(dir.join("secmon.bin"), "secmon")?;
+ }
+ } else {
+ // Take officially released secmon
+ lib.add_object(dir.join("secmon_api.o"));
+ lib.embed_binary(dir.join("secmon.bin"), "secmon")?;
+ }
+
+ Ok(())
+}
diff --git a/core/embed/projects/kernel/src/main.rs b/core/embed/projects/kernel/src/main.rs
new file mode 100644
index 00000000..f56c4ae3
--- /dev/null
+++ b/core/embed/projects/kernel/src/main.rs
@@ -0,0 +1,4 @@
+#![no_std]
+#![no_main]
+
+use trezor_lib as _;
diff --git a/core/embed/projects/prodtest/Cargo.toml b/core/embed/projects/prodtest/Cargo.toml
new file mode 100644
index 00000000..7745c5a4
--- /dev/null
+++ b/core/embed/projects/prodtest/Cargo.toml
@@ -0,0 +1,276 @@
+[package]
+name = "prodtest"
+version = "0.0.0"
+edition = "2024"
+links = "prodtest"
+
+[build-dependencies]
+xbuild.workspace = true
+
+[dependencies]
+trezor_lib.workspace = true
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = [
+ "io/model_d001",
+ "mcu_stm32f429",
+ "dma2d",
+ "pvd",
+ "sdram",
+ "touch",
+ "layout_bolt_d001",
+]
+
+model_d002 = [
+ "io/model_d002",
+ "mcu_stm32u5g",
+ "backlight",
+ "boot_ucb",
+ "dma2d",
+ "hash_processor",
+ "lockable_bootloader",
+ "secmon_header",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ "layout_bolt_d002",
+]
+
+model_t2t1 = [
+ "io/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "pvd",
+ "touch",
+ "sbu",
+ "sd_card",
+ "layout_bolt",
+]
+
+model_t2b1 = [
+ "io/model_t2b1",
+ "mcu_stm32f427",
+ "button",
+ "consumption_mask",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "pvd",
+ "sbu",
+ "secret",
+ "layout_caesar",
+]
+
+model_t3b1 = [
+ "io/model_t3b1",
+ "mcu_stm32u58",
+ "button",
+ "consumption_mask",
+ "hash_processor",
+ "hw_revision",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "pvd",
+ "sbu",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "layout_caesar",
+]
+
+model_t3t1 = [
+ "io/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "haptic",
+ "hash_processor",
+ "hw_revision",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "pvd",
+ "sbu",
+ "sd_card",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ "touch",
+ "layout_delizia",
+]
+
+model_t3w1 = [
+ "io/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "backup_ram",
+ "ble",
+ "boot_ucb",
+ "button",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "hw_revision",
+ "iwdg",
+ "lockable_bootloader",
+ "mcu_attestation",
+ "nfc",
+ # "optiga", # selected from xtask
+ "power_manager",
+ "rgb_led",
+ "rtc",
+ "sbu",
+ "secmon_header",
+ "secret",
+ "secure_aes",
+ "smp",
+ "storage_hw_key",
+ "suspend",
+ "tamper",
+ "telemetry",
+ "touch",
+ "touch_wakeup",
+ # "tropic", # selected from xtask
+ "layout_eckhart",
+]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+bootloader_devel = ["sec/bootloader_devel"]
+clippy = ["trezor_lib/clippy"]
+emulator = ["io/emulator"]
+dbg_console_swo = ["dbg_console"]
+dbg_console_system_view = ["dbg_console", "sys/system_view"]
+debug = ["trezor_lib/debug"]
+debuglink = ["trezor_lib/debuglink", "io/usb_iface_debug"]
+production = ["io/production"]
+ui_debug = ["trezor_lib/ui_debug"]
+ui_debug_overlay = ["trezor_lib/ui_debug_overlay"]
+ui_performance_overlay = ["trezor_lib/ui_performance_overlay"]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "io/display",
+ # "io/fancy_fatal_error", # switched off in prodtest
+ "io/kernel_mode",
+ "io/secure_mode",
+ "io/usb_iface_vcp",
+ "models/prodtest",
+ "rtl/sprintf",
+ "rtl/mldsa",
+ "rtl/aes_gcm",
+ "rtl/noise",
+
+ "trezor_lib/with_new_crates", # only for transitional period
+
+ "trezor_lib/crypto",
+ "trezor_lib/ui",
+ "trezor_lib/prodtest",
+ "trezor_lib/usb",
+]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = []
+mcu_stm32u58 = ["io/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone"]
+
+backlight = ["io/backlight", "trezor_lib/backlight"]
+backup_ram = ["sec/backup_ram"]
+ble = ["io/ble", "trezor_lib/ble", "nrf", "nrf_auth"]
+boot_ucb = ["sec/boot_ucb", "trezor_lib/boot_ucb"]
+button = ["io/button", "trezor_lib/button"]
+consumption_mask = ["sec/consumption_mask"]
+dbg_console = ["sys/dbg_console", "trezor_lib/dbg_console"]
+dma2d = ["io/dma2d", "trezor_lib/dma2d"]
+haptic = ["io/haptic", "trezor_lib/haptic"]
+hash_processor = ["sec/hash_processor"]
+hw_revision = ["sec/hw_revision"]
+iwdg = ["sec/iwdg"]
+lockable_bootloader = ["io/lockable_bootloader"]
+mcu_attestation = ["sec/mcu_attestation"]
+nfc = ["io/nfc"]
+nrf = ["io/nrf", "trezor_lib/nrf"]
+nrf_auth = ["io/nrf_auth"]
+optiga = [
+ "sec/optiga",
+ "trezor_lib/optiga",
+ "sec/storage",
+] # TODO: optiga depends on storage
+power_manager = [
+ "io/power_manager",
+ "trezor_lib/power_manager",
+ "trezor_lib/pmic",
+]
+pvd = ["sys/pvd"]
+rgb_led = ["io/rgb_led", "trezor_lib/rgb_led"]
+rtc = ["sys/rtc"]
+sd_card = ["io/sd_card", "trezor_lib/sd_card"]
+sbu = ["io/sbu", "trezor_lib/sbu"]
+sdram = ["sys/sdram"]
+secmon_header = []
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+smp = ["io/smp", "trezor_lib/smp"]
+storage_hw_key = ["sys/storage_hw_key"]
+suspend = ["io/suspend"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry", "trezor_lib/telemetry"]
+touch = ["io/touch", "trezor_lib/touch"]
+touch_wakeup = ["io/touch_wakeup", "trezor_lib/touch_wakeup"]
+tropic = ["sec/tropic", "trezor_lib/tropic"]
+
+
+layout_bolt_d001 = [
+ "trezor_lib/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+]
+
+layout_bolt_d002 = [
+ "trezor_lib/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_color_32bit",
+]
+
+layout_bolt = ["trezor_lib/layout_bolt", "trezor_lib/display_rgb565"]
+
+layout_caesar = [
+ "trezor_lib/layout_caesar",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_mono",
+]
+
+layout_delizia = [
+ # "trezor_lib/layout_delizia" is not implemented for prodtest
+ "trezor_lib/layout_bolt",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+ "trezor_lib/ui_font_kerning",
+]
+
+layout_eckhart = [
+ "trezor_lib/layout_eckhart",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_color_32bit",
+ "trezor_lib/ui_font_kerning",
+]
diff --git a/core/embed/projects/prodtest/build.rs b/core/embed/projects/prodtest/build.rs
new file mode 100644
index 00000000..31c38560
--- /dev/null
+++ b/core/embed/projects/prodtest/build.rs
@@ -0,0 +1,79 @@
+use xbuild::Result;
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("prodtest", |lib| {
+ lib.import_lib("io")?;
+
+ lib.add_includes(["."]);
+
+ lib.add_include("../../rust"); // Cyclic dependency
+
+ lib.add_sources(["main.c", "commands.c"]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("emulator.c");
+ } else {
+ lib.add_source("header.S");
+
+ if cfg!(feature = "secmon_header") {
+ lib.add_source("secmon_header.S");
+ }
+ }
+
+ lib.add_sources_in_dir(
+ "cmd",
+ [
+ "common.c",
+ "prodtest_boardloader.c",
+ "prodtest_button.c",
+ "prodtest_crc.c",
+ "prodtest_display.c",
+ "prodtest_prodtest.c",
+ "prodtest_backup_ram.c",
+ "prodtest_get_cpuid.c",
+ "prodtest_haptic.c",
+ "prodtest_help.c",
+ "prodtest_hw_revision.c",
+ "prodtest_manufacturing_lock.c",
+ "prodtest_otp_batch.c",
+ "prodtest_otp_variant.c",
+ "prodtest_ping.c",
+ "prodtest_reboot.c",
+ "prodtest_rgbled.c",
+ "prodtest_sdcard.c",
+ "prodtest_tamper.c",
+ "prodtest_sbu.c",
+ "prodtest_secure_channel.c",
+ "prodtest_telemetry.c",
+ "prodtest_touch.c",
+ "prodtest_tropic.c",
+ "prodtest_unit_test.c",
+ "secure_channel.c",
+ ],
+ );
+
+ if cfg!(not(feature = "emulator")) {
+ lib.add_sources_in_dir(
+ "cmd",
+ [
+ "prodtest_ble.c",
+ "prodtest_bootloader.c",
+ "prodtest_nfc.c",
+ "prodtest_rtc.c",
+ "prodtest_nrf.c",
+ "prodtest_optiga.c",
+ "prodtest_power_manager.c",
+ "prodtest_secrets.c",
+ "prodtest_wpc.c",
+ ],
+ );
+
+ lib.embed_binary(
+ xbuild::vendor_header_path("../../models", "prodtest")?,
+ "vendorheader",
+ )?;
+ }
+
+ Ok(())
+ })
+}
diff --git a/core/embed/projects/prodtest/cmd/prodtest_otp_variant.c b/core/embed/projects/prodtest/cmd/prodtest_otp_variant.c
index 8b692b0f..1477a407 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_otp_variant.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_otp_variant.c
@@ -148,7 +148,7 @@ static void prodtest_otp_variant_write(cli_t* cli) {
}
#endif
-#ifdef USE_OPTIGA
+#if defined(USE_OPTIGA) && !defined(TREZOR_EMULATOR)
optiga_locked_status optiga_status = get_optiga_locked_status(cli);
if (optiga_status == OPTIGA_LOCKED_FALSE) {
@@ -171,7 +171,7 @@ static void prodtest_otp_variant_write(cli_t* cli) {
}
if (tropic_status != TROPIC_LOCKED_TRUE) {
- // Error reported by get_optiga_locked_status().
+ // Error reported by get_tropic_locked_status().
return;
}
#endif
diff --git a/core/embed/projects/prodtest/cmd/prodtest_prodtest.c b/core/embed/projects/prodtest/cmd/prodtest_prodtest.c
index c97c35c0..b55d9aea 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_prodtest.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_prodtest.c
@@ -61,7 +61,7 @@ static void prodtest_prodtest_wipe(cli_t* cli) {
return;
}
-#ifdef USE_BLE
+#if defined(USE_BLE) && !defined(TREZOR_EMULATOR)
cli_trace(cli, "Erasing BLE bonds...");
if (!prodtest_ble_erase_bonds(cli)) {
cli_error(cli, CLI_ERROR, "Failed to erase BLE bonds.");
diff --git a/core/embed/projects/prodtest/src/main.rs b/core/embed/projects/prodtest/src/main.rs
new file mode 100644
index 00000000..f56c4ae3
--- /dev/null
+++ b/core/embed/projects/prodtest/src/main.rs
@@ -0,0 +1,4 @@
+#![no_std]
+#![no_main]
+
+use trezor_lib as _;
diff --git a/core/embed/projects/secmon/Cargo.toml b/core/embed/projects/secmon/Cargo.toml
new file mode 100644
index 00000000..7b4c24bc
--- /dev/null
+++ b/core/embed/projects/secmon/Cargo.toml
@@ -0,0 +1,136 @@
+[package]
+name = "secmon"
+version = "0.0.0"
+edition = "2024"
+links = "secmon"
+
+[[bin]]
+name = "secmon"
+path = "src/main.rs"
+test = false
+bench = false
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d002 = [
+ "sec/model_d002",
+ "mcu_stm32u5g",
+ "boot_ucb",
+ "hash_processor",
+ "lockable_bootloader",
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+]
+
+model_t3b1 = [
+ "sec/model_t3b1",
+ "mcu_stm32u58",
+ "consumption_mask",
+ "hash_processor",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ ]
+
+model_t3t1 = [
+ "sec/model_t3t1",
+ "mcu_stm32u58",
+ "hash_processor",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "tamper",
+ ]
+
+model_t3w1 = [
+ "sec/model_t3w1",
+ "mcu_stm32u5g",
+ "backup_ram",
+ "boot_ucb",
+ "hash_processor",
+ "lockable_bootloader",
+ "mcu_attestation",
+ "nrf_auth",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "storage_hw_key",
+ "suspend",
+ "tamper",
+ "telemetry",
+ #"tropic", # selected from xtask
+ ]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+bootloader_devel = ["sec/bootloader_devel"]
+clippy = []
+emulator = ["sec/emulator"]
+dbg_console_swo = ["dbg_console"]
+dbg_console_system_view = ["dbg_console", "sys/system_view"]
+force_bootloader_upgrade = []
+optiga_testing = ["sec/optiga_testing"]
+production = ["sec/production"]
+storage_insecure_testing_mode = ["sec/storage_insecure_testing_mode"]
+universal_fw = []
+unsafe_fw = []
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "secmon_layout",
+ "models/secmon",
+ "sec/kernel_mode",
+ "sec/secure_mode",
+ "sec/storage",
+ "sec/rdi",
+ "rtl/aes_gcm",
+ ]
+
+mcu_stm32u58 = ["sec/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["sec/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone"]
+
+backup_ram = ["sec/backup_ram"]
+boot_ucb = ["sec/boot_ucb"]
+consumption_mask = ["sec/consumption_mask"]
+dbg_console = ["sys/dbg_console"]
+hash_processor = ["sec/hash_processor"]
+lockable_bootloader = ["sec/lockable_bootloader"]
+mcu_attestation = ["sec/mcu_attestation"]
+nrf_auth = ["sec/nrf_auth"]
+optiga = ["sec/optiga"]
+secmon_layout = ["models/secmon_layout"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+storage_hw_key = ["sec/storage_hw_key"]
+suspend = ["sec/suspend"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry"]
+tropic = ["sec/tropic"]
+
diff --git a/core/embed/projects/secmon/build.rs b/core/embed/projects/secmon/build.rs
new file mode 100644
index 00000000..c3fa5900
--- /dev/null
+++ b/core/embed/projects/secmon/build.rs
@@ -0,0 +1,23 @@
+use xbuild::Result;
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("secmon", |lib| {
+ lib.import_lib("sec")?;
+
+ lib.add_include(".");
+
+ lib.add_sources(["main.c", "header.S"]);
+
+ lib.add_sources_in_dir(
+ "../../sys/smcall/stm32",
+ ["smcall_dispatch.c", "smcall_probe.c", "smcall_verifiers.c"],
+ );
+
+ lib.embed_binary(
+ xbuild::vendor_header_path("../../models", "secmon")?,
+ "vendorheader",
+ )?;
+
+ Ok(())
+ })
+}
diff --git a/core/embed/projects/secmon/src/main.rs b/core/embed/projects/secmon/src/main.rs
new file mode 100644
index 00000000..ead0a014
--- /dev/null
+++ b/core/embed/projects/secmon/src/main.rs
@@ -0,0 +1,7 @@
+#![no_std]
+#![no_main]
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
diff --git a/core/embed/projects/unix/Cargo.toml b/core/embed/projects/unix/Cargo.toml
new file mode 100644
index 00000000..83973319
--- /dev/null
+++ b/core/embed/projects/unix/Cargo.toml
@@ -0,0 +1,242 @@
+[package]
+name = "unix"
+version = "0.0.0"
+edition = "2024"
+links = "unix"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+trezor_lib.workspace = true
+io.workspace = true
+sec.workspace = true
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+upymod.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = []
+model_d002 = []
+
+model_t2t1 = [
+ "upymod/model_t2t1",
+ "mcu_stm32f427",
+ "backlight",
+ "dma2d",
+ "touch",
+ "layout_bolt",
+ "sd_card",
+]
+
+model_t2b1 = [
+ "upymod/model_t2b1",
+ "mcu_stm32f427",
+ "button",
+ "consumption_mask",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "secret",
+ "layout_caesar",
+]
+
+model_t3b1 = [
+ "upymod/model_t3b1",
+ "mcu_stm32u58",
+ "button",
+ "consumption_mask",
+ "hash_processor",
+ "lockable_bootloader",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "tamper",
+ "layout_caesar",
+]
+
+model_t3t1 = [
+ "upymod/model_t3t1",
+ "mcu_stm32u58",
+ "backlight",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "lockable_bootloader",
+ "sd_card",
+ # "optiga", # selected from xtask
+ "secret",
+ "secure_aes",
+ "tamper",
+ "touch",
+ "layout_delizia",
+]
+
+model_t3w1 = [
+ "upymod/model_t3w1",
+ "mcu_stm32u5g",
+ "backlight",
+ "backup_ram",
+ "ble",
+ "boot_ucb",
+ "button",
+ "dma2d",
+ "haptic",
+ "hash_processor",
+ "iwdg",
+ "lockable_bootloader",
+ "mcu_attestation",
+ # "optiga", # selected from xtask
+ "power_manager",
+ "secret",
+ "serial_number",
+ "suspend",
+ "tamper",
+ "telemetry",
+ "thp",
+ "touch",
+ "touch_wakeup",
+ "layout_eckhart",
+ "rgb_led",
+ # "tropic", # selected from xtask
+]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+asan = ["models/asan"]
+benchmark = ["upymod/benchmark", "rtl/aes_gcm"]
+clippy = ["trezor_lib/clippy"]
+dbg_console = ["sys/dbg_console", "trezor_lib/dbg_console"]
+debug = ["trezor_lib/debug"]
+debuglink = ["trezor_lib/debuglink", "io/usb_iface_debug"]
+disable_animation = ["upymod/disable_animation"]
+emulator = ["io/emulator", "upymod/emulator"]
+log_stack_usage = ["upymod/log_stack_usage"]
+memperf = ["upymod/memperf"]
+micropy_enable_source_lines = ["upymod/enable_source_lines"]
+n4w1 = ["upymod/n4w1"]
+frozen = ["upymod/frozen"]
+optiga_testing = ["sec/optiga_testing"]
+pyopt = ["upymod/pyopt"]
+ui_debug = ["trezor_lib/ui_debug"]
+ui_debug_overlay = ["trezor_lib/ui_debug_overlay"]
+ui_performance_overlay = ["trezor_lib/ui_performance_overlay"]
+universal_fw = ["trezor_lib/universal_fw", "upymod/universal_fw", "io/usb_iface_webauthn"]
+unsafe_fw = []
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = [
+ "sys/applets",
+ "io/display",
+ "io/fancy_fatal_error",
+ "io/kernel_mode",
+ "io/secure_mode",
+ "io/usb_iface_wire",
+ "sec/rdi",
+ "rtl/secp256k1_zkp",
+ "rtl/aes_gcm",
+
+ "trezor_lib/with_new_crates", # only for transitional period
+ "trezor_lib/with_upymod", # only for transitional period
+
+ "trezor_lib/crypto",
+ "trezor_lib/micropython",
+ "trezor_lib/protobuf",
+ "trezor_lib/ui",
+ "trezor_lib/storage",
+ "trezor_lib/translations",
+ "trezor_lib/usb",
+ ]
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "upymod/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "upymod/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32u58 = ["io/mcu_stm32u58", "upymod/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "upymod/mcu_stm32u5g", "mcu_stm32u5"]
+mcu_stm32u5 = ["sec/trustzone", "mcu_stm32"]
+mcu_stm32 = []
+
+app_loading = ["io/app_loading", "upymod/app_loading", "trezor_lib/app_loading", "io/ipc"]
+backlight = ["io/backlight", "upymod/backlight", "trezor_lib/backlight"]
+backup_ram = ["sec/backup_ram"]
+ble = ["io/ble", "upymod/ble", "trezor_lib/ble", "nrf", "nrf_auth"]
+boot_ucb = ["sec/boot_ucb", "trezor_lib/boot_ucb"]
+button = ["io/button", "upymod/button","trezor_lib/button"]
+consumption_mask = ["sec/consumption_mask"]
+dev_keys = ["trezor_lib/dev_keys"]
+dma2d = ["io/dma2d", "trezor_lib/dma2d"]
+haptic = ["io/haptic", "upymod/haptic", "trezor_lib/haptic"]
+hash_processor = ["sec/hash_processor"]
+iwdg = ["sec/iwdg"]
+lockable_bootloader = ["io/lockable_bootloader"]
+mcu_attestation = ["sec/mcu_attestation", "upymod/mcu_attestation"]
+nrf = ["io/nrf", "trezor_lib/nrf"]
+nrf_auth = ["io/nrf_auth"]
+optiga = ["sec/optiga", "upymod/optiga", "trezor_lib/optiga"]
+power_manager = ["io/power_manager", "upymod/power_manager", "trezor_lib/power_manager", "trezor_lib/pmic"]
+rgb_led = ["io/rgb_led", "upymod/rgb_led", "trezor_lib/rgb_led"]
+sd_card = ["io/sd_card", "upymod/sd_card", "trezor_lib/sd_card"]
+secret = ["sec/secret"]
+secure_aes = ["sec/secure_aes"]
+serial_number = ["upymod/serial_number", "trezor_lib/serial_number"]
+suspend = ["io/suspend"]
+storage_hw_key = ["sec/storage_hw_key"]
+tamper = ["sec/tamper"]
+telemetry = ["sec/telemetry", "upymod/telemetry", "trezor_lib/telemetry"]
+thp = ["upymod/thp", "rtl/aes_gcm"]
+touch = ["io/touch", "upymod/touch", "trezor_lib/touch"]
+touch_wakeup = ["io/touch_wakeup", "upymod/touch_wakeup", "trezor_lib/touch_wakeup"]
+tropic = ["sec/tropic", "upymod/tropic", "trezor_lib/tropic"]
+
+layout_bolt = [
+ "trezor_lib/layout_bolt",
+ "upymod/layout_bolt",
+ "trezor_lib/display_rgb565",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_jpeg",
+ ]
+
+layout_caesar = [
+ "trezor_lib/layout_caesar",
+ "upymod/layout_caesar",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_mono",
+ ]
+
+layout_delizia = [
+ "trezor_lib/layout_delizia",
+ "upymod/layout_delizia",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgb565",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_image_buffer",
+ "trezor_lib/ui_overlay",
+ "trezor_lib/ui_jpeg",
+ "trezor_lib/ui_font_kerning",
+ ]
+
+layout_eckhart = [
+ "trezor_lib/layout_eckhart",
+ "upymod/layout_eckhart",
+ "trezor_lib/framebuffer",
+ "trezor_lib/display_rgba8888",
+ "trezor_lib/ui_blurring",
+ "trezor_lib/ui_image_buffer",
+ "trezor_lib/ui_color_32bit",
+ "trezor_lib/ui_overlay",
+ "trezor_lib/ui_jpeg",
+ "trezor_lib/ui_font_kerning",
+ "trezor_lib/hw_jpeg_decoder",
+ "io/hw_jpeg_decoder",
+ ]
diff --git a/core/embed/projects/unix/build.rs b/core/embed/projects/unix/build.rs
new file mode 100644
index 00000000..64590def
--- /dev/null
+++ b/core/embed/projects/unix/build.rs
@@ -0,0 +1,20 @@
+use xbuild::Result;
+
+fn main() -> Result<()> {
+ xbuild::build_and_link("firmware", |lib| {
+ lib.import_lib("io")?;
+ lib.import_lib("upymod")?;
+
+ lib.add_includes(["."]);
+
+ lib.add_include("../../rust"); // Cyclic dependency
+
+ lib.add_sources(["main.c", "main_main.c"]);
+
+ if cfg!(feature = "app_loading") {
+ lib.add_source("../../api/trezor_api_v1_impl.c");
+ }
+
+ Ok(())
+ })
+}
diff --git a/core/embed/projects/unix/src/main.rs b/core/embed/projects/unix/src/main.rs
new file mode 100644
index 00000000..f56c4ae3
--- /dev/null
+++ b/core/embed/projects/unix/src/main.rs
@@ -0,0 +1,4 @@
+#![no_std]
+#![no_main]
+
+use trezor_lib as _;
diff --git a/core/embed/rtl/Cargo.toml b/core/embed/rtl/Cargo.toml
new file mode 100644
index 00000000..5618fa4c
--- /dev/null
+++ b/core/embed/rtl/Cargo.toml
@@ -0,0 +1,67 @@
+[package]
+name = "rtl"
+version = "0.0.0"
+edition = "2024"
+links = "rtl"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+models.workspace = true
+
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = ["models/model_d001"]
+model_d002 = ["models/model_d002"]
+model_t2t1 = ["models/model_t2t1"]
+model_t2b1 = ["models/model_t2b1"]
+model_t3b1 = ["models/model_t3b1"]
+model_t3t1 = ["models/model_t3t1"]
+model_t3w1 = ["models/model_t3w1"]
+
+# --------------------------------------------------------------------------
+# MCU features
+# --------------------------------------------------------------------------
+
+mcu_stm32f427 = ["models/mcu_stm32f427"]
+mcu_stm32f429 = ["models/mcu_stm32f429"]
+mcu_stm32u58 = ["models/mcu_stm32u58"]
+mcu_stm32u5g = ["models/mcu_stm32u5g"]
+
+# --------------------------------------------------------------------------
+# Privilege mode features
+# --------------------------------------------------------------------------
+
+kernel_mode = ["models/kernel_mode"]
+secure_mode = ["models/secure_mode"]
+
+# --------------------------------------------------------------------------
+# Selectable features
+# --------------------------------------------------------------------------
+
+aes_gcm = []
+ed25519_no_precomp = []
+emulator = ["insecure_prng", "models/emulator"]
+insecure_prng = []
+mldsa = []
+noise = ["aes_gcm"]
+production = ["models/production"]
+secp256k1_zkp = []
+sphincsplus = []
+sprintf = []
+universal_fw = []
+
+test = [
+ "mcu_stm32u5g",
+ "model_t3w1",
+ "emulator",
+ "kernel_mode",
+ "secure_mode",
+]
diff --git a/core/embed/rtl/build.rs b/core/embed/rtl/build.rs
new file mode 100644
index 00000000..42dc63a6
--- /dev/null
+++ b/core/embed/rtl/build.rs
@@ -0,0 +1,321 @@
+use xbuild::{Result, WrapErr, bail, ensure};
+
+use std::process::Command;
+
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ lib.import_lib("models")?;
+
+ lib.add_include("inc");
+
+ lib.add_define("SCM_REVISION_SHORT_INIT", Some(&get_scm_revision_short()?));
+
+ lib.add_sources([
+ "cli.c",
+ "error_handling.c",
+ "scm_revision.c",
+ "strutils.c",
+ "unit_test.c",
+ ]);
+
+ if cfg!(any(feature = "sprintf", not(feature = "production"))) {
+ lib.add_source("printf.c");
+ }
+
+ add_crypto(lib)?;
+
+ add_uzlib(lib);
+
+ if cfg!(feature = "test") {
+ lib.add_source("src/test_setup.c");
+ }
+
+ Ok(())
+ })
+}
+
+/// Extracts the first four bytes of the Git revision and formats them
+/// as a C initializer list, e.g. {0x12, 0x34, 0x56, 0x78}.
+fn get_scm_revision_short() -> Result<String> {
+ let git_output = Command::new("git")
+ .args(["rev-parse", "HEAD"])
+ .output()
+ .context("Failed to execute git command")?;
+
+ ensure!(
+ git_output.status.success(),
+ "Git command failed: {}",
+ String::from_utf8_lossy(&git_output.stderr)
+ );
+
+ let git_hash = String::from_utf8_lossy(&git_output.stdout);
+ let git_hash = git_hash.trim();
+
+ ensure!(
+ git_hash.len() >= 8 && git_hash.chars().all(|c| c.is_ascii_hexdigit()),
+ "Unexpected git hash format: {}",
+ git_hash
+ );
+
+ let init_val = git_hash.as_bytes()[..8]
+ .chunks(2)
+ .map(|chunk| {
+ format!(
+ "0x{},",
+ std::str::from_utf8(chunk).expect("git hash must be valid ASCII")
+ )
+ })
+ .collect::<String>();
+
+ Ok(format!("{{{}}}", init_val))
+}
+
+fn add_crypto(lib: &mut xbuild::CLibrary) -> Result<()> {
+ let crypto_path = "../../vendor/trezor-crypto";
+
+ lib.add_include(crypto_path);
+
+ lib.add_defines([
+ ("AES_128", None),
+ ("AES_192", None),
+ ("USE_KECCAK", Some("1")),
+ ("USE_BIP32_CACHE", Some("0")),
+ ]);
+
+ let val = cfg!(feature = "universal_fw");
+ let val = Some(if val { "1" } else { "0" });
+ lib.add_defines([
+ ("USE_ETHEREUM", val),
+ ("USE_MONERO", val),
+ ("USE_CARDANO", val),
+ ]);
+
+ let val = cfg!(feature = "universal_fw") && cfg!(feature = "model_t2t1");
+ let val = Some(if val { "1" } else { "0" });
+ lib.add_defines([("USE_NEM", val), ("USE_EOS", val)]);
+
+ if cfg!(feature = "ed25519_no_precomp") {
+ lib.add_define("ED25519_NO_PRECOMP", None);
+ }
+
+ let crypto_attrs = xbuild::CompileAttrs::new()
+ .with_flag("-ftrivial-auto-var-init=zero")
+ .with_flag("-ffreestanding");
+
+ lib.add_sources_in_dir_with_attrs(
+ crypto_path,
+ [
+ "address.c",
+ "aes/aes_modes.c",
+ "aes/aesccm.c",
+ "aes/aescrypt.c",
+ "aes/aeskey.c",
+ "aes/aestab.c",
+ "base32.c",
+ "base58.c",
+ "bignum.c",
+ "bip32.c",
+ "bip39.c",
+ "bip39_english.c",
+ "blake256.c",
+ "blake2b.c",
+ "blake2s.c",
+ "buffer.c",
+ "chacha20poly1305/chacha20poly1305.c",
+ "chacha20poly1305/chacha_merged.c",
+ "chacha20poly1305/poly1305-donna.c",
+ "chacha20poly1305/rfc7539.c",
+ "chacha_drbg.c",
+ "consteq.c",
+ "curves.c",
+ "der.c",
+ "ecdsa.c",
+ "ed25519-donna/curve25519-donna-32bit.c",
+ "ed25519-donna/curve25519-donna-helpers.c",
+ "ed25519-donna/curve25519-donna-scalarmult-base.c",
+ "ed25519-donna/ed25519-donna-32bit-tables.c",
+ "ed25519-donna/ed25519-donna-basepoint-table.c",
+ "ed25519-donna/ed25519-donna-impl-base.c",
+ "ed25519-donna/ed25519-keccak.c",
+ "ed25519-donna/ed25519-sha3.c",
+ "ed25519-donna/ed25519.c",
+ "ed25519-donna/modm-donna-32bit.c",
+ "elligator2.c",
+ "groestl.c",
+ "hash_to_curve.c",
+ "hasher.c",
+ "hmac.c",
+ "hmac_drbg.c",
+ "memzero.c",
+ "nem.c",
+ "nist256p1.c",
+ "pbkdf2.c",
+ "rand.c",
+ "rfc6979.c",
+ "ripemd160.c",
+ "secp256k1.c",
+ "segwit_addr.c",
+ "sha2.c",
+ "sha3.c",
+ "shamir.c",
+ "slip39.c",
+ "slip39_english.c",
+ "tls_prf.c",
+ ],
+ Some(crypto_attrs.clone()),
+ );
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources_in_dir_with_attrs(
+ crypto_path,
+ ["rand_insecure.c"],
+ Some(crypto_attrs.clone()),
+ );
+ }
+
+ if cfg!(feature = "universal_fw") {
+ lib.add_sources_in_dir_with_attrs(
+ crypto_path,
+ [
+ "cardano.c",
+ "monero/base58.c",
+ "monero/serialize.c",
+ "monero/xmr.c",
+ ],
+ Some(crypto_attrs.clone()),
+ );
+ }
+
+ if cfg!(feature = "insecure_prng") {
+ if cfg!(feature = "production") && !xbuild::is_rust_analyzer() {
+ bail!("insecure_prng cannot be enabled in production builds");
+ }
+ lib.add_define("USE_INSECURE_PRNG", Some("1"));
+ }
+
+ if cfg!(feature = "aes_gcm") {
+ lib.add_defines([("AES_VAR", None), ("USE_AES_GCM", Some("1"))]);
+
+ lib.add_sources_in_dir_with_attrs(
+ crypto_path,
+ ["aes/gf128mul.c", "aes/aesgcm.c"],
+ Some(crypto_attrs.clone()),
+ );
+ }
+
+ if cfg!(feature = "noise") {
+ lib.add_sources_in_dir_with_attrs(crypto_path, ["noise.c"], Some(crypto_attrs.clone()));
+ }
+
+ if cfg!(feature = "secp256k1_zkp") {
+ let secp256k1_path = "../../vendor/secp256k1-zkp";
+
+ lib.add_defines([
+ ("USE_SECP256K1_ZKP", None),
+ ("USE_SECP256K1_ZKP_ECDSA", None),
+ ("USE_EXTERNAL_DEFAULT_CALLBACKS", None),
+ ("ECMULT_GEN_PREC_BITS", Some("2")),
+ ("ECMULT_WINDOW_SIZE", Some("2")),
+ ("ENABLE_MODULE_GENERATOR", None),
+ ("ENABLE_MODULE_RECOVERY", None),
+ ("ENABLE_MODULE_SCHNORRSIG", None),
+ ("ENABLE_MODULE_EXTRAKEYS", None),
+ ("ENABLE_MODULE_ECDH", None),
+ ]);
+
+ // TODO get rid of #include <vendor/... includes in crypto/zkp_*.c
+ // lib.add_include(PathBuf::from(secp256k1_path).join("include"));
+ lib.add_include("../.."); // points to vendor folder
+
+ if cfg!(feature = "emulator") {
+ lib.add_define("SECP256K1_CONTEXT_SIZE", Some("208"));
+ } else {
+ lib.add_define("SECP256K1_CONTEXT_SIZE", Some("180"));
+ lib.add_define("USE_EXTERNAL_ASM", None);
+ lib.add_sources_in_dir(secp256k1_path, ["src/asm/field_10x26_arm.s"]);
+ }
+
+ let secp256k1_attrs = xbuild::CompileAttrs::new()
+ .with_flag("-ffreestanding")
+ .with_flag("-Wno-unused-function");
+
+ lib.add_sources_in_dir_with_attrs(
+ secp256k1_path,
+ [
+ "src/secp256k1.c",
+ "src/precomputed_ecmult.c",
+ "src/precomputed_ecmult_gen.c",
+ ],
+ Some(secp256k1_attrs.clone()),
+ );
+
+ lib.add_sources_in_dir_with_attrs(
+ crypto_path,
+ ["zkp_context.c", "zkp_ecdsa.c", "zkp_bip340.c"],
+ Some(secp256k1_attrs.clone()),
+ );
+ }
+
+ if cfg!(feature = "sphincsplus") {
+ let sphincsplus_path = "../../vendor/sphincsplus/ref";
+
+ lib.add_include(sphincsplus_path);
+
+ lib.add_define("PARAMS", Some("sphincs-sha2-128s"));
+
+ let attrs = xbuild::CompileAttrs::new()
+ .with_flag("-Wno-incompatible-pointer-types")
+ .with_flag("-ftrivial-auto-var-init=zero");
+
+ lib.add_sources_in_dir_with_attrs(
+ sphincsplus_path,
+ [
+ "address.c",
+ "fors.c",
+ "hash_sha2.c",
+ "sha2.c",
+ "sign.c",
+ "thash_sha2_simple.c",
+ "utils.c",
+ "wots.c",
+ ],
+ Some(attrs),
+ );
+ }
+
+ if cfg!(feature = "mldsa") {
+ let mldsa_path = "../../vendor/mldsa-native/mldsa";
+
+ lib.add_include(mldsa_path);
+
+ lib.add_defines([
+ ("MLD_CONFIG_NAMESPACE_PREFIX", Some("mldsa")),
+ ("MLD_CONFIG_NO_RANDOMIZED_API", Some("1")),
+ ]);
+
+ lib.add_sources_in_dir_with_attrs(
+ mldsa_path,
+ [
+ "src/fips202/fips202.c",
+ "src/fips202/fips202x4.c",
+ "src/fips202/keccakf1600.c",
+ "src/packing.c",
+ "src/poly.c",
+ "src/poly_kl.c",
+ "src/polyvec.c",
+ "src/sign.c",
+ ],
+ Some(crypto_attrs.clone()),
+ );
+ }
+
+ Ok(())
+}
+
+fn add_uzlib(lib: &mut xbuild::CLibrary) {
+ let uzlib_path = "../../vendor/micropython/lib/uzlib";
+
+ lib.add_include(uzlib_path);
+
+ lib.add_sources_in_dir(uzlib_path, ["adler32.c", "crc32.c", "tinflate.c"]);
+}
diff --git a/core/embed/rtl/src/lib.rs b/core/embed/rtl/src/lib.rs
new file mode 100644
index 00000000..0c9ac1ac
--- /dev/null
+++ b/core/embed/rtl/src/lib.rs
@@ -0,0 +1 @@
+#![no_std]
diff --git a/core/embed/rtl/src/test_setup.c b/core/embed/rtl/src/test_setup.c
new file mode 100644
index 00000000..bfdb8285
--- /dev/null
+++ b/core/embed/rtl/src/test_setup.c
@@ -0,0 +1,49 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+// Provide definitions of the system exit functions so that they can be
+// called without linking the sys crate. This is needed when compiling the
+// tests for the crates that don't depend on sys, such as the crypto crate.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void system_exit_error(const char *title, const char *message,
+ const char *footer) {
+ printf("Error: %s\n", message);
+ if (title != NULL && *title != '\0') {
+ printf("Title: %s\n", title);
+ }
+
+ if (footer != NULL && *footer != '\0') {
+ printf("Footer: %s\n", footer);
+ }
+
+ exit(1);
+}
+
+void system_exit_fatal(const char *message, const char *file, int line) {
+ printf("Fatal error: %s", message);
+ if (file != NULL && *file != '\0') {
+ printf(" at %s:%d", file, line);
+ }
+ printf("\n");
+
+ exit(1);
+}
diff --git a/core/embed/rtl/unit_test.c b/core/embed/rtl/unit_test.c
index c33b83c9..78f12ec1 100644
--- a/core/embed/rtl/unit_test.c
+++ b/core/embed/rtl/unit_test.c
@@ -21,13 +21,25 @@
#include <rtl/unit_test.h>
+unit_test_t g_ut = {0};
+
+#ifdef TREZOR_EMULATOR
+
+unit_test_t* unit_test_get_records(void) {
+ // Returns an empty list.
+ // TODO: Fix when unit tests are implemented.
+ return &g_ut;
+}
+
+#else
+
extern unit_test_record_t _unit_test_section_start;
extern unit_test_record_t _unit_test_section_end;
-unit_test_t g_ut = {0};
-
unit_test_t* unit_test_get_records(void) {
g_ut.unit_test_array = &_unit_test_section_start;
g_ut.unit_test_count = &_unit_test_section_end - &_unit_test_section_start;
return &g_ut;
}
+
+#endif
diff --git a/core/embed/rust-staticlib/Cargo.toml b/core/embed/rust-staticlib/Cargo.toml
new file mode 100644
index 00000000..c45363f0
--- /dev/null
+++ b/core/embed/rust-staticlib/Cargo.toml
@@ -0,0 +1,70 @@
+[package]
+name = "trezor_lib_staticlib"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+name = "trezor_lib"
+crate-type = ["staticlib"]
+
+[features]
+crypto = ["trezor_lib/crypto"]
+layout_bolt = ["trezor_lib/layout_bolt"]
+layout_caesar = ["trezor_lib/layout_caesar"]
+layout_delizia = ["trezor_lib/layout_delizia"]
+layout_eckhart = ["trezor_lib/layout_eckhart"]
+micropython = ["trezor_lib/micropython"]
+protobuf = ["trezor_lib/protobuf"]
+ui = ["trezor_lib/ui"]
+dma2d = ["trezor_lib/dma2d"]
+framebuffer = ["trezor_lib/framebuffer"]
+display_mono = ["trezor_lib/display_mono"]
+display_rgb565 = ["trezor_lib/display_rgb565"]
+display_rgba8888 = ["trezor_lib/display_rgba8888"]
+ui_debug = ["trezor_lib/ui_debug"]
+ui_performance_overlay = ["trezor_lib/ui_performance_overlay"]
+ui_debug_overlay = ["trezor_lib/ui_debug_overlay"]
+ui_antialiasing = ["trezor_lib/ui_antialiasing"]
+ui_blurring = ["trezor_lib/ui_blurring"]
+ui_image_buffer = ["trezor_lib/ui_image_buffer"]
+ui_color_32bit = ["trezor_lib/ui_color_32bit"]
+ui_overlay = ["trezor_lib/ui_overlay"]
+ui_empty_lock = ["trezor_lib/ui_empty_lock"]
+ui_jpeg = ["trezor_lib/ui_jpeg"]
+ui_font_kerning = ["trezor_lib/ui_font_kerning"]
+hw_jpeg_decoder = ["trezor_lib/hw_jpeg_decoder"]
+boot_ucb = ["trezor_lib/boot_ucb"]
+bootloader = ["trezor_lib/bootloader"]
+prodtest = ["trezor_lib/prodtest"]
+button = ["trezor_lib/button"]
+touch = ["trezor_lib/touch"]
+touch_wakeup = ["trezor_lib/touch_wakeup"]
+clippy = ["trezor_lib/clippy"]
+debug = ["trezor_lib/debug"]
+debuglink = ["trezor_lib/debuglink"]
+dev_keys = ["trezor_lib/dev_keys"]
+sbu = ["trezor_lib/sbu"]
+haptic = ["trezor_lib/haptic"]
+sd_card = ["trezor_lib/sd_card"]
+rgb_led = ["trezor_lib/rgb_led"]
+power_manager = ["trezor_lib/power_manager"]
+pmic = ["trezor_lib/pmic"]
+backlight = ["trezor_lib/backlight"]
+usb = ["trezor_lib/usb"]
+optiga = ["trezor_lib/optiga"]
+ble = ["trezor_lib/ble"]
+nrf = ["trezor_lib/nrf"]
+smp = ["trezor_lib/smp"]
+tropic = ["trezor_lib/tropic"]
+serial_number = ["trezor_lib/serial_number"]
+storage = ["trezor_lib/storage"]
+telemetry = ["trezor_lib/telemetry"]
+n4w1 = ["trezor_lib/n4w1"]
+translations = ["trezor_lib/translations"]
+secmon_layout = ["trezor_lib/secmon_layout"]
+dbg_console = ["trezor_lib/dbg_console"]
+app_loading = ["trezor_lib/app_loading"]
+universal_fw = ["trezor_lib/universal_fw"]
+
+[dependencies]
+trezor_lib = { workspace = true, default-features = false }
diff --git a/core/embed/rust-staticlib/src/lib.rs b/core/embed/rust-staticlib/src/lib.rs
new file mode 100644
index 00000000..cd22e6f3
--- /dev/null
+++ b/core/embed/rust-staticlib/src/lib.rs
@@ -0,0 +1,3 @@
+#![no_std]
+
+use trezor_lib as _;
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index 3644987b..2cd2bf49 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -1,5 +1,3 @@
-cargo-features = ["panic-immediate-abort"]
-
[package]
name = "trezor_lib"
version = "0.1.0"
@@ -91,104 +89,41 @@ test = [
"universal_fw",
]
universal_fw = []
+with_new_crates = ["dep:io", "dep:xbuild"]
+with_upymod = ["dep:upymod"]
[lib]
-crate-type = ["staticlib"]
-
-[profile.dev]
-# Keep panic mechanism on emulator PYOPT=0 builds
-panic = "abort"
-split-debuginfo = "off"
-debug = 2
-
-[profile.release]
-panic = "immediate-abort"
-opt-level = "z"
-lto = true
-codegen-units = 1
-split-debuginfo = "off"
-debug = 2
-
-[profile.release.package.trezor-tjpgdec]
-opt-level = 3
-
-[profile.test]
-split-debuginfo = "off"
-debug = 2
+crate-type = ["rlib"]
+doctest = false
[dependencies]
-cfg-if = { version = "1.0" }
-qrcodegen = { version = "1.8.0", path = "../../vendor/QR-Code-generator/rust-no-heap" }
-spin = { version = "0.9.8", features = ["rwlock"], default-features = false }
-trezor-tjpgdec = { version = "0.1.0", path = "../../../rust/trezor-tjpgdec" }
-ufmt = "0.2.0"
-zeroize = { version = "1.8.2", default-features = false, optional = true }
-
-# Runtime dependencies
-
-[dependencies.cty]
-version = "0.2.2"
-
-[dependencies.heapless]
-version = "0.9.2"
-features = ["ufmt"]
-default-features = false
-
-[dependencies.log]
-version = "0.4.29"
-# Disable logging for release profile.
-features = ["max_level_trace", "release_max_level_off"]
-
-[dependencies.num-traits]
-version = "0.2.19"
-default-features = false
-features = ["libm"]
-
-[dependencies.num-derive]
-version = "0.4.2"
-
-[dependencies.static-alloc]
-version = "0.2.6"
-
-[dependencies.without-alloc]
-version = "0.2.2"
-
-[dependencies.unsize]
-version = "1.1.0"
-
-[dependencies.pareen]
-version = "0.3.3"
-path = "../../../rust/pareen"
-default-features = false
-features = ["libm", "easer"]
-
-[dependencies.easer]
-version = "0.3.0"
-default-features = false
-features = ["libm"]
-
-[dependencies.minicbor]
-version = "1.0.0"
-default-features = false
-
-
-# Build dependencies
-
-[build-dependencies.bindgen]
-version = "0.72.1"
-default-features = false
-features = ["runtime"]
-
-# Build dependencies used for linking the test binary
-
-[build-dependencies.cc]
-optional = true
-version = "1.0.69"
-
-[build-dependencies.glob]
-optional = true
-version = "0.3.0"
+cfg-if.workspace = true
+cty.workspace = true
+easer.workspace = true
+heapless.workspace = true
+log.workspace = true
+minicbor.workspace = true
+num-derive.workspace = true
+num-traits.workspace = true
+pareen.workspace = true
+qrcodegen.workspace = true
+spin.workspace = true
+static-alloc.workspace = true
+trezor-tjpgdec.workspace = true
+ufmt.workspace = true
+unsize.workspace = true
+without-alloc.workspace = true
+zeroize = { workspace = true, optional = true }
+
+io = { workspace = true, optional = true }
+upymod = { workspace = true, optional = true }
+
+[build-dependencies]
+bindgen.workspace = true
+cc = { workspace = true, optional = true }
+glob = { workspace = true, optional = true }
+xbuild = { workspace = true, optional = true }
[dev-dependencies]
-hex = "0.4.3"
-serde_json = "1.0.96"
+hex.workspace = true
+serde_json.workspace = true
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 558f5641..3f9e38e4 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -1,8 +1,15 @@
-#[cfg(feature = "test")]
+#[cfg(all(feature = "test", not(feature = "with_new_crates")))]
use std::ffi::OsStr;
-use std::{env, path::PathBuf, process::Command};
+use std::{env, path::PathBuf};
+
+#[cfg(not(feature = "with_new_crates"))]
+use std::process::Command;
fn main() {
+ // hide warning: unexpected `cfg` condition name: `rust_analyzer` in ffi.rs
+ println!("cargo:rustc-check-cfg=cfg(rust_analyzer)");
+
+ #[cfg(not(feature = "with_new_crates"))]
println!("cargo:rustc-env=BUILD_DIR={}", build_dir());
#[cfg(feature = "micropython")]
generate_qstr_bindings();
@@ -11,10 +18,22 @@ fn main() {
generate_trezorhal_bindings();
#[cfg(feature = "crypto")]
generate_crypto_bindings();
- #[cfg(feature = "test")]
+ #[cfg(all(feature = "test", not(feature = "with_new_crates")))]
link_core_objects();
+
+ #[cfg(all(feature = "with_new_crates", feature = "with_upymod"))]
+ {
+ // Pass path of protobuf blobs generated by upymod build script
+ // to Rust code via environment variable.
+ // We can get rid of this once we switch to the new build system
+ // and move /rusr/protob/ to upymod or a separate crate.
+ let dir = env::var("DEP_UPYMOD_PROTOB_BLOBS_DIR")
+ .expect("DEP_UPYMOD_PROTOB_BLOBS_DIR is not set");
+ println!("cargo:rustc-env=PROTOB_BLOBS_DIR={dir}");
+ }
}
+#[cfg(not(feature = "with_new_crates"))]
fn build_dir() -> String {
let build_dir_str = env::var("BUILD_DIR").unwrap_or(String::from("../../build/unix"));
PathBuf::from(build_dir_str)
@@ -25,6 +44,7 @@ fn build_dir() -> String {
.to_string()
}
+#[cfg(not(feature = "with_new_crates"))]
const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
"-I../projects/bootloader",
"-I../projects/unix",
@@ -70,6 +90,7 @@ const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
"-DBOOTLOADER",
];
+#[cfg(not(feature = "with_new_crates"))]
fn add_bindgen_macros<'a>(
clang_args: &mut Vec<String>,
envvar: Option<&'a str>,
@@ -105,19 +126,34 @@ fn add_bindgen_macros<'a>(
/// Generates Rust module that exports QSTR constants used in firmware.
#[cfg(feature = "micropython")]
fn generate_qstr_bindings() {
- let out_path = env::var("OUT_DIR").unwrap();
+ let out_dir = env::var("OUT_DIR").unwrap();
// Tell cargo to invalidate the built crate whenever the header changes.
println!("cargo:rerun-if-changed=qstr.h");
- let dest_file = PathBuf::from(out_path).join("qstr.rs");
+ let dest_file = PathBuf::from(out_dir).join("qstr.rs");
+ #[cfg(feature = "with_new_crates")]
+ prepare_bindings()
+ .header("qstr.h")
+ // Build the Qstr enum as a newtype so we can define method on it.
+ .default_enum_style(bindgen::EnumVariation::NewType {
+ is_bitfield: false,
+ is_global: false,
+ })
+ .generate()
+ .expect("Unable to generate Rust QSTR bindings")
+ .write_to_file(&dest_file)
+ .unwrap();
+
+ #[cfg(not(feature = "with_new_crates"))]
let enum_size = if is_firmware() {
"-fshort-enums"
} else {
"-fno-short-enums"
};
+ #[cfg(not(feature = "with_new_crates"))]
bindgen::Builder::default()
.header("qstr.h")
// Build the Qstr enum as a newtype so we can define method on it.
@@ -154,6 +190,7 @@ fn generate_qstr_bindings() {
std::fs::write(&dest_file, qstr_modified).unwrap();
}
+#[cfg(not(feature = "with_new_crates"))]
fn prepare_bindings() -> bindgen::Builder {
let mut bindings = bindgen::Builder::default();
@@ -220,9 +257,55 @@ fn prepare_bindings() -> bindgen::Builder {
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
}
+#[cfg(feature = "with_new_crates")]
+fn prepare_bindings() -> bindgen::Builder {
+ let mut attrs = xbuild::CompileAttrs::new();
+
+ if is_firmware() {
+ attrs
+ .import_cc_compiler_includes()
+ .expect("Failed to import C compiler includes");
+ }
+
+ attrs
+ .import_library_metadata("io")
+ .expect("Failed to import library metadata for io");
+
+ if cfg!(feature = "micropython") {
+ attrs
+ .import_library_metadata("upymod")
+ .expect("Failed to import library metadata for upymod");
+ }
+
+ if cfg!(feature = "bootloader") {
+ // Cyclic dependency between bootloader and trezor_lib
+ attrs.add_include("../projects/bootloader");
+ }
+
+ // bindgen uses clang to parse headers, while GCC compiles the C code.
+ // Remove GCC-only flags that make clang fail.
+ attrs.remove_flag("-mcmse");
+ attrs.remove_flag("-fsingle-precision-constant");
+
+ let bindings = bindgen::Builder::default();
+
+ bindings
+ .clang_args(attrs.to_compiler_args())
+ // Customize the standard types.
+ .use_core()
+ .ctypes_prefix("cty")
+ .size_t_is_usize(true)
+ // Disable the layout tests. They spew out a lot of code-style bindings, and are not too
+ // relevant for our use-case.
+ .layout_tests(false)
+ // Tell cargo to invalidate the built crate whenever any of the
+ // included header files change.
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
+}
+
#[cfg(feature = "micropython")]
fn generate_micropython_bindings() {
- let out_path = env::var("OUT_DIR").unwrap();
+ let out_dir = env::var("OUT_DIR").unwrap();
// Tell cargo to invalidate the built crate whenever the header changes.
println!("cargo:rerun-if-changed=micropython.h");
@@ -328,12 +411,12 @@ fn generate_micropython_bindings() {
bindings
.generate()
.expect("Unable to generate bindings")
- .write_to_file(PathBuf::from(out_path).join("micropython.rs"))
+ .write_to_file(PathBuf::from(out_dir).join("micropython.rs"))
.unwrap();
}
fn generate_trezorhal_bindings() {
- let out_path = env::var("OUT_DIR").unwrap();
+ let out_dir = env::var("OUT_DIR").unwrap();
// Tell cargo to invalidate the built crate whenever the header changes.
println!("cargo:rerun-if-changed=trezorhal.h");
@@ -525,13 +608,13 @@ fn generate_trezorhal_bindings() {
bindings
.generate()
.expect("Unable to generate bindings")
- .write_to_file(PathBuf::from(out_path).join("trezorhal.rs"))
+ .write_to_file(PathBuf::from(out_dir).join("trezorhal.rs"))
.unwrap();
}
#[cfg(feature = "crypto")]
fn generate_crypto_bindings() {
- let out_path = env::var("OUT_DIR").unwrap();
+ let out_dir = env::var("OUT_DIR").unwrap();
// Tell cargo to invalidate the built crate whenever the header changes.
println!("cargo:rerun-if-changed=crypto.h");
@@ -583,7 +666,7 @@ fn generate_crypto_bindings() {
.clang_arg("-Wno-unused-function") // mode_hdr.h has static inline functions unused at parse time
.generate()
.expect("Unable to generate bindings")
- .write_to_file(PathBuf::from(out_path).join("crypto.rs"))
+ .write_to_file(PathBuf::from(out_dir).join("crypto.rs"))
.unwrap();
}
@@ -592,7 +675,7 @@ fn is_firmware() -> bool {
target.starts_with("thumbv7") || target.starts_with("thumbv8")
}
-#[cfg(feature = "test")]
+#[cfg(all(feature = "test", not(feature = "with_new_crates")))]
fn link_core_objects() {
let crate_path = env::var("CARGO_MANIFEST_DIR").unwrap();
let build_path = format!("{}/../../build/unix", crate_path);
diff --git a/core/embed/rust/src/protobuf/defs.rs b/core/embed/rust/src/protobuf/defs.rs
index 6ffbc852..8c484751 100644
--- a/core/embed/rust/src/protobuf/defs.rs
+++ b/core/embed/rust/src/protobuf/defs.rs
@@ -2,12 +2,20 @@ use core::mem;
use crate::align::include_aligned;
+#[cfg(not(feature = "with_upymod"))]
macro_rules! proto_def_path {
($filename:expr) => {
concat!(env!("BUILD_DIR"), "/rust/", $filename)
};
}
+#[cfg(feature = "with_upymod")]
+macro_rules! proto_def_path {
+ ($filename:expr) => {
+ concat!(env!("PROTOB_BLOBS_DIR"), "/", $filename)
+ };
+}
+
static ENUM_DEFS: &[u8] = include_aligned!(u16, proto_def_path!("proto_enums.data"));
static MSG_DEFS: &[u8] = include_aligned!(u16, proto_def_path!("proto_msgs.data"));
static NAME_DEFS: &[u8] = include_aligned!(NameDef, proto_def_path!("proto_names.data"));
diff --git a/core/embed/sec/Cargo.toml b/core/embed/sec/Cargo.toml
new file mode 100644
index 00000000..e5874a96
--- /dev/null
+++ b/core/embed/sec/Cargo.toml
@@ -0,0 +1,95 @@
+[package]
+name = "sec"
+version = "0.0.0"
+edition = "2024"
+links = "sec"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+sys.workspace = true
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = ["sys/model_d001"]
+model_d002 = ["sys/model_d002"]
+model_t2t1 = ["sys/model_t2t1"]
+model_t2b1 = ["sys/model_t2b1"]
+model_t3b1 = ["sys/model_t3b1"]
+model_t3t1 = ["sys/model_t3t1"]
+model_t3w1 = ["sys/model_t3w1"]
+
+# --------------------------------------------------------------------------
+# MCU features
+# --------------------------------------------------------------------------
+
+mcu_stm32f427 = ["sys/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["sys/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32u58 = ["sys/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["sys/mcu_stm32u5g", "mcu_stm32u5"]
+
+# --------------------------------------------------------------------------
+# Privilege mode features
+# --------------------------------------------------------------------------
+
+kernel_mode = ["sys/kernel_mode"]
+secure_mode = ["sys/secure_mode"]
+
+# --------------------------------------------------------------------------
+# Selectable components
+# --------------------------------------------------------------------------
+
+backup_ram = []
+bootloader_devel = []
+boot_ucb = ["sys/boot_ucb", "rtl/sphincsplus"]
+consumption_mask = []
+emulator = ["sys/emulator"]
+hash_processor = []
+hw_revision = []
+iwdg = []
+lockable_bootloader = ["sys/lockable_bootloader"]
+mcu_attestation = ["rtl/mldsa"]
+nrf_auth = []
+optiga = ["sys/i2c_bus", "time_estimate"]
+optiga_testing = []
+production = ["sys/production"]
+rdi = []
+secmon_verification = []
+secret = []
+secure_aes = []
+storage = ["time_estimate"]
+storage_hw_key = ["sys/storage_hw_key"]
+storage_insecure_testing_mode = []
+suspend = []
+tamper = []
+telemetry = ["backup_ram"]
+time_estimate = []
+tropic = []
+trustzone = ["sys/trustzone"]
+
+test = [
+ "mcu_stm32u5g",
+ "model_t3w1",
+ "emulator",
+ "kernel_mode",
+ "secure_mode",
+ "secret",
+]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+mcu_stm32u5 = ["mcu_stm32"]
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32 = []
+
+
diff --git a/core/embed/sec/backup_ram/build.rs b/core/embed/sec/backup_ram/build.rs
new file mode 100644
index 00000000..3ae4533f
--- /dev/null
+++ b/core/embed/sec/backup_ram/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("backup_ram/inc");
+
+ lib.add_define("USE_BACKUP_RAM", Some("1"));
+
+ lib.add_source("backup_ram/backup_ram_crc.c");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("backup_ram/unix/backup_ram.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("backup_ram/stm32u5/backup_ram.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/board_capabilities/build.rs b/core/embed/sec/board_capabilities/build.rs
new file mode 100644
index 00000000..30f021b4
--- /dev/null
+++ b/core/embed/sec/board_capabilities/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("board_capabilities/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("board_capabilities/unix/board_capabilities.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("board_capabilities/stm32/board_capabilities.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/build.rs b/core/embed/sec/build.rs
new file mode 100644
index 00000000..1505f88b
--- /dev/null
+++ b/core/embed/sec/build.rs
@@ -0,0 +1,107 @@
+use xbuild::{Result, build_mods};
+
+#[path = "backup_ram/build.rs"]
+mod backup_ram;
+#[path = "board_capabilities/build.rs"]
+mod board_capabilities;
+#[path = "consumption_mask/build.rs"]
+mod consumption_mask;
+#[path = "fwutils/build.rs"]
+mod fwutils;
+#[path = "hash_processor/build.rs"]
+mod hash_processor;
+#[path = "hw_revision/build.rs"]
+mod hw_revision;
+#[path = "image/build.rs"]
+mod image;
+#[path = "iwdg/build.rs"]
+mod iwdg;
+#[path = "mcu_attestation/build.rs"]
+mod mcu_attestation;
+#[path = "monoctr/build.rs"]
+mod monoctr;
+#[path = "optiga/build.rs"]
+mod optiga;
+#[path = "option_bytes/build.rs"]
+mod option_bytes;
+#[path = "random_delays/build.rs"]
+mod random_delays;
+#[path = "rng/build.rs"]
+mod rng;
+#[path = "rsod/build.rs"]
+mod rsod;
+#[path = "secret/build.rs"]
+mod secret;
+#[path = "secret_keys/build.rs"]
+mod secret_keys;
+#[path = "secure_aes/build.rs"]
+mod secure_aes;
+#[path = "storage/build.rs"]
+mod storage;
+#[path = "suspend/build.rs"]
+mod suspend;
+#[path = "tamper/build.rs"]
+mod tamper;
+#[path = "telemetry/build.rs"]
+mod telemetry;
+#[path = "time_estimate/build.rs"]
+mod time_estimate;
+#[path = "tropic/build.rs"]
+mod tropic;
+#[path = "trustzone/build.rs"]
+mod trustzone;
+#[path = "unit_properties/build.rs"]
+mod unit_properties;
+
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ lib.import_lib("sys")?;
+
+ build_mods!(
+ lib,
+ [
+ backup_ram if cfg!(feature = "backup_ram"),
+ board_capabilities,
+ consumption_mask if cfg!(feature = "consumption_mask"),
+ fwutils,
+ hash_processor if cfg!(feature = "hash_processor"),
+ hw_revision if cfg!(feature = "hw_revision"),
+ mcu_attestation if cfg!(feature = "mcu_attestation"),
+ monoctr,
+ option_bytes,
+ image,
+ iwdg if cfg!(feature = "iwdg"),
+ optiga if cfg!(feature = "optiga"),
+ random_delays,
+ rng,
+ rsod,
+ secret if cfg!(feature = "secret"),
+ secret_keys,
+ secure_aes if cfg!(feature = "secure_aes"),
+ storage if cfg!(feature = "storage"),
+ suspend if cfg!(feature = "suspend"),
+ tamper if cfg!(feature = "tamper"),
+ telemetry if cfg!(feature = "telemetry"),
+ time_estimate if cfg!(feature = "time_estimate"),
+ tropic if cfg!(feature = "tropic"),
+ trustzone if cfg!(feature = "trustzone"),
+ unit_properties,
+ ]
+ );
+
+ if cfg!(feature = "bootloader_devel") {
+ lib.add_define("BOOTLOADER_DEVEL", Some("1"));
+ }
+
+ if cfg!(not(feature = "emulator")) && cfg!(not(feature = "secure_mode")) {
+ // Linking sec layer in non-secure mode
+ lib.add_source("../sys/smcall/stm32/smcall_stubs.c");
+ }
+
+ if cfg!(feature = "test") {
+ lib.add_source("src/test_setup.c");
+ }
+
+ Ok(())
+ })
+}
diff --git a/core/embed/sec/consumption_mask/build.rs b/core/embed/sec/consumption_mask/build.rs
new file mode 100644
index 00000000..406a1ec0
--- /dev/null
+++ b/core/embed/sec/consumption_mask/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("consumption_mask/inc");
+
+ lib.add_define("USE_CONSUMPTION_MASK", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("consumption_mask/unix/consumption_mask.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("consumption_mask/stm32u5/consumption_mask.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("consumption_mask/stm32f4/consumption_mask.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/fwutils/build.rs b/core/embed/sec/fwutils/build.rs
new file mode 100644
index 00000000..0f1141ef
--- /dev/null
+++ b/core/embed/sec/fwutils/build.rs
@@ -0,0 +1,9 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("fwutils/inc");
+
+ lib.add_source("fwutils/fwutils.c");
+
+ Ok(())
+}
diff --git a/core/embed/sec/hash_processor/build.rs b/core/embed/sec/hash_processor/build.rs
new file mode 100644
index 00000000..4edd5b48
--- /dev/null
+++ b/core/embed/sec/hash_processor/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_include("hash_processor/inc");
+ lib.add_define("USE_HASH_PROCESSOR", Some("1"));
+ lib.add_source("hash_processor/stm32u5/hash_processor.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/hw_revision/build.rs b/core/embed/sec/hw_revision/build.rs
new file mode 100644
index 00000000..e9c3009d
--- /dev/null
+++ b/core/embed/sec/hw_revision/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("hw_revision/inc");
+
+ lib.add_define("USE_HW_REVISION", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("hw_revision/unix/hw_revision.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("hw_revision/stm32/hw_revision.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/image/build.rs b/core/embed/sec/image/build.rs
new file mode 100644
index 00000000..6244a5b6
--- /dev/null
+++ b/core/embed/sec/image/build.rs
@@ -0,0 +1,25 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("image/inc");
+
+ if cfg!(feature = "secmon_verification") {
+ lib.add_define("USE_SECMON_VERIFICATION", Some("1"));
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("image/unix/boot_ucb.c")
+ } else if cfg!(feature = "mcu_stm32") {
+ if cfg!(feature = "boot_ucb") {
+ lib.add_sources(["image/stm32/boot_header.c", "image/stm32/boot_ucb.c"]);
+ // USE_BOOT_UCB symbol is already define in sys layer
+ }
+ lib.add_sources(["image/stm32/boot_image.c"]);
+ } else {
+ bail_unsupported!();
+ }
+
+ lib.add_sources(["image/image.c"]);
+
+ Ok(())
+}
diff --git a/core/embed/sec/image/image.c b/core/embed/sec/image/image.c
index a5159dd0..a8995579 100644
--- a/core/embed/sec/image/image.c
+++ b/core/embed/sec/image/image.c
@@ -75,6 +75,17 @@ static const uint8_t * const SECMON_KEYS[] = {
};
#endif
+static int popcount(uint32_t value) {
+ int count = 0;
+ while (value != 0) {
+ if ((value & 1) != 0) {
+ count++;
+ }
+ value >>= 1;
+ }
+ return count;
+}
+
static secbool compute_pubkey(uint8_t sig_m, uint8_t sig_n,
const uint8_t *const *pub, uint8_t sigmask,
ed25519_public_key res) {
@@ -85,7 +96,7 @@ static secbool compute_pubkey(uint8_t sig_m, uint8_t sig_n,
sigmask &= ((1 << sig_n) - 1);
// remove if number of set bits in sigmask is not equal to sig_m
- if (__builtin_popcount(sigmask) != sig_m) return secfalse;
+ if (popcount(sigmask) != sig_m) return secfalse;
ed25519_public_key keys[sig_m];
int j = 0;
diff --git a/core/embed/sec/iwdg/build.rs b/core/embed/sec/iwdg/build.rs
new file mode 100644
index 00000000..2087a0aa
--- /dev/null
+++ b/core/embed/sec/iwdg/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("iwdg/inc");
+
+ lib.add_define("USE_IWDG", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("iwdg/unix/iwdg.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("iwdg/stm32/iwdg.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/mcu_attestation/build.rs b/core/embed/sec/mcu_attestation/build.rs
new file mode 100644
index 00000000..9c05e650
--- /dev/null
+++ b/core/embed/sec/mcu_attestation/build.rs
@@ -0,0 +1,11 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("mcu_attestation/inc");
+
+ lib.add_define("USE_MCU_ATTESTATION", Some("1"));
+
+ lib.add_source("mcu_attestation/mcu_attestation.c");
+
+ Ok(())
+}
diff --git a/core/embed/sec/monoctr/build.rs b/core/embed/sec/monoctr/build.rs
new file mode 100644
index 00000000..333bf255
--- /dev/null
+++ b/core/embed/sec/monoctr/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("monoctr/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("monoctr/unix/monoctr.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("monoctr/stm32u5/monoctr.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("monoctr/stm32f4/monoctr.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/optiga/build.rs b/core/embed/sec/optiga/build.rs
new file mode 100644
index 00000000..101c00fc
--- /dev/null
+++ b/core/embed/sec/optiga/build.rs
@@ -0,0 +1,33 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("optiga/inc");
+
+ lib.add_define("USE_OPTIGA", Some("1"));
+
+ if cfg!(feature = "optiga_testing") {
+ lib.add_define("USE_OPTIGA_TESTING", Some("1"));
+ }
+
+ lib.add_sources(["optiga/optiga_init.c"]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources([
+ "optiga/unix/optiga_commands.c",
+ "optiga/unix/optiga_hal.c",
+ "optiga/unix/optiga_transport.c",
+ "optiga/unix/optiga.c",
+ ]);
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_sources([
+ "optiga/optiga_commands.c",
+ "optiga/optiga_transport.c",
+ "optiga/optiga.c",
+ "optiga/stm32/optiga_hal.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/option_bytes/build.rs b/core/embed/sec/option_bytes/build.rs
new file mode 100644
index 00000000..dd23304b
--- /dev/null
+++ b/core/embed/sec/option_bytes/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("option_bytes/inc");
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("option_bytes/stm32u5/option_bytes.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("option_bytes/stm32f4/option_bytes.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/random_delays/build.rs b/core/embed/sec/random_delays/build.rs
new file mode 100644
index 00000000..934926f8
--- /dev/null
+++ b/core/embed/sec/random_delays/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("random_delays/inc");
+
+ if cfg!(feature = "rdi") {
+ lib.add_define("RDI", Some("1"));
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("random_delays/unix/random_delays.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("random_delays/stm32/random_delays.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/rng/build.rs b/core/embed/sec/rng/build.rs
new file mode 100644
index 00000000..a46d42c3
--- /dev/null
+++ b/core/embed/sec/rng/build.rs
@@ -0,0 +1,9 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("rng/inc");
+
+ lib.add_source("rng/rng_strong.c");
+
+ Ok(())
+}
diff --git a/core/embed/sec/rsod/build.rs b/core/embed/sec/rsod/build.rs
new file mode 100644
index 00000000..647c264a
--- /dev/null
+++ b/core/embed/sec/rsod/build.rs
@@ -0,0 +1,9 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("rsod/inc");
+
+ lib.add_source("rsod/rsod_special.c");
+
+ Ok(())
+}
diff --git a/core/embed/sec/secret/build.rs b/core/embed/sec/secret/build.rs
new file mode 100644
index 00000000..5c9a1655
--- /dev/null
+++ b/core/embed/sec/secret/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("secret/inc");
+
+ lib.add_define("USE_SECRET", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("secret/unix/secret.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("secret/stm32u5/secret.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("secret/stm32f4/secret.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/secret_keys/build.rs b/core/embed/sec/secret_keys/build.rs
new file mode 100644
index 00000000..ed80ac53
--- /dev/null
+++ b/core/embed/sec/secret_keys/build.rs
@@ -0,0 +1,25 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("secret_keys/inc");
+
+ lib.add_define("USE_SECRET_KEYS", Some("1"));
+
+ lib.add_source("secret_keys/secret_keys_common.c");
+
+ if cfg!(feature = "nrf_auth") {
+ lib.add_define("USE_NRF_AUTH", Some("1"));
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("secret_keys/unix/secret_keys.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("secret_keys/stm32f4/secret_keys.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("secret_keys/stm32u5/secret_keys.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/secure_aes/build.rs b/core/embed/sec/secure_aes/build.rs
new file mode 100644
index 00000000..75706c51
--- /dev/null
+++ b/core/embed/sec/secure_aes/build.rs
@@ -0,0 +1,16 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("secure_aes/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("secure_aes/unix/secure_aes.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("secure_aes/stm32u5/secure_aes.c");
+ lib.add_source("secure_aes/stm32u5/secure_aes_unpriv.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/src/lib.rs b/core/embed/sec/src/lib.rs
new file mode 100644
index 00000000..98bc18a2
--- /dev/null
+++ b/core/embed/sec/src/lib.rs
@@ -0,0 +1,24 @@
+#![cfg_attr(not(test), no_std)]
+#![no_main]
+#![feature(custom_test_frameworks)]
+#![reexport_test_harness_main = "test_main"]
+
+#[cfg(test)]
+#[unsafe(no_mangle)]
+pub fn main() -> i32 {
+ unsafe extern "C" {
+ safe fn rust_tests_c_setup();
+ }
+
+ // Initialize the C part of the library before running any tests
+ rust_tests_c_setup();
+
+ // Call the Rust test harness main function
+ // The function panics if any test fails.
+ // Asserting that it returns () to ensure that if a future Rust version
+ // changes the signature and behavior, we'll be notified.
+ assert_eq!(test_main(), ());
+
+ // Return 0 to indicate success
+ 0
+}
diff --git a/core/embed/sec/src/test_setup.c b/core/embed/sec/src/test_setup.c
new file mode 100644
index 00000000..708908ec
--- /dev/null
+++ b/core/embed/sec/src/test_setup.c
@@ -0,0 +1,26 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+// Provide definitions of the system exit functions so that they can be
+// called without linking the sys crate. This is needed when compiling the
+// tests for the crates that don't depend on sys, such as the crypto crate.
+
+#include <sys/system.h>
+
+void rust_tests_c_setup(void) { system_init(NULL); }
diff --git a/core/embed/sec/storage/build.rs b/core/embed/sec/storage/build.rs
new file mode 100644
index 00000000..3402a446
--- /dev/null
+++ b/core/embed/sec/storage/build.rs
@@ -0,0 +1,40 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("storage/inc");
+
+ lib.add_define("USE_STORAGE", Some("1"));
+
+ if cfg!(not(feature = "secure_mode")) {
+ // TODO: refactor to avoid this hack
+ // Storage source code doe not contain #ifdef SECURE_MODE,
+ // so we need to exclude it entirely in non-secure mode
+ return Ok(());
+ }
+
+ if cfg!(feature = "storage_insecure_testing_mode") {
+ lib.add_define("STORAGE_INSECURE_TESTING_MODE", Some("1"));
+ }
+
+ lib.add_source("storage/storage_setup.c");
+
+ lib.add_sources_in_dir(
+ "../../vendor/trezor-storage/",
+ ["norcow.c", "storage.c", "storage_utils.c"],
+ );
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("storage/unix/storage_salt.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("storage/stm32f4/storage_salt.c");
+ if cfg!(feature = "storage_hw_key") {
+ bail_unsupported!();
+ }
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("storage/stm32u5/storage_salt.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/suspend/build.rs b/core/embed/sec/suspend/build.rs
new file mode 100644
index 00000000..d3e3570f
--- /dev/null
+++ b/core/embed/sec/suspend/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("suspend/inc");
+
+ lib.add_define("USE_SUSPEND", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("suspend/stm32u5/suspend_io.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/tamper/build.rs b/core/embed/sec/tamper/build.rs
new file mode 100644
index 00000000..4a43a289
--- /dev/null
+++ b/core/embed/sec/tamper/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("tamper/inc");
+
+ lib.add_define("USE_TAMPER", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("tamper/unix/tamper.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("tamper/stm32u5/tamper.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/telemetry/build.rs b/core/embed/sec/telemetry/build.rs
new file mode 100644
index 00000000..b033c0a8
--- /dev/null
+++ b/core/embed/sec/telemetry/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("telemetry/inc");
+
+ lib.add_define("USE_TELEMETRY", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("telemetry/unix/telemetry.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("telemetry/stm32u5/telemetry.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/time_estimate/build.rs b/core/embed/sec/time_estimate/build.rs
new file mode 100644
index 00000000..85ff0300
--- /dev/null
+++ b/core/embed/sec/time_estimate/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("time_estimate/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("time_estimate/unix/time_estimate.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("time_estimate/stm32/time_estimate.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/tropic/build.rs b/core/embed/sec/tropic/build.rs
new file mode 100644
index 00000000..f7ee9be0
--- /dev/null
+++ b/core/embed/sec/tropic/build.rs
@@ -0,0 +1,62 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+use std::path::PathBuf;
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("tropic/inc");
+
+ lib.add_define("USE_TROPIC", Some("1"));
+
+ let tropic_dir = PathBuf::from("../../vendor/libtropic");
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources(["tropic/unix/tropic01.c"]);
+
+ lib.add_sources_in_dir(&tropic_dir, ["hal/posix/tcp/libtropic_port_posix_tcp.c"]);
+
+ lib.add_define("ABAB", Some("1"));
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources(["tropic/stm32/tropic01.c"]);
+
+ lib.add_define("ACAB", Some("1"));
+ } else {
+ bail_unsupported!();
+ }
+
+ lib.add_sources(["tropic/tropic.c"]);
+
+ lib.add_sources_in_dir(
+ &tropic_dir,
+ [
+ "cal/trezor_crypto/lt_trezor_crypto_aesgcm.c",
+ "cal/trezor_crypto/lt_trezor_crypto_common.c",
+ "cal/trezor_crypto/lt_trezor_crypto_hmac_sha256.c",
+ "cal/trezor_crypto/lt_trezor_crypto_sha256.c",
+ "cal/trezor_crypto/lt_trezor_crypto_x25519.c",
+ "src/libtropic.c",
+ "src/libtropic_l2.c",
+ "src/libtropic_l3.c",
+ "src/lt_asn1_der.c",
+ "src/lt_crc16.c",
+ "src/lt_hkdf.c",
+ "src/lt_l1.c",
+ "src/lt_l2_frame_check.c",
+ "src/lt_l3_process.c",
+ "src/lt_port_wrap.c",
+ "src/lt_tr01_attrs.c",
+ ],
+ );
+
+ lib.add_includes([
+ tropic_dir.join("include"),
+ tropic_dir.join("src"),
+ tropic_dir.join("TROPIC01_fw_update_files/boot_v_2_0_1/fw_v_1_0_0"),
+ ]);
+
+ lib.add_defines([
+ ("LT_USE_TREZOR_CRYPTO", Some("1")),
+ ("LT_HELPERS", Some("1")),
+ ]);
+
+ Ok(())
+}
diff --git a/core/embed/sec/trustzone/build.rs b/core/embed/sec/trustzone/build.rs
new file mode 100644
index 00000000..40ed513f
--- /dev/null
+++ b/core/embed/sec/trustzone/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("trustzone/inc");
+
+ // USE_TRUSTZONE is defined in sys layer
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("trustzone/unix/tz_init.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("trustzone/stm32u5/tz_init.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sec/unit_properties/build.rs b/core/embed/sec/unit_properties/build.rs
new file mode 100644
index 00000000..90cbd7ab
--- /dev/null
+++ b/core/embed/sec/unit_properties/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("unit_properties/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("unit_properties/unix/unit_properties.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("unit_properties/stm32/unit_properties.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/Cargo.toml b/core/embed/sys/Cargo.toml
new file mode 100644
index 00000000..5da54bdd
--- /dev/null
+++ b/core/embed/sys/Cargo.toml
@@ -0,0 +1,84 @@
+[package]
+name = "sys"
+version = "0.0.0"
+edition = "2024"
+links = "sys"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+rtl.workspace = true
+models.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = ["rtl/model_d001"]
+model_d002 = ["rtl/model_d002"]
+model_t2t1 = ["rtl/model_t2t1"]
+model_t2b1 = ["rtl/model_t2b1"]
+model_t3b1 = ["rtl/model_t3b1"]
+model_t3t1 = ["rtl/model_t3t1"]
+model_t3w1 = ["rtl/model_t3w1"]
+
+# --------------------------------------------------------------------------
+# MCU features
+# --------------------------------------------------------------------------
+
+mcu_stm32f427 = ["rtl/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["rtl/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32u58 = ["rtl/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["rtl/mcu_stm32u5g", "mcu_stm32u5"]
+
+# --------------------------------------------------------------------------
+# Privilege mode features
+# --------------------------------------------------------------------------
+
+kernel_mode = ["rtl/kernel_mode"]
+secure_mode = ["rtl/secure_mode"]
+
+# --------------------------------------------------------------------------
+# Selectable components
+# --------------------------------------------------------------------------
+
+applets = []
+app_loading = ["applets"]
+block_on_vcp = []
+boot_ucb = []
+emulator = ["rtl/emulator"]
+i2c_bus = []
+ipc = []
+lockable_bootloader = []
+pvd = []
+rtc = []
+trustzone = []
+dbg_console = []
+dbg_console_swo = ["dbg_console"]
+dbg_console_vcp = ["dbg_console"]
+dbg_console_system_view = ["dbg_console", "system_view"]
+sdram = []
+storage_hw_key = []
+system_view = []
+production = ["rtl/production"]
+
+test = [
+ "mcu_stm32u5g",
+ "model_t3w1",
+ "emulator",
+ "kernel_mode",
+ "secure_mode",
+]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32u5 = ["mcu_stm32"]
+mcu_stm32 = []
+
diff --git a/core/embed/sys/bsp/build.rs b/core/embed/sys/bsp/build.rs
new file mode 100644
index 00000000..81bdea20
--- /dev/null
+++ b/core/embed/sys/bsp/build.rs
@@ -0,0 +1,155 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("bsp/inc");
+
+ if cfg!(feature = "emulator") {
+ add_emulator_bsp(lib)?;
+ } else if cfg!(feature = "mcu_stm32u5") {
+ add_stm32u5_bsp(lib)?;
+ } else if cfg!(feature = "mcu_stm32f4") {
+ add_stm32f4_bsp(lib)?;
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
+
+fn add_stm32u5_bsp(lib: &mut CLibrary) -> Result<()> {
+ if cfg!(feature = "mcu_stm32u5g") {
+ lib.add_define("STM32U5G9xx", None);
+ } else if cfg!(feature = "mcu_stm32u58") {
+ lib.add_define("STM32U585xx", None);
+ } else {
+ bail_unsupported!();
+ }
+
+ lib.add_defines([
+ ("STM32_HAL_H", Some("<stm32u5xx.h>")),
+ ("USE_HAL_DRIVER", None),
+ ]);
+
+ lib.add_includes([
+ "../../vendor/cmsis_5/CMSIS/Core/Include",
+ "../../vendor/cmsis_device_u5/Include",
+ "../../vendor/stm32u5xx_hal_driver/Inc",
+ "bsp/stm32u5",
+ ]);
+
+ lib.add_sources_in_dir(
+ "../../vendor/stm32u5xx_hal_driver/Src/",
+ [
+ "stm32u5xx_hal.c",
+ "stm32u5xx_hal_cortex.c",
+ "stm32u5xx_hal_cryp.c",
+ "stm32u5xx_hal_dma2d.c",
+ "stm32u5xx_hal_dma.c",
+ "stm32u5xx_hal_dma_ex.c",
+ "stm32u5xx_hal_dsi.c",
+ "stm32u5xx_hal_exti.c",
+ "stm32u5xx_hal_flash.c",
+ "stm32u5xx_hal_flash_ex.c",
+ "stm32u5xx_hal_gfxmmu.c",
+ "stm32u5xx_hal_gpio.c",
+ "stm32u5xx_hal_gtzc.c",
+ "stm32u5xx_hal_hash.c",
+ "stm32u5xx_hal_hash_ex.c",
+ "stm32u5xx_hal_i2c.c",
+ "stm32u5xx_hal_i2c_ex.c",
+ "stm32u5xx_hal_icache.c",
+ "stm32u5xx_hal_iwdg.c",
+ "stm32u5xx_hal_lptim.c",
+ "stm32u5xx_hal_ltdc.c",
+ "stm32u5xx_hal_ltdc_ex.c",
+ "stm32u5xx_hal_pcd.c",
+ "stm32u5xx_hal_pcd_ex.c",
+ "stm32u5xx_hal_pwr.c",
+ "stm32u5xx_hal_pwr_ex.c",
+ "stm32u5xx_hal_ramcfg.c",
+ "stm32u5xx_hal_rtc.c",
+ "stm32u5xx_hal_rtc_ex.c",
+ "stm32u5xx_hal_sd.c",
+ "stm32u5xx_hal_spi.c",
+ "stm32u5xx_hal_sram.c",
+ "stm32u5xx_hal_tim.c",
+ "stm32u5xx_hal_tim_ex.c",
+ "stm32u5xx_hal_uart.c",
+ "stm32u5xx_hal_uart_ex.c",
+ "stm32u5xx_ll_fmc.c",
+ "stm32u5xx_ll_usb.c",
+ "stm32u5xx_ll_sdmmc.c",
+ ],
+ );
+
+ if cfg!(feature = "secure_mode") {
+ lib.add_sources_in_dir(
+ "../../vendor/stm32u5xx_hal_driver/Src/",
+ ["stm32u5xx_hal_rcc.c", "stm32u5xx_hal_rcc_ex.c"],
+ );
+ }
+
+ Ok(())
+}
+
+fn add_stm32f4_bsp(lib: &mut CLibrary) -> Result<()> {
+ if cfg!(feature = "mcu_stm32f427") {
+ lib.add_define("STM32F427xx", None);
+ } else if cfg!(feature = "mcu_stm32f429") {
+ lib.add_define("STM32F429xx", None);
+ } else {
+ bail_unsupported!();
+ }
+
+ lib.add_defines([
+ ("STM32_HAL_H", Some("<stm32f4xx.h>")),
+ ("USE_HAL_DRIVER", None),
+ ]);
+
+ lib.add_includes([
+ "../../vendor/micropython/lib/cmsis/inc",
+ "../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc",
+ "../../vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include",
+ "bsp/stm32f4",
+ ]);
+
+ lib.add_sources_in_dir(
+ "../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/",
+ [
+ "stm32f4xx_hal.c",
+ "stm32f4xx_hal_cortex.c",
+ "stm32f4xx_hal_dma.c",
+ "stm32f4xx_hal_dma2d.c",
+ "stm32f4xx_hal_flash.c",
+ "stm32f4xx_hal_flash_ex.c",
+ "stm32f4xx_hal_gpio.c",
+ "stm32f4xx_hal_i2c.c",
+ "stm32f4xx_hal_ltdc.c",
+ "stm32f4xx_hal_pcd.c",
+ "stm32f4xx_hal_pcd_ex.c",
+ "stm32f4xx_hal_pwr.c",
+ "stm32f4xx_hal_rcc.c",
+ "stm32f4xx_hal_rcc_ex.c",
+ "stm32f4xx_hal_sd.c",
+ "stm32f4xx_hal_spi.c",
+ "stm32f4xx_hal_sram.c",
+ "stm32f4xx_hal_sdram.c",
+ "stm32f4xx_hal_tim.c",
+ "stm32f4xx_hal_tim_ex.c",
+ "stm32f4xx_ll_fmc.c",
+ "stm32f4xx_ll_sdmmc.c",
+ "stm32f4xx_ll_usb.c",
+ ],
+ );
+
+ Ok(())
+}
+
+fn add_emulator_bsp(lib: &mut xbuild::CLibrary) -> Result<()> {
+ lib.add_source("bsp/unix/profile.c");
+
+ lib.import_external_lib("sdl3", true)?;
+ lib.import_external_lib("sdl3-image", true)?;
+
+ Ok(())
+}
diff --git a/core/embed/sys/build.rs b/core/embed/sys/build.rs
new file mode 100644
index 00000000..a60ad252
--- /dev/null
+++ b/core/embed/sys/build.rs
@@ -0,0 +1,85 @@
+use xbuild::{Result, build_mods};
+
+#[path = "bsp/build.rs"]
+mod bsp;
+#[path = "cpuid/build.rs"]
+mod cpuid;
+#[path = "dbg/build.rs"]
+mod dbg;
+#[path = "flash/build.rs"]
+mod flash;
+#[path = "i2c_bus/build.rs"]
+mod i2c_bus;
+#[path = "ipc/build.rs"]
+mod ipc;
+#[path = "irq/build.rs"]
+mod irq;
+#[path = "linker/build.rs"]
+mod linker;
+#[path = "mpu/build.rs"]
+mod mpu;
+#[path = "pvd/build.rs"]
+mod pvd;
+#[path = "rng/build.rs"]
+mod rng;
+#[path = "sdram/build.rs"]
+mod sdram;
+#[path = "stack/build.rs"]
+mod stack;
+#[path = "startup/build.rs"]
+mod startup;
+#[path = "task/build.rs"]
+mod task;
+#[path = "time/build.rs"]
+mod time;
+#[path = "trustzone/build.rs"]
+mod trustzone;
+
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ lib.import_lib("rtl")?;
+
+ lib.add_includes([
+ "syscall/inc", // temporary hack
+ "inc",
+ "../../vendor",
+ ]);
+
+ if cfg!(feature = "boot_ucb") {
+ lib.add_define("USE_BOOT_UCB", Some("1"));
+ }
+
+ if cfg!(feature = "storage_hw_key") {
+ lib.add_define("USE_STORAGE_HWKEY", Some("1"));
+ }
+
+ if cfg!(feature = "lockable_bootloader") {
+ lib.add_define("LOCKABLE_BOOTLOADER", None);
+ }
+
+ build_mods!(
+ lib,
+ [
+ bsp,
+ cpuid,
+ dbg if cfg!(feature = "dbg_console"),
+ i2c_bus if cfg!(feature = "i2c_bus"),
+ ipc if cfg!(feature = "ipc"),
+ irq,
+ flash,
+ linker if cfg!(not(feature = "emulator")),
+ mpu,
+ pvd if cfg!(feature = "pvd"),
+ rng,
+ sdram if cfg!(feature = "sdram"),
+ stack,
+ startup,
+ task,
+ time,
+ trustzone if cfg!(feature = "trustzone"),
+ ]
+ );
+
+ Ok(())
+ })
+}
diff --git a/core/embed/sys/cpuid/build.rs b/core/embed/sys/cpuid/build.rs
new file mode 100644
index 00000000..6af0f34f
--- /dev/null
+++ b/core/embed/sys/cpuid/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("cpuid/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("cpuid/unix/cpuid.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("cpuid/stm32/cpuid.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/dbg/build.rs b/core/embed/sys/dbg/build.rs
new file mode 100644
index 00000000..10f1fa07
--- /dev/null
+++ b/core/embed/sys/dbg/build.rs
@@ -0,0 +1,55 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("dbg/inc");
+
+ lib.add_define("USE_DBG_CONSOLE", Some("1"));
+
+ lib.add_sources(["dbg/dbg_console.c", "dbg/syslog.c"]);
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("dbg/unix/dbg_console_backend.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("dbg/stm32/dbg_console_backend.c");
+
+ if cfg!(feature = "block_on_vcp") {
+ lib.add_define("BLOCK_ON_VCP", None);
+ }
+
+ if cfg!(feature = "dbg_console_swo") {
+ lib.add_define("USE_DBG_CONSOLE_SWO", None);
+ }
+
+ if cfg!(feature = "dbg_console_vcp") {
+ lib.add_define("USE_DBG_CONSOLE_VCP", None);
+ }
+
+ if cfg!(feature = "dbg_console_system_view") {
+ lib.add_define("USE_DBG_CONSOLE_SYSTEM_VIEW", None);
+ }
+
+ if cfg!(feature = "system_view") {
+ def_system_view(lib);
+ }
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
+
+fn def_system_view(lib: &mut CLibrary) {
+ lib.add_define("USE_SYSTEM_VIEW", Some("1"));
+
+ lib.add_includes(["dbg/stm32/systemview/config", "dbg/stm32/systemview/segger"]);
+
+ lib.add_sources_in_dir(
+ "dbg/stm32/systemview",
+ [
+ "config/SEGGER_SYSVIEW_Config_NoOS.c",
+ "segger/SEGGER_SYSVIEW.c",
+ "segger/SEGGER_RTT.c",
+ "segger/SEGGER_RTT_ASM_ARMv7M.S",
+ ],
+ );
+}
diff --git a/core/embed/sys/dbg/stm32/dbg_console_backend.c b/core/embed/sys/dbg/stm32/dbg_console_backend.c
index 105f7917..2a6fe6d5 100644
--- a/core/embed/sys/dbg/stm32/dbg_console_backend.c
+++ b/core/embed/sys/dbg/stm32/dbg_console_backend.c
@@ -31,10 +31,6 @@
#include "SEGGER_SYSVIEW.h"
#endif
-#if defined(USE_DBG_CONSOLE_VCP) && !defined(USE_USB_IFACE_VCP)
-#error "USE_DBG_CONSOLE_VCP requires USE_USB_IFACE_VCP"
-#endif
-
#if defined(USE_DBG_CONSOLE_SYSTEM_VIEW) && !defined(USE_SYSTEM_VIEW)
#error "USE_DBG_CONSOLE_SYSTEM_VIEW requires USE_SYSTEM_VIEW"
#endif
diff --git a/core/embed/sys/flash/build.rs b/core/embed/sys/flash/build.rs
new file mode 100644
index 00000000..4d026078
--- /dev/null
+++ b/core/embed/sys/flash/build.rs
@@ -0,0 +1,60 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("flash/inc");
+
+ lib.add_source("flash/flash_utils.c");
+
+ lib.add_source("../../vendor/trezor-storage/flash_area.c");
+
+ if cfg!(feature = "mcu_stm32f4") {
+ lib.add_defines([
+ ("FLASH_BIT_ACCESS", Some("1")),
+ ("FLASH_BLOCK_WORDS", Some("1")),
+ ]);
+
+ lib.add_source("flash/stm32f4/flash_layout.c");
+
+ if cfg!(feature = "emulator") {
+ lib.add_define("STM32F427xx", None);
+ lib.add_sources(["flash/unix/flash.c", "flash/unix/flash_otp.c"]);
+ } else {
+ lib.add_sources(["flash/stm32f4/flash.c", "flash/stm32f4/flash_otp.c"]);
+ }
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("flash/stm32u5/flash_layout.c");
+
+ if cfg!(feature = "emulator") {
+ // TODO: do not use FLASH_BIT_ACCESS for emulating STM32U5
+ // (keeping it for backward compatibility with the SCons build system,
+ // but we should reconsider this in the future)
+ lib.add_defines([
+ ("FLASH_BIT_ACCESS", Some("1")),
+ ("FLASH_BLOCK_WORDS", Some("1")),
+ ]);
+
+ if cfg!(feature = "mcu_stm32u5g") {
+ lib.add_define("STM32U5G9xx", None);
+ } else if cfg!(feature = "mcu_stm32u58") {
+ lib.add_define("STM32U585xx", None);
+ } else {
+ bail_unsupported!();
+ }
+
+ lib.add_sources(["flash/unix/flash.c", "flash/unix/flash_otp.c"]);
+ } else {
+ lib.add_defines([
+ ("USE_FLASH_BURST", Some("1")),
+ ("FLASH_BURST_WORDS", Some("32")),
+ ("FLASH_BURST_SIZE", Some("128")),
+ ("FLASH_BLOCK_WORDS", Some("4")),
+ ]);
+
+ lib.add_sources(["flash/stm32u5/flash.c", "flash/stm32u5/flash_otp.c"]);
+ }
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/i2c_bus/build.rs b/core/embed/sys/i2c_bus/build.rs
new file mode 100644
index 00000000..01a1285b
--- /dev/null
+++ b/core/embed/sys/i2c_bus/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("i2c_bus/inc");
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("i2c_bus/stm32f4/i2c_bus.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("i2c_bus/stm32u5/i2c_bus.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/ipc/build.rs b/core/embed/sys/ipc/build.rs
new file mode 100644
index 00000000..2370adeb
--- /dev/null
+++ b/core/embed/sys/ipc/build.rs
@@ -0,0 +1,19 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("ipc/inc");
+
+ lib.add_define("USE_IPC", Some("1"));
+
+ lib.add_source("ipc/ipc.c");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("ipc/unix/ipc_memcpy.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("ipc/stm32u5/ipc_memcpy.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/irq/build.rs b/core/embed/sys/irq/build.rs
new file mode 100644
index 00000000..2d1b3590
--- /dev/null
+++ b/core/embed/sys/irq/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("irq/inc");
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("irq/stm32/irq.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/linker/build.rs b/core/embed/sys/linker/build.rs
new file mode 100644
index 00000000..15525415
--- /dev/null
+++ b/core/embed/sys/linker/build.rs
@@ -0,0 +1,9 @@
+use xbuild::{CLibrary, Result};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("linker/inc");
+
+ lib.add_source("linker/linker_utils.c");
+
+ Ok(())
+}
diff --git a/core/embed/sys/mpu/build.rs b/core/embed/sys/mpu/build.rs
new file mode 100644
index 00000000..1dca0a6e
--- /dev/null
+++ b/core/embed/sys/mpu/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("mpu/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("mpu/unix/mpu.c");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("mpu/stm32f4/mpu.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("mpu/stm32u5/mpu.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/pvd/build.rs b/core/embed/sys/pvd/build.rs
new file mode 100644
index 00000000..88c7ed51
--- /dev/null
+++ b/core/embed/sys/pvd/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("pvd/inc");
+
+ lib.add_define("USE_PVD", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("pvd/unix/pvd.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("pvd/stm32/pvd.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/rng/build.rs b/core/embed/sys/rng/build.rs
new file mode 100644
index 00000000..ab8f3e05
--- /dev/null
+++ b/core/embed/sys/rng/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("rng/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("rng/unix/rng.c");
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("rng/stm32/rng.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/sdram/build.rs b/core/embed/sys/sdram/build.rs
new file mode 100644
index 00000000..eefd5cff
--- /dev/null
+++ b/core/embed/sys/sdram/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("sdram/inc");
+
+ lib.add_define("USE_SDRAM", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "model_d001") {
+ lib.add_source("sdram/stm32f429i-disc1/sdram_bsp.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/src/lib.rs b/core/embed/sys/src/lib.rs
new file mode 100644
index 00000000..0c9ac1ac
--- /dev/null
+++ b/core/embed/sys/src/lib.rs
@@ -0,0 +1 @@
+#![no_std]
diff --git a/core/embed/sys/stack/build.rs b/core/embed/sys/stack/build.rs
new file mode 100644
index 00000000..48a980ac
--- /dev/null
+++ b/core/embed/sys/stack/build.rs
@@ -0,0 +1,15 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("stack/inc");
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("stack/stm32/stack_utils.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/startup/build.rs b/core/embed/sys/startup/build.rs
new file mode 100644
index 00000000..0755121e
--- /dev/null
+++ b/core/embed/sys/startup/build.rs
@@ -0,0 +1,30 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("startup/inc");
+
+ lib.add_source("startup/startup_args.c");
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("startup/unix/bootutils.c");
+ } else {
+ if cfg!(feature = "mcu_stm32") {
+ lib.add_source("startup/stm32/bootutils.c");
+ lib.add_source("startup/stm32/sysutils.c");
+ }
+
+ if cfg!(feature = "mcu_stm32u5") {
+ lib.add_source("startup/stm32u5/startup_init.c");
+ lib.add_source("startup/stm32u5/reset_flags.c");
+ lib.add_source("startup/stm32u5/vectortable.S");
+ } else if cfg!(feature = "mcu_stm32f4") {
+ lib.add_source("startup/stm32f4/startup_init.c");
+ lib.add_source("startup/stm32f4/reset_flags.c");
+ lib.add_source("startup/stm32f4/vectortable.S");
+ } else {
+ bail_unsupported!();
+ }
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/task/build.rs b/core/embed/sys/task/build.rs
new file mode 100644
index 00000000..41d43a64
--- /dev/null
+++ b/core/embed/sys/task/build.rs
@@ -0,0 +1,35 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("task/inc");
+
+ lib.add_sources(["task/system.c", "task/sysevent.c"]);
+
+ if cfg!(feature = "applets") {
+ lib.add_define("USE_APPLETS", Some("1"));
+ lib.add_source("task/applet.c");
+ }
+
+ if cfg!(feature = "app_loading") {
+ lib.add_define("USE_APP_LOADING", Some("1"));
+ }
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources([
+ "task/unix/coreapp.c",
+ "task/unix/sdl_event.c",
+ "task/unix/systask.c",
+ "task/unix/system.c",
+ ]);
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_sources([
+ "task/stm32/coreapp.c",
+ "task/stm32/systask.c",
+ "task/stm32/system.c",
+ ]);
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/time/build.rs b/core/embed/sys/time/build.rs
new file mode 100644
index 00000000..35bc9215
--- /dev/null
+++ b/core/embed/sys/time/build.rs
@@ -0,0 +1,27 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("time/inc");
+
+ if cfg!(feature = "emulator") {
+ lib.add_sources(["time/unix/systick.c", "time/unix/systimer.c"]);
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_sources(["time/stm32/systick.c", "time/stm32/systimer.c"]);
+ } else {
+ bail_unsupported!();
+ }
+
+ if cfg!(feature = "rtc") {
+ lib.add_define("USE_RTC", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ lib.add_source("time/unix/rtc.c");
+ } else if cfg!(feature = "mcu_stm32u5") {
+ lib.add_sources(["time/stm32u5/rtc_scheduler.c", "time/stm32u5/rtc.c"]);
+ } else {
+ bail_unsupported!();
+ }
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/trustzone/build.rs b/core/embed/sys/trustzone/build.rs
new file mode 100644
index 00000000..2723799c
--- /dev/null
+++ b/core/embed/sys/trustzone/build.rs
@@ -0,0 +1,17 @@
+use xbuild::{CLibrary, Result, bail_unsupported};
+
+pub fn def_module(lib: &mut CLibrary) -> Result<()> {
+ lib.add_include("trustzone/inc");
+
+ lib.add_define("USE_TRUSTZONE", Some("1"));
+
+ if cfg!(feature = "emulator") {
+ // No implementation
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_source("trustzone/stm32u5/trustzone.c");
+ } else {
+ bail_unsupported!();
+ }
+
+ Ok(())
+}
diff --git a/core/embed/sys/trustzone/stm32u5/trustzone.c b/core/embed/sys/trustzone/stm32u5/trustzone.c
index 55104827..ef8ca44d 100644
--- a/core/embed/sys/trustzone/stm32u5/trustzone.c
+++ b/core/embed/sys/trustzone/stm32u5/trustzone.c
@@ -91,8 +91,8 @@ sram_region_t g_sram_regions[] = {
void tz_set_sram_unpriv(uint32_t start, uint32_t size, bool unpriv) {
const size_t block_size = TZ_SRAM_ALIGNMENT;
- ensure(sectrue * IS_ALIGNED(start, block_size), "TZ alignment");
- ensure(sectrue * IS_ALIGNED(size, block_size), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(start, TZ_SRAM_ALIGNMENT), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(size, TZ_SRAM_ALIGNMENT), "TZ alignment");
uint32_t end = start + size;
@@ -125,8 +125,8 @@ void tz_set_sram_unpriv(uint32_t start, uint32_t size, bool unpriv) {
void tz_set_sram_unsecure(uint32_t start, uint32_t size, bool unsecure) {
const size_t block_size = TZ_SRAM_ALIGNMENT;
- ensure(sectrue * IS_ALIGNED(start, block_size), "TZ alignment");
- ensure(sectrue * IS_ALIGNED(size, block_size), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(start, TZ_SRAM_ALIGNMENT), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(size, TZ_SRAM_ALIGNMENT), "TZ alignment");
uint32_t end = start + size;
@@ -200,8 +200,8 @@ flash_region_t g_flash_regions[] = {
void tz_set_flash_unpriv(uint32_t start, uint32_t size, bool unpriv) {
const size_t block_size = TZ_FLASH_ALIGNMENT;
- ensure(sectrue * IS_ALIGNED(start, block_size), "TZ alignment");
- ensure(sectrue * IS_ALIGNED(size, block_size), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(start, TZ_FLASH_ALIGNMENT), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(size, TZ_FLASH_ALIGNMENT), "TZ alignment");
uint32_t end = start + size;
@@ -234,8 +234,8 @@ void tz_set_flash_unpriv(uint32_t start, uint32_t size, bool unpriv) {
void tz_set_flash_unsecure(uint32_t start, uint32_t size, bool unsecure) {
const size_t block_size = TZ_FLASH_ALIGNMENT;
- ensure(sectrue * IS_ALIGNED(start, block_size), "TZ alignment");
- ensure(sectrue * IS_ALIGNED(size, block_size), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(start, TZ_FLASH_ALIGNMENT), "TZ alignment");
+ ensure(sectrue * IS_ALIGNED(size, TZ_FLASH_ALIGNMENT), "TZ alignment");
uint32_t end = start + size;
diff --git a/core/embed/upymod/Cargo.toml b/core/embed/upymod/Cargo.toml
new file mode 100644
index 00000000..176e6d71
--- /dev/null
+++ b/core/embed/upymod/Cargo.toml
@@ -0,0 +1,83 @@
+[package]
+name = "upymod"
+version = "0.0.0"
+edition = "2024"
+links = "upymod"
+
+[build-dependencies]
+color-eyre.workspace = true
+xbuild.workspace = true
+
+[dependencies]
+models.workspace = true
+rtl.workspace = true
+sec.workspace = true
+io.workspace = true
+
+[features]
+
+# --------------------------------------------------------------------------
+# Model features
+# --------------------------------------------------------------------------
+
+model_d001 = ["io/model_d001"]
+model_d002 = ["io/model_d002"]
+model_t2t1 = ["io/model_t2t1"]
+model_t2b1 = ["io/model_t2b1"]
+model_t3b1 = ["io/model_t3b1"]
+model_t3t1 = ["io/model_t3t1"]
+model_t3w1 = ["io/model_t3w1"]
+
+# --------------------------------------------------------------------------
+# MCU features
+# --------------------------------------------------------------------------
+
+mcu_stm32f427 = ["io/mcu_stm32f427", "mcu_stm32f4"]
+mcu_stm32f429 = ["io/mcu_stm32f429", "mcu_stm32f4"]
+mcu_stm32u58 = ["io/mcu_stm32u58", "mcu_stm32u5"]
+mcu_stm32u5g = ["io/mcu_stm32u5g", "mcu_stm32u5"]
+
+# --------------------------------------------------------------------------
+# Selectable components
+# --------------------------------------------------------------------------
+
+app_loading = ["io/app_loading", "io/ipc"]
+backlight = ["io/backlight"]
+benchmark = []
+ble = ["io/ble"]
+button = ["io/button"]
+disable_animation = []
+enable_source_lines = []
+emulator = ["io/emulator"]
+frozen = []
+haptic = ["io/haptic"]
+layout_bolt = []
+layout_caesar = []
+layout_delizia = []
+layout_eckhart = []
+log_stack_usage = []
+mcu_attestation = ["sec/mcu_attestation"]
+memperf = []
+n4w1 = []
+optiga = ["sec/optiga"]
+power_manager = ["io/power_manager"]
+pyopt = []
+rgb_led = ["io/rgb_led"]
+serial_number = []
+sd_card = ["io/sd_card"]
+telemetry = ["sec/telemetry"]
+thp = []
+touch = ["io/touch"]
+touch_wakeup = ["io/touch_wakeup"]
+tropic = ["sec/tropic"]
+universal_fw = ["rtl/universal_fw"]
+
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
+
+default = ["sec/storage", "io/usb_iface_wire"]
+
+mcu_stm32f4 = ["mcu_stm32"]
+mcu_stm32u5 = ["mcu_stm32"]
+mcu_stm32 = []
diff --git a/core/embed/upymod/build.rs b/core/embed/upymod/build.rs
new file mode 100644
index 00000000..7cad7fa8
--- /dev/null
+++ b/core/embed/upymod/build.rs
@@ -0,0 +1,1247 @@
+use std::{
+ env,
+ fs::{self, File},
+ io::{BufRead, BufReader, Write},
+ iter::once,
+ os::unix,
+ path::{Path, PathBuf},
+};
+
+use xbuild::{CLibrary, InputFiles, Result, WrapErr, bail, bail_unsupported, ensure};
+
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ let mpy_dir = "../../vendor/micropython";
+
+ lib.import_lib("io")?;
+
+ if cfg!(feature = "emulator") {
+ // There are two mpconfigport.h files in both ports/unix and projects/unix.
+ // The first one has precedence and is used for compilation.
+ lib.add_include("../projects/unix");
+ lib.add_include(PathBuf::from(mpy_dir).join("ports/unix"));
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_include("../projects/firmware");
+ } else {
+ bail_unsupported!();
+ }
+
+ lib.add_include(mpy_dir);
+
+ if cfg!(feature = "universal_fw") {
+ lib.add_define("BITCOIN_ONLY", Some("0"));
+ } else {
+ lib.add_define("BITCOIN_ONLY", Some("1"));
+ }
+
+ if cfg!(feature = "layout_bolt") {
+ lib.add_define("UI_LAYOUT_BOLT", None);
+ } else if cfg!(feature = "layout_caesar") {
+ lib.add_define("UI_LAYOUT_CAESAR", None);
+ } else if cfg!(feature = "layout_delizia") {
+ lib.add_define("UI_LAYOUT_DELIZIA", None);
+ } else if cfg!(feature = "layout_eckhart") {
+ lib.add_define("UI_LAYOUT_ECKHART", None);
+ } else {
+ bail_unsupported!();
+ }
+
+ if cfg!(feature = "thp") {
+ lib.add_define("USE_THP", None);
+ }
+
+ if cfg!(feature = "serial_number") {
+ lib.add_define("USE_SERIAL_NUMBER", Some("1"));
+ }
+
+ if cfg!(feature = "disable_animation") {
+ lib.add_define("DISABLE_ANIMATION", Some("1"));
+ }
+
+ if cfg!(feature = "log_stack_usage") {
+ lib.add_define("LOG_STACK_USAGE", Some("1"));
+ }
+
+ if cfg!(feature = "memperf") {
+ lib.add_define("MICROPY_TREZOR_MEMPERF", Some("1"));
+ }
+
+ if cfg!(feature = "n4w1") {
+ lib.add_define("USE_N4W1", Some("1"));
+ }
+
+ lib.add_define(
+ "MICROPY_ENABLE_SOURCE_LINE",
+ Some(if cfg!(feature = "enable_source_lines") {
+ "1"
+ } else {
+ "0"
+ }),
+ );
+
+ if cfg!(feature = "pyopt") {
+ lib.add_define("PYOPT", Some("1"));
+ lib.add_private_define("MICROPY_OOM_CALLBACK", Some("0"));
+ } else {
+ lib.add_define("PYOPT", Some("0"));
+ // This is needed to compile modtrezorutils-meminfo.h that
+ // calls STATIC functions in other modules
+ lib.add_private_defines([("STATIC", Some("")), ("MICROPY_OOM_CALLBACK", Some("1"))]);
+ }
+
+ // TODO: remove this hack (causing cyclic dependence) by moving micropython
+ // related code from trezor_lib into upymod.
+ lib.add_private_include("../rust");
+
+ lib.add_sources([
+ "modutime.c",
+ "rustmods.c",
+ "trezorobj.c",
+ "modtrezorapp/modtrezorapp.c",
+ "modtrezorconfig/modtrezorconfig.c",
+ "modtrezorcrypto/modtrezorcrypto.c",
+ "modtrezorcrypto/crc.c",
+ "modtrezorio/modtrezorio.c",
+ "modtrezorui/modtrezorui.c",
+ "modtrezorutils/modtrezorutils.c",
+ ]);
+
+ if cfg!(feature = "sd_card") {
+ lib.add_sources(["modtrezorio/ff.c", "modtrezorio/ffunicode.c"]);
+ }
+
+ let attrs =
+ cfg!(not(feature = "emulator")).then(|| xbuild::CompileAttrs::new().with_flag("-O3"));
+
+ lib.add_sources_in_dir_with_attrs(mpy_dir, ["py/gc.c", "py/pystack.c", "py/vm.c"], attrs);
+
+ lib.add_sources_in_dir(
+ mpy_dir,
+ [
+ "extmod/modubinascii.c",
+ "extmod/moductypes.c",
+ "extmod/moduheapq.c",
+ "extmod/modutimeq.c",
+ "extmod/utime_mphal.c",
+ "shared/timeutils/timeutils.c",
+ "py/argcheck.c",
+ "py/asmarm.c",
+ "py/asmbase.c",
+ "py/asmthumb.c",
+ "py/asmx64.c",
+ "py/asmx86.c",
+ "py/asmxtensa.c",
+ "py/bc.c",
+ "py/binary.c",
+ "py/builtinevex.c",
+ "py/builtinhelp.c",
+ "py/builtinimport.c",
+ "py/compile.c",
+ "py/emitbc.c",
+ "py/emitcommon.c",
+ "py/emitglue.c",
+ "py/emitinlinethumb.c",
+ "py/formatfloat.c",
+ "py/frozenmod.c",
+ "py/lexer.c",
+ "py/malloc.c",
+ "py/map.c",
+ "py/modarray.c",
+ "py/modbuiltins.c",
+ "py/modcmath.c",
+ "py/modcollections.c",
+ "py/modgc.c",
+ "py/modio.c",
+ "py/modmath.c",
+ "py/modmicropython.c",
+ "py/modstruct.c",
+ "py/modsys.c",
+ "py/modthread.c",
+ "py/moduerrno.c",
+ "py/mpprint.c",
+ "py/mpstate.c",
+ "py/mpz.c",
+ "py/nativeglue.c",
+ "py/obj.c",
+ "py/objarray.c",
+ "py/objattrtuple.c",
+ "py/objbool.c",
+ "py/objboundmeth.c",
+ "py/objcell.c",
+ "py/objclosure.c",
+ "py/objcomplex.c",
+ "py/objdeque.c",
+ "py/objdict.c",
+ "py/objenumerate.c",
+ "py/objexcept.c",
+ "py/objfilter.c",
+ "py/objfloat.c",
+ "py/objfun.c",
+ "py/objgenerator.c",
+ "py/objgetitemiter.c",
+ "py/objint.c",
+ "py/objint_longlong.c",
+ "py/objint_mpz.c",
+ "py/objlist.c",
+ "py/objmap.c",
+ "py/objmodule.c",
+ "py/objnamedtuple.c",
+ "py/objnone.c",
+ "py/objobject.c",
+ "py/objpolyiter.c",
+ "py/objproperty.c",
+ "py/objrange.c",
+ "py/objreversed.c",
+ "py/objset.c",
+ "py/objsingleton.c",
+ "py/objslice.c",
+ "py/objstr.c",
+ "py/objstringio.c",
+ "py/objstrunicode.c",
+ "py/objtuple.c",
+ "py/objtype.c",
+ "py/objzip.c",
+ "py/opmethods.c",
+ "py/parse.c",
+ "py/parsenum.c",
+ "py/parsenumbase.c",
+ "py/persistentcode.c",
+ "py/qstr.c",
+ "py/reader.c",
+ "py/repl.c",
+ "py/runtime.c",
+ "py/runtime_utils.c",
+ "py/scheduler.c",
+ "py/scope.c",
+ "py/sequence.c",
+ "py/showbc.c",
+ "py/smallint.c",
+ "py/stackctrl.c",
+ "py/stream.c",
+ "py/unicode.c",
+ "py/vstr.c",
+ "py/warning.c",
+ ],
+ );
+
+ if cfg!(feature = "emulator") {
+ lib.add_defines([("MP_CONFIGFILE", Some("\"mpconfigport.h\""))]);
+
+ if cfg!(feature = "frozen") {
+ lib.add_define("TREZOR_EMULATOR_FROZEN", None);
+ }
+
+ // TODO: refactor modtrezorutils-meminfo.h to avoid this
+ //
+ // The hack is needed to compile modtrezorutils-meminfo.h that
+ // calls STATIC functions in other modules
+ lib.add_private_define("STATIC", Some(""));
+
+ lib.add_sources_in_dir(
+ mpy_dir,
+ [
+ "extmod/vfs_posix_file.c",
+ "extmod/moduos.c",
+ "py/emitnarm.c",
+ "py/emitnative.c",
+ "py/emitnthumb.c",
+ "py/emitnx64.c",
+ "py/emitnx86.c",
+ "py/nlr.c",
+ "py/nlraarch64.c",
+ "py/nlrsetjmp.c",
+ "py/nlrthumb.c",
+ "py/nlrx64.c",
+ "py/nlrx86.c",
+ "py/profile.c",
+ "ports/unix/alloc.c",
+ "ports/unix/gccollect.c",
+ "ports/unix/input.c",
+ "ports/unix/unix_mphal.c",
+ "shared/runtime/gchelper_generic.c",
+ "shared/readline/readline.c",
+ ],
+ );
+ } else if cfg!(feature = "mcu_stm32") {
+ lib.add_sources_in_dir("../projects/firmware", ["mphalport.c", "nlrthumb.c"]);
+
+ lib.add_sources_in_dir(
+ mpy_dir,
+ [
+ "ports/stm32/gccollect.c",
+ "shared/libc/abort_.c",
+ "shared/libc/printf.c",
+ "shared/runtime/gchelper_native.c",
+ "shared/runtime/interrupt_char.c",
+ "shared/runtime/pyexec.c",
+ "shared/runtime/stdout_helpers.c",
+ // "shared/runtime/gchelper_m3.s", // This file is added later
+ ],
+ );
+ } else {
+ bail_unsupported!();
+ }
+
+ // Include OUT_DIR for so the code can use #include <genhdr/xxx.h>
+ lib.add_include(PathBuf::from(env::var("OUT_DIR").unwrap()));
+
+ // Defines SCM_REVISION_INIT
+ let scm_revision_xor2 = define_scm_revision(lib)?;
+
+ // Build content of genhdr folder
+ let mpy_builder = MpyBuilder::new(lib, scm_revision_xor2);
+ let qstr_preprocessed = mpy_builder.build_genhdr()?;
+
+ if cfg!(feature = "frozen") && !xbuild::is_rust_analyzer() {
+ // Build frozen_mpy.c if frozen modules are enabled
+ let mpy_frozen_c = mpy_builder.build_frozen_modules(&qstr_preprocessed)?;
+ lib.add_source(mpy_frozen_c);
+
+ // Add symlink to __oot/src folder
+ create_mpy_files_symlink()?;
+ }
+
+ if cfg!(not(feature = "emulator")) {
+ // This file must not be preprocessed in MpyBuilder so it is added here
+ // after the build_genhdr step
+ lib.add_sources_in_dir(mpy_dir, ["shared/runtime/gchelper_m3.s"]);
+ }
+
+ Ok(())
+ })
+}
+
+/// Extracts the Git revision, obfuscates it, and defines
+/// SCM_REVISION_INIT together with two per-build XOR key bytes.
+fn define_scm_revision(lib: &mut CLibrary) -> Result<u8> {
+ let git_output = std::process::Command::new("git")
+ .args(["rev-parse", "HEAD"])
+ .output()
+ .context("Failed to execute git command")?;
+
+ ensure!(
+ git_output.status.success(),
+ "Git command failed: {}",
+ String::from_utf8_lossy(&git_output.stderr)
+ );
+
+ let revision = String::from_utf8_lossy(&git_output.stdout);
+ let revision = revision.trim();
+
+ let mut revision = revision.as_bytes()[8..]
+ .chunks_exact(2)
+ .map(|chunk| {
+ let hex = std::str::from_utf8(chunk).expect("git hash must be ASCII hex");
+ u8::from_str_radix(hex, 16).expect("valid hex")
+ })
+ .collect::<Vec<u8>>();
+
+ // Derive the XOR bytes from a standard FNV-1 hash of the whole revision.
+ let fnv_hash = revision.iter().fold(0x811C9DC5u32, |hash, &byte| {
+ hash.wrapping_mul(0x01000193) ^ u32::from(byte)
+ });
+ let hash_bytes = fnv_hash.to_le_bytes();
+ let xor1 = hash_bytes[0] ^ hash_bytes[2];
+ let xor2 = hash_bytes[1] ^ hash_bytes[3];
+
+ // Apply both XOR keys in an alternating pattern to obfuscate the revision.
+ for (index, byte) in revision.iter_mut().enumerate() {
+ *byte ^= if index % 2 == 0 { xor1 } else { xor2 };
+ }
+
+ // Format the obfuscated revision and XOR values as an array of hex bytes.
+ let scm_rev_init = revision
+ .iter()
+ .map(|byte| format!("0x{:02x},", byte))
+ .collect::<String>();
+
+ lib.add_private_defines([
+ (
+ "SCM_REVISION_LONG_INIT",
+ Some(format!("{{{}}}", scm_rev_init)),
+ ),
+ ("SCM_REVISION_XOR1", Some(format!("0x{:02x}", xor1))),
+ ("SCM_REVISION_XOR2", Some(format!("0x{:02x}", xor2))),
+ ]);
+
+ Ok(xor2)
+}
+
+/// Creates a symlink to the __oot/src folder used
+/// when generating test coverage reports that need to process *.i files
+fn create_mpy_files_symlink() -> Result<()> {
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+ let symlink_path = out_dir.join("../../../mpy-files");
+ let target_path = out_dir.join("__oot/src");
+
+ if symlink_path.exists() {
+ fs::remove_file(&symlink_path).with_context(|| {
+ format!(
+ "Failed to remove existing symlink at {}",
+ symlink_path.display()
+ )
+ })?;
+ }
+
+ unix::fs::symlink(&target_path, &symlink_path).with_context(|| {
+ format!(
+ "Failed to create symlink from {} to {}",
+ symlink_path.display(),
+ target_path.display()
+ )
+ })?;
+
+ Ok(())
+}
+
+struct MpyBuilder<'a> {
+ lib: &'a CLibrary,
+ crate_dir: PathBuf,
+ mpy_dir: PathBuf,
+ out_dir: PathBuf,
+ genhdr_dir: PathBuf,
+ py_src_dir: PathBuf,
+ scm_revision_xor2: u8,
+}
+
+impl<'a> MpyBuilder<'a> {
+ fn new(lib: &'a CLibrary, scm_revision_xor2: u8) -> Self {
+ let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
+ let mpy_dir = crate_dir.join("../../vendor/micropython");
+ let py_src_dir = crate_dir.join("../../src");
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+ let genhdr_dir = out_dir.join("genhdr");
+
+ Self {
+ lib,
+ crate_dir,
+ mpy_dir,
+ out_dir,
+ genhdr_dir,
+ py_src_dir,
+ scm_revision_xor2,
+ }
+ }
+
+ fn build_genhdr(&self) -> Result<PathBuf> {
+ // Generate mpversion.h containing MPY_VERSION and MPY_GIT_TAG
+ // macros based on Git metadata and the version in mpy_dir
+ self.build_mpversion_header()?;
+
+ // Extract all strings from protobuf .proto files and generate
+ // qstrdefs.protobuf.h with corresponding Q(xxx) definitions.
+ self.build_protobuf_headers()?;
+
+ // Additional sourcess that do not live in the /upymod folder.
+ // TODO: remove this hack by moving these sources (or part of them)
+ // into upymod.
+ let extra_sources = if cfg!(feature = "emulator") {
+ [self.crate_dir.join("../projects/unix/main.c")]
+ } else if cfg!(feature = "mcu_stm32") {
+ [self.crate_dir.join("../projects/firmware/main.c")]
+ } else {
+ bail_unsupported!();
+ };
+
+ // Run the C preprocessor on all sources + extra_sources and store
+ // the preprocessed output in corresponding .upydef files next to
+ // each object file.
+ let upydefs = self.lib.process_sources(
+ "upydef",
+ Some(&["-E", "-DNO_QSTR", "-DN_X64", "-DN_X86", "-DN_THUMB"]),
+ Some(&extra_sources),
+ )?;
+
+ // Extract all MP_QSTR_xxx entries from preprocessed .upydef files
+ // and store them in qstrdefs.collected.h as Q(xxx).
+ let qstr_collected = self.build_qstrdefs_collected(&upydefs)?;
+
+ // Extract all MP_REGISTER_MODULE entries from preprocessed .upydef
+ // files and store them in moduledefs.collected.h.
+ let moduledefs_collected = self.build_moduledefs_collected(&upydefs)?;
+
+ // Generate MicroPython module definitions from
+ // moduledefs.collected.h and store them in moduledefs.h, which can
+ // be included directly in firmware.
+ self.build_moduledefs(&moduledefs_collected)?;
+
+ // Combine qstrdefs.collected.h with additional headers into
+ // qstrdefs.combined.h. During this process, Q(xxx) is converted to
+ // "Q(xxx)" so it passes through the next C preprocessing step
+ // unchanged.
+ let qstr_combined = self.build_qstrdefs_combined(&qstr_collected)?;
+
+ // Run the C preprocessor on qstrdefs.combined.h and store the result
+ // in qstrdefs.preprocessed.raw.h.
+ let qstr_preprocessed_raw = self.build_qstrdefs_preprocessed_raw(&qstr_combined)?;
+
+ // Process qstrdefs.preprocessed.raw.h to remove quotes around Q(xxx)
+ // and store the result in qstrdefs.preprocessed.h.
+ let qstr_preprocessed = self.build_qstrdefs_preprocessed(&qstr_preprocessed_raw)?;
+
+ // Run makeqstrdata.py on qstrdefs.preprocessed.h to generate
+ // qstrdefs.generated.h, which contains qstr definitions in a format
+ // that can be included directly in firmware.
+ let qstr_generated = self.build_qstrdefs_generated(&qstr_preprocessed)?;
+
+ // Extract all MP_COMPRESSED_ROM_TEXT("xxx") entries from preprocessed
+ // .upydef files and store them in compressed.collected.h as one value
+ // per line.
+ let compressed_collected = self.build_compressed_collected(&upydefs)?;
+
+ // Run makecompresseddata.py on compressed.collected.h to generate
+ // compressed.data.h with compressed data definitions in a format that
+ // can be included directly in firmware.
+ self.build_compressed_data(&compressed_collected)?;
+
+ // Generate protobuf blobs based on .proto for Rust code.
+ self.build_protobuf_blobs(&qstr_generated)?;
+
+ Ok(qstr_preprocessed)
+ }
+
+ fn build_mpversion_header(&self) -> Result<()> {
+ let output = self.genhdr_dir.join("mpversion.h");
+
+ let mut cmd = std::process::Command::new("python3");
+ let tool = self.mpy_dir.join("py/makeversionhdr.py");
+ cmd.arg(&tool).arg(&output);
+
+ xbuild::run_command(&mut cmd, &[tool], &[output]).context("Failed to build mpversion.h")?;
+
+ Ok(())
+ }
+
+ fn collect_protobuf_inputs(&self, protob_dir: &Path) -> Result<InputFiles> {
+ let mut inputs = InputFiles::new();
+
+ inputs
+ .add(protob_dir, "*.proto")
+ .context("Failed to collect protobuf sources")?;
+
+ inputs.remove(protob_dir, "messages-bootloader.proto");
+
+ if cfg!(not(feature = "thp")) {
+ inputs.remove(protob_dir, "messages-thp.proto");
+ }
+
+ if cfg!(feature = "pyopt") {
+ inputs.remove(protob_dir, "messages-debug.proto");
+ }
+
+ Ok(inputs)
+ }
+
+ fn build_protobuf_headers(&self) -> Result<PathBuf> {
+ let protob_dir = self.crate_dir.join("../../../common/protob");
+ let output = self.genhdr_dir.join("qstrdefs.protobuf.h");
+ let inputs = self.collect_protobuf_inputs(&protob_dir)?;
+ let pb2py_path = protob_dir.join("pb2py");
+
+ let mut cmd = std::process::Command::new(&pb2py_path);
+ cmd.args(inputs.as_paths())
+ .arg("--qstr-out")
+ .arg(&output)
+ .arg(format!(
+ "--bitcoin-only={}",
+ if cfg!(feature = "universal_fw") {
+ "0"
+ } else {
+ "1"
+ }
+ ));
+
+ let inputs = inputs.as_path_refs().chain(once(pb2py_path.as_path()));
+
+ xbuild::run_command(&mut cmd, inputs, [&output])
+ .context("Failed to build protobuf headers")?;
+
+ Ok(output)
+ }
+
+ fn build_protobuf_blobs(&self, qstrdefs_generated: &Path) -> Result<()> {
+ let protob_dir = self.crate_dir.join("../../../common/protob");
+
+ let inputs = self.collect_protobuf_inputs(&protob_dir)?;
+ let pb2py_path = protob_dir.join("pb2py");
+
+ let blobs_dir = self.out_dir.join("protob_blobs");
+ let outputs = [
+ blobs_dir.join("proto_enums.data"),
+ blobs_dir.join("proto_msgs.data"),
+ blobs_dir.join("proto_names.data"),
+ blobs_dir.join("proto_wire.data"),
+ ];
+
+ println!("cargo::metadata=protob_blobs_dir={}", blobs_dir.display());
+
+ let mut cmd = std::process::Command::new(&pb2py_path);
+ cmd.arg(format!(
+ "--bitcoin-only={}",
+ if cfg!(feature = "universal_fw") {
+ "0"
+ } else {
+ "1"
+ }
+ ))
+ .arg("--blob-outdir")
+ .arg(&blobs_dir)
+ .args(inputs.as_paths())
+ .arg("--qstr-defs")
+ .arg(qstrdefs_generated);
+
+ let inputs = inputs
+ .as_path_refs()
+ .chain(once(qstrdefs_generated))
+ .chain(once(pb2py_path.as_path()));
+
+ xbuild::run_command(&mut cmd, inputs, &outputs)
+ .context("Failed to build protobuf blobs")?;
+
+ Ok(())
+ }
+
+ fn build_qstrdefs_collected(&self, upydef_files: &[PathBuf]) -> Result<PathBuf> {
+ let output = self.genhdr_dir.join("qstrdefs.collected.h");
+ let mut cmd = std::process::Command::new("sh");
+ cmd
+ .arg("-c")
+ .arg(r#"out="$1"; shift; cat "$@" | perl -nle 'print "Q($1)" while /MP_QSTR_(\w+)/g' > "$out""#)
+ .arg("sh")
+ .arg(&output)
+ .args(upydef_files);
+
+ let inputs = upydef_files.iter().collect::<Vec<_>>();
+ xbuild::run_command(&mut cmd, &inputs, [&output])
+ .context("Failed to build qstrdefs collected")?;
+
+ Ok(output)
+ }
+
+ fn build_moduledefs_collected(&self, upydef_files: &[PathBuf]) -> Result<PathBuf> {
+ let output = self.genhdr_dir.join("moduledefs.collected.h");
+ let mut cmd = std::process::Command::new("sh");
+ cmd.arg("-c")
+ .arg(r#"out="$1"; shift; grep '^MP_REGISTER_MODULE' "$@" > "$out""#)
+ .arg("sh")
+ .arg(&output)
+ .args(upydef_files);
+
+ let inputs = upydef_files.iter().collect::<Vec<_>>();
+ xbuild::run_command(&mut cmd, &inputs, [&output])
+ .context("Failed to build moduledefs collected")?;
+
+ Ok(output)
+ }
+
+ fn build_moduledefs(&self, moduledefs_collected: &Path) -> Result<PathBuf> {
+ let output = self.genhdr_dir.join("moduledefs.h");
+
+ let mut cmd = std::process::Command::new("python3");
+ let tool = self.mpy_dir.join("py/makemoduledefs.py");
+ cmd.arg(&tool).arg(moduledefs_collected);
+
+ let inputs = [tool, moduledefs_collected.to_path_buf()];
+ xbuild::run_command_to_file(&mut cmd, &inputs, &output)
+ .context("Failed to build moduledefs")?;
+
+ Ok(output)
+ }
+
+ fn build_qstrdefs_generated(&self, qstr_preprocessed: &Path) -> Result<PathBuf> {
+ let mut cmd = std::process::Command::new("python3");
+ let tool = self.mpy_dir.join("py/makeqstrdata.py");
+ cmd.arg(&tool).arg(qstr_preprocessed);
+
+ let inputs = [tool, qstr_preprocessed.to_path_buf()];
+ let output = self.genhdr_dir.join("qstrdefs.generated.h");
+ xbuild::run_command_to_file(&mut cmd, &inputs, &output)
+ .context("Failed to build qstrdefs generated")?;
+
+ Ok(output)
+ }
+
+ fn build_qstrdefs_combined(&self, qstrdefs_collected: &Path) -> Result<PathBuf> {
+ let output = self.genhdr_dir.join("qstrdefs.combined.h");
+
+ let inputs = [
+ self.mpy_dir.join("py/qstrdefs.h"),
+ self.genhdr_dir.join("qstrdefs.protobuf.h"),
+ qstrdefs_collected.to_path_buf(),
+ self.crate_dir.join("qstrdefsport.h"),
+ ];
+
+ xbuild::emit_rerun_if_changed(&inputs);
+
+ if xbuild::needs_rebuild(&inputs, &[&output]) {
+ let mut output_file = File::create(&output)
+ .unwrap_or_else(|_| panic!("Failed to create {}", output.display()));
+
+ for input in &inputs {
+ let file = File::open(input)
+ .unwrap_or_else(|_| panic!("Failed to opWhy this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.