chore(core): build trezor_lib with xbuild
What changed, and why it matters
This is a routine build-system cleanup for the Trezor firmware. It switches the internal 'trezor_lib' Rust crate to be built with the project's own 'xbuild' tool, removes transitional feature flags, and reorganizes Cargo.toml files. There is no indication this change fixes or introduces a security vulnerability.
No security action required; treat as normal build-system maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit migrates trezor_lib’s build.rs to use xbuild::CLibrary for bindgen-based FFI bindings, removes transitional Cargo features (‘with_new_crates’, ‘with_upymod’), deletes the old cc/glob object-linking path, and updates test setup. It is a pure refactoring/build-infrastructure change with no runtime security logic modifications.
Changed components
core/embed/rust/build.rscore/embed/rust/Cargo.tomlcore/embed/xbuild/src/clibrary/rust_bindings.rscore/embed/xtask/src/cargo.rsInspect captured patch +597 / −868
diff --git a/core/Makefile b/core/Makefile
index 7e8ee662..392b5156 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -125,6 +125,7 @@ test: ## run unit tests
test_rust: ## run rs unit tests
xtask test crypto
+ xtask test trezor_lib
# TODO:
# xtask test all
diff --git a/core/embed/Cargo.lock b/core/embed/Cargo.lock
index 7aa74b11..7370364f 100644
--- a/core/embed/Cargo.lock
+++ b/core/embed/Cargo.lock
@@ -1002,25 +1002,25 @@ version = "0.1.0"
[[package]]
name = "trezor_lib"
-version = "0.1.0"
+version = "0.0.0"
dependencies = [
"bindgen",
- "cc",
"cfg-if",
"crypto",
"cty",
"easer",
- "glob",
"heapless",
"hex",
"io",
"log",
"minicbor",
+ "models",
"num-derive",
"num-traits",
"pareen",
"qrcodegen",
"rtl",
+ "sec",
"serde_json",
"spin",
"static-alloc",
diff --git a/core/embed/projects/bootloader/Cargo.toml b/core/embed/projects/bootloader/Cargo.toml
index 2cce41b8..8f00cc75 100644
--- a/core/embed/projects/bootloader/Cargo.toml
+++ b/core/embed/projects/bootloader/Cargo.toml
@@ -109,8 +109,6 @@ default = [
"models/bootloader",
"crypto/ed25519_no_precomp",
- "trezor_lib/with_new_crates", # only for transitional period
-
"trezor_lib/crypto",
"trezor_lib/ui",
"trezor_lib/bootloader",
diff --git a/core/embed/projects/firmware/Cargo.toml b/core/embed/projects/firmware/Cargo.toml
index 4d6deee5..60ca4d13 100644
--- a/core/embed/projects/firmware/Cargo.toml
+++ b/core/embed/projects/firmware/Cargo.toml
@@ -158,9 +158,6 @@ default = [
"io/usb_iface_wire",
"crypto/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",
diff --git a/core/embed/projects/kernel/Cargo.toml b/core/embed/projects/kernel/Cargo.toml
index 620f4e81..02b31e86 100644
--- a/core/embed/projects/kernel/Cargo.toml
+++ b/core/embed/projects/kernel/Cargo.toml
@@ -102,7 +102,6 @@ default = [
"sec/storage",
"models/kernel",
"crypto/aes_gcm",
- "trezor_lib/with_new_crates", # only for transitional period
]
mcu_stm32f4 = []
diff --git a/core/embed/projects/prodtest/Cargo.toml b/core/embed/projects/prodtest/Cargo.toml
index d1a0f5a3..45bba8b8 100644
--- a/core/embed/projects/prodtest/Cargo.toml
+++ b/core/embed/projects/prodtest/Cargo.toml
@@ -124,8 +124,6 @@ default = [
"crypto/mldsa",
"crypto/noise",
- "trezor_lib/with_new_crates", # only for transitional period
-
"trezor_lib/crypto",
"trezor_lib/ui",
"trezor_lib/prodtest",
diff --git a/core/embed/projects/unix/Cargo.toml b/core/embed/projects/unix/Cargo.toml
index 2f1c136b..60565508 100644
--- a/core/embed/projects/unix/Cargo.toml
+++ b/core/embed/projects/unix/Cargo.toml
@@ -155,9 +155,6 @@ default = [
"crypto/secp256k1_zkp",
"crypto/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",
diff --git a/core/embed/projects/unix/rust_c_setup.c b/core/embed/projects/unix/rust_c_setup.c
deleted file mode 100644
index e4bed6c0..00000000
--- a/core/embed/projects/unix/rust_c_setup.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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/>.
- */
-
-#include <trezor_rtl.h>
-
-#include <io/display.h>
-#include <io/usb_config.h>
-#include <sec/unit_properties.h>
-#include <sys/flash.h>
-#include <sys/flash_otp.h>
-#include <sys/system.h>
-
-#ifdef USE_BUTTON
-#include <io/button.h>
-#endif
-
-#ifdef USE_TOUCH
-#include <io/touch.h>
-#endif
-
-#ifdef USE_TROPIC
-#include <sec/tropic.h>
-#endif
-
-// Initialize the system and drivers for running tests in the Rust code.
-// The function is called from the Rust before the test main function is run.
-void rust_tests_c_setup(void) {
- system_init(NULL);
-
- flash_init();
- flash_otp_init();
-
- unit_properties_init();
-
- display_init(DISPLAY_RESET_CONTENT);
-
-#if USE_TOUCH
- touch_init();
-#endif
-
-#ifdef USE_BUTTON
- button_init();
-#endif
-
-#ifdef USE_TROPIC
- tropic_init(NULL);
-#endif
-
- usb_configure(NULL);
-}
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index 82000c09..5d14e959 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -1,78 +1,147 @@
[package]
name = "trezor_lib"
-version = "0.1.0"
+version = "0.0.0"
authors = ["SatoshiLabs <info@satoshilabs.com>"]
edition = "2021"
-build = "build.rs"
+links = "trezor_lib"
+
+[lib]
+crate-type = ["rlib"]
+doctest = false
+
+[build-dependencies]
+bindgen.workspace = true
+xbuild.workspace = true
+
+[dev-dependencies]
+hex.workspace = true
+serde_json.workspace = true
+
+[dependencies]
+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-thp = { workspace = true, optional = true }
+trezor-tjpgdec.workspace = true
+ufmt.workspace = true
+unsize.workspace = true
+without-alloc.workspace = true
+zeroize = { workspace = true, optional = true }
+
+# crates in embed/ directory
+crypto.workspace = true
+io.workspace = true
+models.workspace = true
+rtl.workspace = true
+sec.workspace = true
+sys.workspace = true
+upymod = { workspace = true, optional = true }
[features]
-default = ["layout_bolt"]
-crypto = ["dep:crypto"]
-layout_bolt = []
-layout_caesar = []
-layout_delizia = []
-layout_eckhart = []
-micropython = []
-protobuf = ["micropython"]
-ui = []
-dma2d = []
-framebuffer = []
-display_mono = []
-display_rgb565 = ["ui_antialiasing"]
-display_rgba8888 = ["ui_antialiasing"]
-ui_debug = []
-ui_performance_overlay = []
-ui_debug_overlay = []
-ui_antialiasing = []
-ui_blurring = []
-ui_image_buffer = []
-ui_color_32bit = []
-ui_overlay = []
-ui_empty_lock = []
-ui_jpeg = []
-ui_font_kerning = []
-hw_jpeg_decoder = []
+
+# --------------------------------------------------------------------------
+# Selectable components
+# --------------------------------------------------------------------------
+
+app_loading = []
+backlight = []
+ble = []
boot_ucb = []
bootloader = []
-prodtest = []
button = []
-touch = []
clippy = []
+crypto = []
+dbg_console = []
debug = ["ui_debug", "dev_keys"]
debuglink = []
dev_keys = []
-sbu = []
+display_mono = []
+display_rgb565 = ["ui_antialiasing"]
+display_rgba8888 = ["ui_antialiasing"]
+dma2d = []
+framebuffer = []
haptic = []
-sd_card = []
-rgb_led = []
-power_manager = []
-touch_wakeup = []
-pmic = []
-backlight = []
-usb = []
-optiga = []
-ble = []
+hw_jpeg_decoder = []
+layout_bolt = []
+layout_caesar = []
+layout_delizia = []
+layout_eckhart = []
+micropython = ["dep:upymod"]
+n4w1 = []
nrf = []
-smp = []
-tropic = []
+optiga = []
+pmic = []
+power_manager = []
+prodtest = []
+protobuf = ["micropython"]
+rgb_led = []
+sbu = []
+sd_card = []
+secmon_layout = []
serial_number = []
+smp = []
storage = []
telemetry = []
-n4w1 = []
-translations = ["crypto"]
-secmon_layout = []
-dbg_console = ["dep:sys"]
-app_loading = []
thp = ["crypto/thp", "dep:trezor-thp", "dep:zeroize"]
+touch = []
+touch_wakeup = []
+translations = ["crypto"]
+tropic = []
+ui = []
+ui_antialiasing = []
+ui_blurring = []
+ui_color_32bit = []
+ui_debug = []
+ui_debug_overlay = []
+ui_empty_lock = []
+ui_font_kerning = []
+ui_image_buffer = []
+ui_jpeg = []
+ui_overlay = []
+ui_performance_overlay = []
+universal_fw = []
+usb = []
+
+# --------------------------------------------------------------------------
+# Unit test configuration
+# --------------------------------------------------------------------------
+
test = [
+ "crypto/aes_gcm",
+ "emulator",
+ "io/button",
+ "io/display_panel_t2t1",
+ "io/emulator",
+ "io/fancy_fatal_error",
+ "io/kernel_mode",
+ "io/mcu_stm32f429",
+ "io/nrf",
+ "io/secure_mode",
+ "io/touch",
+ "mcu_stm32f429",
+ "models/model_t2t1",
+ "sec/secret",
+ "sys/dbg_console",
+ "upymod/emulator",
+ "upymod/layout_bolt",
+ "upymod/universal_fw",
+
"backlight",
"button",
- "cc",
"crypto",
"dbg_console",
- "dma2d",
"debug",
- "glob",
+ "dma2d",
+ "layout_bolt",
"micropython",
"nrf",
"optiga",
@@ -83,55 +152,23 @@ test = [
"touch",
"translations",
"trezor-thp?/use_std",
- "ui",
- "ui_jpeg",
- "ui_font_kerning",
"ui_blurring",
+ "ui_empty_lock",
+ "ui_font_kerning",
"ui_image_buffer",
+ "ui_jpeg",
"ui_overlay",
- "ui_empty_lock",
+ "ui",
"universal_fw",
]
-universal_fw = []
-with_new_crates = ["dep:io", "dep:xbuild"]
-with_upymod = ["dep:upymod"]
-[lib]
-crate-type = ["rlib"]
-doctest = false
-
-[dependencies]
-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
-rtl.workspace = true
-spin.workspace = true
-static-alloc.workspace = true
-trezor-tjpgdec.workspace = true
-ufmt.workspace = true
-unsize.workspace = true
-without-alloc.workspace = true
+# --------------------------------------------------------------------------
+# Automatically derived features (do not enable from outside)
+# --------------------------------------------------------------------------
-crypto = { workspace = true, optional = true }
-io = { workspace = true, optional = true }
-sys = { workspace = true, optional = true }
-trezor-thp = { workspace = true, optional = true }
-upymod = { workspace = true, optional = true }
-zeroize = { workspace = true, optional = true }
+default = []
-[build-dependencies]
-bindgen.workspace = true
-cc = { workspace = true, optional = true }
-glob = { workspace = true, optional = true }
-xbuild = { workspace = true, optional = true }
+emulator = []
+mcu_stm32f429 = ["mcu_stm32f4"]
+mcu_stm32f4 = []
-[dev-dependencies]
-hex.workspace = true
-serde_json.workspace = true
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index ee13a33f..0d04b957 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -1,663 +1,340 @@
use std::env;
-#[cfg(all(feature = "test", not(feature = "with_new_crates")))]
-use std::ffi::OsStr;
-use std::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)");
+use xbuild::{CLibrary, Result};
- #[cfg(not(feature = "with_new_crates"))]
- println!("cargo:rustc-env=BUILD_DIR={}", build_dir());
- #[cfg(feature = "micropython")]
- generate_qstr_bindings();
- #[cfg(feature = "micropython")]
- generate_micropython_bindings();
- generate_trezorhal_bindings();
- #[cfg(all(feature = "test", not(feature = "with_new_crates")))]
- link_core_objects();
+fn main() -> Result<()> {
+ xbuild::build(|lib| {
+ lib.import_lib("io")?;
- #[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)
- .canonicalize()
- .unwrap()
- .to_str()
- .unwrap()
- .to_string()
-}
-
-#[cfg(not(feature = "with_new_crates"))]
-const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
- "-I../projects/bootloader",
- "-I../projects/unix",
- "-I../../build/unix",
- "-I../../vendor/micropython/ports/unix",
- "-I../../../crypto",
- "-I../../../storage",
- "-I../../vendor/micropython",
- "-I../../vendor/micropython/lib/uzlib",
- "-I../../vendor/",
- "-I../rtl/inc",
- "-I../io/gfx/inc",
- "-I../io/ble/inc",
- "-I../io/button/inc",
- "-I../io/display/inc",
- "-I../io/haptic/inc",
- "-I../io/nrf/inc",
- "-I../io/touch/inc",
- "-I../io/power_manager/inc",
- "-I../io/rgb_led/inc",
- "-I../io/suspend/inc",
- "-I../io/translations/inc",
- "-I../io/usb/inc",
- "-I../sec/storage/inc",
- "-I../sys/dbg/inc",
- "-I../sys/inc",
- "-I../sys/time/inc",
- "-I../sys/task/inc",
- "-I../sys/irq/inc",
- "-I../sys/flash/inc",
- "-I../models",
- "-DTREZOR_EMULATOR",
- "-DUSE_BUTTON",
- "-DUSE_TOUCH",
- "-DUSE_HAPTIC",
- "-DUSE_RGB_LED",
- "-DUSE_BLE",
- "-DUSE_POWER_MANAGER",
- "-DUSE_NRF",
- "-DUSE_HW_JPEG_DECODER",
- "-DUSE_STORAGE",
- "-DUSE_DBG_CONSOLE",
- "-DBOOTLOADER",
-];
-
-#[cfg(not(feature = "with_new_crates"))]
-fn add_bindgen_macros<'a>(
- clang_args: &mut Vec<String>,
- envvar: Option<&'a str>,
- test_envvar: Option<&'a str>,
-) {
- if let Some(envvar) = envvar {
- clang_args.extend(envvar.split(',').map(String::from));
- return;
- }
- clang_args.extend(DEFAULT_BINDGEN_MACROS_COMMON.iter().map(|s| s.to_string()));
- if let Some(envvar) = test_envvar {
- clang_args.extend(envvar.split(',').map(String::from));
- return;
- }
-
- let mut model_dirs: Vec<&str> = vec![];
- // always include Bolt as the baseline
- model_dirs.push("../models/T2T1");
- #[cfg(feature = "layout_caesar")]
- model_dirs.push("../models/T3B1");
- #[cfg(feature = "layout_delizia")]
- model_dirs.push("../models/T3T1");
- #[cfg(feature = "layout_eckhart")]
- model_dirs.push("../models/T3W1");
- for model_dir in model_dirs {
- let macros = PathBuf::from(model_dir).join("test_bindgen_macros.txt");
- let contents = std::fs::read_to_string(¯os)
- .unwrap_or_else(|_| panic!("Failed to read {:?}", macros));
- clang_args.extend(contents.split(",\n").map(String::from));
- }
-}
-
-/// Generates Rust module that exports QSTR constants used in firmware.
-#[cfg(feature = "micropython")]
-fn generate_qstr_bindings() {
- 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_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();
+ generate_trezorhal_bindings(lib)?;
- #[cfg(not(feature = "with_new_crates"))]
- let enum_size = if is_firmware() {
- "-fshort-enums"
- } else {
- "-fno-short-enums"
- };
+ if cfg!(feature = "micropython") {
+ // 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"))]
- bindgen::Builder::default()
- .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,
- })
- // Pass in correct include paths.
- .clang_args(&["-I", &build_dir()])
- .clang_arg(enum_size)
- // Customize the standard types.
- .use_core()
- .ctypes_prefix("cty")
- .size_t_is_usize(true)
- // Tell cargo to invalidate the built crate whenever any of the
- // included header files change.
- .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
- .generate()
- .expect("Unable to generate Rust QSTR bindings")
- .write_to_file(&dest_file)
- .unwrap();
+ lib.import_lib("upymod")?;
- // rewrite the file to change internal representation of the qstr newtype
- let qstr_generated = std::fs::read_to_string(&dest_file).unwrap();
-
- let qstr_enum_type = if is_firmware() { "c_ushort" } else { "c_uint" };
-
- let qstr_modified = qstr_generated.replace(
- &format!("pub struct Qstr(pub cty::{});", qstr_enum_type),
- "pub struct Qstr(pub usize);",
- );
-
- assert_ne!(qstr_generated, qstr_modified, "Failed to rewrite type of Qstr in qstr.rs file.\nThis indicates that the generated file has changed. Please update the rewriting code.");
- 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();
-
- let build_dir_include = format!("-I{}", build_dir());
-
- let mut clang_args: Vec<String> = Vec::new();
-
- let bindgen_macros_env = env::var("BINDGEN_MACROS").ok();
- let test_macros_env = env::var("TEST_BINDGEN_MACROS").ok();
- add_bindgen_macros(
- &mut clang_args,
- bindgen_macros_env.as_deref(),
- test_macros_env.as_deref(),
- );
-
- #[cfg(feature = "framebuffer")]
- {
- bindings = bindings.clang_args(&["-DFRAMEBUFFER"]);
- }
-
- clang_args.push(build_dir_include);
-
- // Pass in correct include paths and defines.
- if is_firmware() {
- clang_args.push("-nostdinc".to_string());
- clang_args.push("-fshort-enums".to_string()); // Make sure enums use the same size as in C
-
- // Append gcc-arm-none-eabi's include paths.
- let cc_output = Command::new("arm-none-eabi-gcc")
- .arg("-E")
- .arg("-Wp,-v")
- .arg("-")
- .output()
- .expect("arm-none-eabi-gcc failed to execute");
- if !cc_output.status.success() {
- panic!("arm-none-eabi-gcc failed");
+ generate_micropython_bindings(lib)?;
+ generate_qstr_bindings(lib)?;
}
- let include_paths =
- String::from_utf8(cc_output.stderr).expect("arm-none-eabi-gcc returned invalid output");
- let include_args = include_paths
- .lines()
- .skip_while(|s| !s.contains("search starts here:"))
- .take_while(|s| !s.contains("End of search list."))
- .filter(|s| s.starts_with(' '))
- .map(|s| format!("-I{}", s.trim()));
-
- bindings = bindings.clang_args(include_args);
- } else {
- clang_args.push("-fno-short-enums".to_string());
- }
- bindings = bindings.clang_args(&clang_args);
-
- bindings
- // 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 = "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();
+ 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");
+ }
- 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()))
+ Ok(())
+ })
}
-#[cfg(feature = "micropython")]
-fn generate_micropython_bindings() {
- let out_dir = env::var("OUT_DIR").unwrap();
-
+fn generate_micropython_bindings(lib: &mut CLibrary) -> Result<()> {
// Tell cargo to invalidate the built crate whenever the header changes.
println!("cargo:rerun-if-changed=micropython.h");
- let bindings = prepare_bindings()
- .header("micropython.h")
- // obj
- .new_type_alias("mp_obj_t")
- .allowlist_type("mp_obj_type_t")
- .allowlist_type("mp_obj_base_t")
- .allowlist_function("mp_obj_new_int")
- .allowlist_function("mp_obj_new_int_from_ll")
- .allowlist_function("mp_obj_new_int_from_ull")
- .allowlist_function("mp_obj_new_int_from_uint")
- .allowlist_function("mp_obj_new_bytes")
- .allowlist_function("mp_obj_new_str")
- .allowlist_function("mp_obj_new_tuple")
- .allowlist_function("mp_obj_new_attrtuple")
- .allowlist_function("mp_obj_get_int_maybe")
- .allowlist_function("mp_obj_is_true")
- .allowlist_function("mp_obj_get_type_str")
- .allowlist_function("mp_call_function_n_kw")
- .allowlist_function("trezor_obj_get_ll_checked")
- .allowlist_function("trezor_obj_str_from_rom_text")
- // buffer
- .allowlist_function("mp_obj_new_slice")
- .allowlist_function("mp_obj_subscr")
- .allowlist_function("mp_get_buffer")
- .allowlist_var("MP_BUFFER_READ")
- .allowlist_var("MP_BUFFER_WRITE")
- .allowlist_var("mp_type_str")
- .allowlist_var("mp_type_bytes")
- .allowlist_var("mp_type_bytearray")
- .allowlist_var("mp_type_memoryview")
- // dict
- .allowlist_type("mp_obj_dict_t")
- .allowlist_function("mp_obj_new_dict")
- .allowlist_var("mp_type_dict")
- // fun
- .allowlist_type("mp_obj_fun_builtin_fixed_t")
- .allowlist_var("mp_type_fun_builtin_0")
- .allowlist_var("mp_type_fun_builtin_1")
- .allowlist_var("mp_type_fun_builtin_2")
- .allowlist_var("mp_type_fun_builtin_3")
- .allowlist_type("mp_obj_fun_builtin_var_t")
- .allowlist_var("mp_type_fun_builtin_var")
- // gc
- .allowlist_function("gc_alloc")
- .allowlist_function("gc_free")
- .allowlist_var("GC_ALLOC_FLAG_HAS_FINALISER")
- // iter
- .allowlist_type("mp_obj_iter_buf_t")
- .allowlist_function("mp_getiter")
- .allowlist_function("mp_iternext")
- // list
- .allowlist_type("mp_obj_list_t")
- .allowlist_function("mp_obj_new_list")
- .allowlist_function("mp_obj_list_append")
- .allowlist_function("mp_obj_list_get")
- .allowlist_function("mp_obj_list_set_len")
- .allowlist_var("mp_type_list")
- // map
- .allowlist_type("mp_map_elem_t")
- .allowlist_function("mp_map_init")
- .allowlist_function("mp_map_init_fixed_table")
- .allowlist_function("mp_map_lookup")
- // exceptions
- .allowlist_function("nlr_jump")
- .allowlist_function("mp_obj_new_exception")
- .allowlist_function("mp_obj_new_exception_args")
- .allowlist_function("mp_obj_exception_print")
- .allowlist_function("mp_obj_exception_attr")
- .allowlist_function("mp_obj_exception_make_new")
- .allowlist_function("trezor_obj_call_protected")
- .allowlist_var("mp_type_AttributeError")
- .allowlist_var("mp_type_EOFError")
- .allowlist_var("mp_type_Exception")
- .allowlist_var("mp_type_IndexError")
- .allowlist_var("mp_type_KeyError")
- .allowlist_var("mp_type_MemoryError")
- .allowlist_var("mp_type_OverflowError")
- .allowlist_var("mp_type_ValueError")
- .allowlist_var("mp_type_TypeError")
- .allowlist_var("mp_type_RuntimeError")
- .allowlist_var("mp_type_NotImplementedError")
- // time
- .allowlist_function("mp_hal_ticks_ms")
- .allowlist_function("mp_hal_delay_ms")
- // debug
- .allowlist_function("mp_print_strn")
- .allowlist_function("str_modulo_format")
- .allowlist_var("mp_plat_print")
- // typ
- .allowlist_var("mp_type_type")
- // module
- .allowlist_type("mp_obj_module_t")
- .allowlist_var("mp_type_module")
- // qstr
- .allowlist_function("qstr_data")
- // tuple
- .allowlist_type("mp_obj_tuple_t")
- // `ffi::mp_map_t` type is not allowed to be `Clone` or `Copy` because we tie it
- // to the data lifetimes with the `MapRef` type, see `src/micropython/map.rs`.
- // TODO: We should disable `Clone` and `Copy` for all types and only allow-list
- // the specific cases we require.
- .no_copy("_mp_map_t");
-
- // Write the bindings to a file in the OUR_DIR.
- bindings
- .generate()
- .expect("Unable to generate bindings")
- .write_to_file(PathBuf::from(out_dir).join("micropython.rs"))
- .unwrap();
+ lib.add_rust_bindings_ex("micropython", |builder| {
+ Ok(builder
+ .header("micropython.h")
+ // obj
+ .new_type_alias("mp_obj_t")
+ .allowlist_type("mp_obj_type_t")
+ .allowlist_type("mp_obj_base_t")
+ .allowlist_function("mp_obj_new_int")
+ .allowlist_function("mp_obj_new_int_from_ll")
+ .allowlist_function("mp_obj_new_int_from_ull")
+ .allowlist_function("mp_obj_new_int_from_uint")
+ .allowlist_function("mp_obj_new_bytes")
+ .allowlist_function("mp_obj_new_str")
+ .allowlist_function("mp_obj_new_tuple")
+ .allowlist_function("mp_obj_new_attrtuple")
+ .allowlist_function("mp_obj_get_int_maybe")
+ .allowlist_function("mp_obj_is_true")
+ .allowlist_function("mp_obj_get_type_str")
+ .allowlist_function("mp_call_function_n_kw")
+ .allowlist_function("trezor_obj_get_ll_checked")
+ .allowlist_function("trezor_obj_str_from_rom_text")
+ // buffer
+ .allowlist_function("mp_obj_new_slice")
+ .allowlist_function("mp_obj_subscr")
+ .allowlist_function("mp_get_buffer")
+ .allowlist_var("MP_BUFFER_READ")
+ .allowlist_var("MP_BUFFER_WRITE")
+ .allowlist_var("mp_type_str")
+ .allowlist_var("mp_type_bytes")
+ .allowlist_var("mp_type_bytearray")
+ .allowlist_var("mp_type_memoryview")
+ // dict
+ .allowlist_type("mp_obj_dict_t")
+ .allowlist_function("mp_obj_new_dict")
+ .allowlist_var("mp_type_dict")
+ // fun
+ .allowlist_type("mp_obj_fun_builtin_fixed_t")
+ .allowlist_var("mp_type_fun_builtin_0")
+ .allowlist_var("mp_type_fun_builtin_1")
+ .allowlist_var("mp_type_fun_builtin_2")
+ .allowlist_var("mp_type_fun_builtin_3")
+ .allowlist_type("mp_obj_fun_builtin_var_t")
+ .allowlist_var("mp_type_fun_builtin_var")
+ // gc
+ .allowlist_function("gc_alloc")
+ .allowlist_function("gc_free")
+ .allowlist_var("GC_ALLOC_FLAG_HAS_FINALISER")
+ // iter
+ .allowlist_type("mp_obj_iter_buf_t")
+ .allowlist_function("mp_getiter")
+ .allowlist_function("mp_iternext")
+ // list
+ .allowlist_type("mp_obj_list_t")
+ .allowlist_function("mp_obj_new_list")
+ .allowlist_function("mp_obj_list_append")
+ .allowlist_function("mp_obj_list_get")
+ .allowlist_function("mp_obj_list_set_len")
+ .allowlist_var("mp_type_list")
+ // map
+ .allowlist_type("mp_map_elem_t")
+ .allowlist_function("mp_map_init")
+ .allowlist_function("mp_map_init_fixed_table")
+ .allowlist_function("mp_map_lookup")
+ // exceptions
+ .allowlist_function("nlr_jump")
+ .allowlist_function("mp_obj_new_exception")
+ .allowlist_function("mp_obj_new_exception_args")
+ .allowlist_function("mp_obj_exception_print")
+ .allowlist_function("mp_obj_exception_attr")
+ .allowlist_function("mp_obj_exception_make_new")
+ .allowlist_function("trezor_obj_call_protected")
+ .allowlist_var("mp_type_AttributeError")
+ .allowlist_var("mp_type_EOFError")
+ .allowlist_var("mp_type_Exception")
+ .allowlist_var("mp_type_IndexError")
+ .allowlist_var("mp_type_KeyError")
+ .allowlist_var("mp_type_MemoryError")
+ .allowlist_var("mp_type_OverflowError")
+ .allowlist_var("mp_type_ValueError")
+ .allowlist_var("mp_type_TypeError")
+ .allowlist_var("mp_type_RuntimeError")
+ .allowlist_var("mp_type_NotImplementedError")
+ // time
+ .allowlist_function("mp_hal_ticks_ms")
+ .allowlist_function("mp_hal_delay_ms")
+ // debug
+ .allowlist_function("mp_print_strn")
+ .allowlist_function("str_modulo_format")
+ .allowlist_var("mp_plat_print")
+ // typ
+ .allowlist_var("mp_type_type")
+ // module
+ .allowlist_type("mp_obj_module_t")
+ .allowlist_var("mp_type_module")
+ // qstr
+ .allowlist_function("qstr_data")
+ // tuple
+ .allowlist_type("mp_obj_tuple_t")
+ // `ffi::mp_map_t` type is not allowed to be `Clone` or `Copy` because we tie it
+ // to the data lifetimes with the `MapRef` type, see `src/micropython/map.rs`.
+ // TODO: We should disable `Clone` and `Copy` for all types and only allow-list
+ // the specific cases we require.
+ .no_copy("_mp_map_t"))
+ })
}
-fn generate_trezorhal_bindings() {
- let out_dir = env::var("OUT_DIR").unwrap();
-
+fn generate_trezorhal_bindings(lib: &mut CLibrary) -> Result<()> {
// Tell cargo to invalidate the built crate whenever the header changes.
println!("cargo:rerun-if-changed=trezorhal.h");
- let bindings = prepare_bindings()
- .header("trezorhal.h")
- // model
- .allowlist_var("MODEL_INTERNAL_NAME")
- .allowlist_var("MODEL_FULL_NAME")
- // secbool
- .allowlist_type("secbool")
- .must_use_type("secbool")
- .allowlist_var("sectrue")
- .allowlist_var("secfalse")
- // storage
- .allowlist_var("EXTERNAL_SALT_SIZE")
- .allowlist_function("storage_setup")
- .allowlist_function("storage_wipe")
- .allowlist_function("storage_is_unlocked")
- .allowlist_function("storage_lock")
- .allowlist_function("storage_unlock")
- .allowlist_function("storage_has_pin")
- .allowlist_function("storage_get_pin_rem")
- .allowlist_function("storage_change_pin")
- .allowlist_function("storage_ensure_not_wipe_code")
- .allowlist_function("storage_has")
- .allowlist_function("storage_get")
- .allowlist_function("storage_set")
- .allowlist_function("storage_delete")
- .allowlist_function("storage_set_counter")
- .allowlist_function("storage_next_counter")
- .allowlist_function("translations_read")
- .allowlist_function("translations_write")
- .allowlist_function("translations_erase")
- .allowlist_function("translations_area_bytesize")
- .allowlist_type("storage_unlock_result_t")
- .rustified_enum("storage_unlock_result_t")
- .allowlist_type("storage_pin_change_result_t")
- .rustified_enum("storage_pin_change_result_t")
- // display
- .allowlist_function("display_refresh")
- .allowlist_function("display_set_backlight")
- .allowlist_function("display_get_backlight")
- .allowlist_function("display_wait_for_sync")
- .allowlist_var("DISPLAY_RESX_")
- .allowlist_var("DISPLAY_RESY_")
- .allowlist_type("display_fb_info_t")
- .allowlist_function("display_get_frame_buffer")
- .allowlist_function("display_fill")
- .allowlist_function("display_copy_rgb565")
- .allowlist_function("display_is_recording")
- .allowlist_function("display_record_screen")
- // gfx_bitblt
- .allowlist_type("gfx_bitblt_t")
- .allowlist_function("gfx_rgb565_fill")
- .allowlist_function("gfx_rgb565_copy_mono4")
- .allowlist_function("gfx_rgb565_copy_rgb565")
- .allowlist_function("gfx_rgb565_blend_mono4")
- .allowlist_function("gfx_rgb565_blend_mono8")
- .allowlist_function("gfx_rgba8888_fill")
- .allowlist_function("gfx_rgba8888_copy_mono4")
- .allowlist_function("gfx_rgba8888_copy_rgb565")
- .allowlist_function("gfx_rgba8888_copy_rgba8888")
- .allowlist_function("gfx_rgba8888_blend_mono4")
- .allowlist_function("gfx_rgba8888_blend_mono8")
- .allowlist_function("gfx_mono8_fill")
- .allowlist_function("gfx_mono8_copy_mono1p")
- .allowlist_function("gfx_mono8_copy_mono4")
- .allowlist_function("gfx_mono8_blend_mono1p")
- .allowlist_function("gfx_mono8_blend_mono4")
- .allowlist_function("gfx_bitblt_wait")
- // uzlib
- .allowlist_function("uzlib_uncompress_init")
- .allowlist_function("uzlib_uncompress")
- // bip39
- .allowlist_function("mnemonic_word_completion_mask")
- .allowlist_var("BIP39_WORDLIST_ENGLISH")
- .allowlist_var("BIP39_WORD_COUNT")
- // slip39
- .allowlist_function("slip39_word_completion_mask")
- .allowlist_function("button_sequence_to_word")
- .allowlist_var("SLIP39_WORDLIST")
- .allowlist_var("SLIP39_WORD_COUNT")
- // random
- .allowlist_function("random_buffer")
- .allowlist_function("random_uniform")
- // rgb led
- .allowlist_type("rgb_led_effect_type_t")
- .allowlist_function("rgb_led_set_color")
- .allowlist_function("rgb_led_effect_start")
- .allowlist_function("rgb_led_effect_stop")
- .allowlist_function("rgb_led_effect_ongoing")
- .allowlist_function("rgb_led_effect_get_type")
- // systick
- .allowlist_function("systick_delay_ms")
- .allowlist_function("systick_ms")
- .allowlist_function("systick_us")
- // toif
- .allowlist_type("toif_format_t")
- //usb
- .allowlist_type("usb_event_t")
- .allowlist_function("usb_get_state")
- // ble
- .allowlist_var("BLE_MAX_BONDS")
- .allowlist_var("BLE_PAIRING_CODE_LEN")
- .allowlist_var("BLE_RX_PACKET_SIZE")
- .allowlist_var("BLE_TX_PACKET_SIZE")
- .allowlist_var("BLE_ADV_NAME_LEN")
- .allowlist_function("ble_get_state")
- .allowlist_function("ble_get_event")
- .allowlist_function("ble_switch_on")
- .allowlist_function("ble_switch_off")
- .allowlist_function("ble_enter_pairing_mode")
- .allowlist_function("ble_disconnect")
- .allowlist_function("ble_set_name")
- .allowlist_function("ble_erase_bonds")
- .allowlist_function("ble_allow_pairing")
- .allowlist_function("ble_reject_pairing")
- .allowlist_function("ble_start")
- .allowlist_function("ble_write")
- .allowlist_function("ble_read")
- .allowlist_function("ble_set_name")
- .allowlist_function("ble_unpair")
- .allowlist_function("ble_get_bond_list")
- .allowlist_function("ble_set_high_speed")
- .allowlist_function("ble_set_enabled")
- .allowlist_function("ble_get_enabled")
- .allowlist_type("ble_command_t")
- .allowlist_type("ble_state_t")
- .allowlist_type("ble_event_t")
- .allowlist_type("bt_le_addr_t")
- // touch
- .allowlist_function("touch_get_event")
- // button
- .allowlist_type("button_t")
- .allowlist_type("button_event_t")
- .allowlist_function("button_get_event")
- // haptic
- .allowlist_type("haptic_effect_t")
- .allowlist_function("haptic_play")
- .allowlist_function("haptic_play_custom")
- // jpegdec
- .allowlist_var("JPEGDEC_RGBA8888_BUFFER_SIZE")
- .allowlist_var("JPEGDEC_MONO8_BUFFER_SIZE")
- .allowlist_type("jpegdec_state_t")
- .allowlist_type("jpegdec_image_t")
- .allowlist_type("jpegdec_image_format_t")
- .allowlist_type("jpegdec_slice_t")
- .allowlist_function("jpegdec_open")
- .allowlist_function("jpegdec_close")
- .allowlist_function("jpegdec_process")
- .allowlist_function("jpegdec_get_info")
- .allowlist_function("jpegdec_get_slice_rgba8888")
- .allowlist_function("jpegdec_get_slice_mono8")
- // sysevent
- .allowlist_type("syshandle_t")
- .allowlist_type("sysevents_t")
- .allowlist_function("sysevents_poll")
- // power manager
- .allowlist_type("pm_event_t")
- .allowlist_function("pm_get_events")
- .allowlist_function("pm_get_state")
- .allowlist_function("pm_suspend")
- .allowlist_function("pm_hibernate")
- .allowlist_function("pm_charging_enable")
- .allowlist_function("pm_charging_disable")
- // irq
- .allowlist_function("irq_lock_fn")
- .allowlist_function("irq_unlock_fn")
- // nrf
- .allowlist_function("nrf_send_uart_data")
- // syslog
- .allowlist_function("syslog_start_record")
- .allowlist_function("syslog_write_chunk")
- .allowlist_type("log_source_t")
- .allowlist_type("log_level_t")
- .allowlist_var("LOG_LEVEL_DBG")
- .allowlist_var("LOG_LEVEL_INF")
- .allowlist_var("LOG_LEVEL_WARN")
- .allowlist_var("LOG_LEVEL_ERR")
- // c_layout
- .allowlist_type("c_layout_t")
- .allowlist_function("bootloader_process_ble")
- .allowlist_function("bootloader_process_usb")
- .allowlist_function("debuglink_process")
- .allowlist_function("debuglink_notify_layout_change");
-
- // Write the bindings to a file in the OUR_DIR.
- bindings
- .generate()
- .expect("Unable to generate bindings")
- .write_to_file(PathBuf::from(out_dir).join("trezorhal.rs"))
- .unwrap();
-}
-
-fn is_firmware() -> bool {
- let target = env::var("TARGET").unwrap();
- target.starts_with("thumbv7") || target.starts_with("thumbv8")
+ lib.add_rust_bindings_ex("trezorhal", |builder| {
+ Ok(builder
+ .header("trezorhal.h")
+ // model
+ .allowlist_var("MODEL_INTERNAL_NAME")
+ .allowlist_var("MODEL_FULL_NAME")
+ // secbool
+ .allowlist_type("secbool")
+ .must_use_type("secbool")
+ .allowlist_var("sectrue")
+ .allowlist_var("secfalse")
+ // storage
+ .allowlist_var("EXTERNAL_SALT_SIZE")
+ .allowlist_function("storage_setup")
+ .allowlist_function("storage_wipe")
+ .allowlist_function("storage_is_unlocked")
+ .allowlist_function("storage_lock")
+ .allowlist_function("storage_unlock")
+ .allowlist_function("storage_has_pin")
+ .allowlist_function("storage_get_pin_rem")
+ .allowlist_function("storage_change_pin")
+ .allowlist_function("storage_ensure_not_wipe_code")
+ .allowlist_function("storage_has")
+ .allowlist_function("storage_get")
+ .allowlist_function("storage_set")
+ .allowlist_function("storage_delete")
+ .allowlist_function("storage_set_counter")
+ .allowlist_function("storage_next_counter")
+ .allowlist_function("translations_read")
+ .allowlist_function("translations_write")
+ .allowlist_function("translations_erase")
+ .allowlist_function("translations_area_bytesize")
+ .allowlist_type("storage_unlock_result_t")
+ .rustified_enum("storage_unlock_result_t")
+ .allowlist_type("storage_pin_change_result_t")
+ .rustified_enum("storage_pin_change_result_t")
+ // display
+ .allowlist_function("display_refresh")
+ .allowlist_function("display_set_backlight")
+ .allowlist_function("display_get_backlight")
+ .allowlist_function("display_wait_for_sync")
+ .allowlist_var("DISPLAY_RESX_")
+ .allowlist_var("DISPLAY_RESY_")
+ .allowlist_type("display_fb_info_t")
+ .allowlist_function("display_get_frame_buffer")
+ .allowlist_function("display_fill")
+ .allowlist_function("display_copy_rgb565")
+ .allowlist_function("display_is_recording")
+ .allowlist_function("display_record_screen")
+ // gfx_bitblt
+ .allowlist_type("gfx_bitblt_t")
+ .allowlist_function("gfx_rgb565_fill")
+ .allowlist_function("gfx_rgb565_copy_mono4")
+ .allowlist_function("gfx_rgb565_copy_rgb565")
+ .allowlist_function("gfx_rgb565_blend_mono4")
+ .allowlist_function("gfx_rgb565_blend_mono8")
+ .allowlist_function("gfx_rgba8888_fill")
+ .allowlist_function("gfx_rgba8888_copy_mono4")
+ .allowlist_function("gfx_rgba8888_copy_rgb565")
+ .allowlist_function("gfx_rgba8888_copy_rgba8888")
+ .allowlist_function("gfx_rgba8888_blend_mono4")
+ .allowlist_function("gfx_rgba8888_blend_mono8")
+ .allowlist_function("gfx_mono8_fill")
+ .allowlist_function("gfx_mono8_copy_mono1p")
+ .allowlist_function("gfx_mono8_copy_mono4")
+ .allowlist_function("gfx_mono8_blend_mono1p")
+ .allowlist_function("gfx_mono8_blend_mono4")
+ .allowlist_function("gfx_bitblt_wait")
+ // uzlib
+ .allowlist_function("uzlib_uncompress_init")
+ .allowlist_function("uzlib_uncompress")
+ // bip39
+ .allowlist_function("mnemonic_word_completion_mask")
+ .allowlist_var("BIP39_WORDLIST_ENGLISH")
+ .allowlist_var("BIP39_WORD_COUNT")
+ // slip39
+ .allowlist_function("slip39_word_completion_mask")
+ .allowlist_function("button_sequence_to_word")
+ .allowlist_var("SLIP39_WORDLIST")
+ .allowlist_var("SLIP39_WORD_COUNT")
+ // random
+ .allowlist_function("random_buffer")
+ .allowlist_function("random_uniform")
+ // rgb led
+ .allowlist_type("rgb_led_effect_type_t")
+ .allowlist_function("rgb_led_set_color")
+ .allowlist_function("rgb_led_effect_start")
+ .allowlist_function("rgb_led_effect_stop")
+ .allowlist_function("rgb_led_effect_ongoing")
+ .allowlist_function("rgb_led_effect_get_type")
+ // systick
+ .allowlist_function("systick_delay_ms")
+ .allowlist_function("systick_ms")
+ .allowlist_function("systick_us")
+ // toif
+ .allowlist_type("toif_format_t")
+ //usb
+ .allowlist_type("usb_event_t")
+ .allowlist_function("usb_get_state")
+ // ble
+ .allowlist_var("BLE_MAX_BONDS")
+ .allowlist_var("BLE_PAIRING_CODE_LEN")
+ .allowlist_var("BLE_RX_PACKET_SIZE")
+ .allowlist_var("BLE_TX_PACKET_SIZE")
+ .allowlist_var("BLE_ADV_NAME_LEN")
+ .allowlist_function("ble_get_state")
+ .allowlist_function("ble_get_event")
+ .allowlist_function("ble_switch_on")
+ .allowlist_function("ble_switch_off")
+ .allowlist_function("ble_enter_pairing_mode")
+ .allowlist_function("ble_disconnect")
+ .allowlist_function("ble_set_name")
+ .allowlist_function("ble_erase_bonds")
+ .allowlist_function("ble_allow_pairing")
+ .allowlist_function("ble_reject_pairing")
+ .allowlist_function("ble_start")
+ .allowlist_function("ble_write")
+ .allowlist_function("ble_read")
+ .allowlist_function("ble_set_name")
+ .allowlist_function("ble_unpair")
+ .allowlist_function("ble_get_bond_list")
+ .allowlist_function("ble_set_high_speed")
+ .allowlist_function("ble_set_enabled")
+ .allowlist_function("ble_get_enabled")
+ .allowlist_type("ble_command_t")
+ .allowlist_type("ble_state_t")
+ .allowlist_type("ble_event_t")
+ .allowlist_type("bt_le_addr_t")
+ // touch
+ .allowlist_function("touch_get_event")
+ // button
+ .allowlist_type("button_t")
+ .allowlist_type("button_event_t")
+ .allowlist_function("button_get_event")
+ // haptic
+ .allowlist_type("haptic_effect_t")
+ .allowlist_function("haptic_play")
+ .allowlist_function("haptic_play_custom")
+ // jpegdec
+ .allowlist_var("JPEGDEC_RGBA8888_BUFFER_SIZE")
+ .allowlist_var("JPEGDEC_MONO8_BUFFER_SIZE")
+ .allowlist_type("jpegdec_state_t")
+ .allowlist_type("jpegdec_image_t")
+ .allowlist_type("jpegdec_image_format_t")
+ .allowlist_type("jpegdec_slice_t")
+ .allowlist_function("jpegdec_open")
+ .allowlist_function("jpegdec_close")
+ .allowlist_function("jpegdec_process")
+ .allowlist_function("jpegdec_get_info")
+ .allowlist_function("jpegdec_get_slice_rgba8888")
+ .allowlist_function("jpegdec_get_slice_mono8")
+ // sysevent
+ .allowlist_type("syshandle_t")
+ .allowlist_type("sysevents_t")
+ .allowlist_function("sysevents_poll")
+ // power manager
+ .allowlist_type("pm_event_t")
+ .allowlist_function("pm_get_events")
+ .allowlist_function("pm_get_state")
+ .allowlist_function("pm_suspend")
+ .allowlist_function("pm_hibernate")
+ .allowlist_function("pm_charging_enable")
+ .allowlist_function("pm_charging_disable")
+ // irq
+ .allowlist_function("irq_lock_fn")
+ .allowlist_function("irq_unlock_fn")
+ // nrf
+ .allowlist_function("nrf_send_uart_data")
+ // c_layout
+ .allowlist_type("c_layout_t")
+ .allowlist_function("bootloader_process_ble")
+ .allowlist_function("bootloader_process_usb")
+ .allowlist_function("debuglink_process")
+ .allowlist_function("debuglink_notify_layout_change"))
+ })
}
-#[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);
-
- // List of object filenames to ignore in the `embed` directory
- let embed_blocklist = [OsStr::new("main_main.o")];
-
- // Collect all objects that the `core` library uses, and link it in. We have to
- // make sure to avoid the object with the `_main` symbol, so we don't get any
- // duplicates.
- let mut cc = cc::Build::new();
- for obj in glob::glob(&format!("{}/embed/**/*.o", build_path)).unwrap() {
- let obj = obj.unwrap();
- if embed_blocklist.contains(&obj.file_name().unwrap()) {
- // Ignore.
- } else {
- cc.object(obj);
- }
- }
-
- for obj in glob::glob(&format!("{}/vendor/**/*.o", build_path)).unwrap() {
- let obj = obj.unwrap();
- cc.object(obj);
- }
-
- // Add frozen modules, if present.
- for obj in glob::glob(&format!("{}/*.o", build_path)).unwrap() {
- cc.object(obj.unwrap());
- }
-
- // Compile all the objects into a static library and link it in automatically.
- cc.compile("core_lib");
-
- println!("cargo:rustc-link-lib=SDL3");
- println!("cargo:rustc-link-lib=SDL3_image");
+fn generate_qstr_bindings(lib: &mut CLibrary) -> Result<()> {
+ // Tell cargo to invalidate the built crate whenever the header changes.
+ println!("cargo:rerun-if-changed=qstr.h");
- #[cfg(any(feature = "ui_jpeg", feature = "hw_jpeg_decoder"))]
- println!("cargo:rustc-link-lib=jpeg");
+ lib.add_rust_bindings_ex("qstr", |builder| {
+ Ok(builder
+ .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,
+ }))
+ })
}
diff --git a/core/embed/rust/qstr.h b/core/embed/rust/qstr.h
index 7e03ae5d..f67ac73e 100644
--- a/core/embed/rust/qstr.h
+++ b/core/embed/rust/qstr.h
@@ -1,4 +1,6 @@
-enum Qstr {
+#include <stddef.h>
+
+enum Qstr : size_t {
// Copied from `vendor/micropython/py/qstr.h`:
diff --git a/core/embed/rust/src/protobuf/defs.rs b/core/embed/rust/src/protobuf/defs.rs
index 8c484751..4d93247c 100644
--- a/core/embed/rust/src/protobuf/defs.rs
+++ b/core/embed/rust/src/protobuf/defs.rs
@@ -2,14 +2,6 @@ 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)
diff --git a/core/embed/rust/src/test_setup.c b/core/embed/rust/src/test_setup.c
new file mode 100644
index 00000000..35d182d0
--- /dev/null
+++ b/core/embed/rust/src/test_setup.c
@@ -0,0 +1,78 @@
+/*
+ * 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/>.
+ */
+
+#include <trezor_rtl.h>
+
+#include <io/display.h>
+#include <io/usb_config.h>
+#include <sec/unit_properties.h>
+#include <sys/flash.h>
+#include <sys/flash_otp.h>
+#include <sys/system.h>
+
+#ifdef USE_BUTTON
+#include <io/button.h>
+#endif
+
+#ifdef USE_TOUCH
+#include <io/touch.h>
+#endif
+
+#ifdef USE_TROPIC
+#include <sec/tropic.h>
+#endif
+
+#include <stdlib.h>
+#include "py/builtin.h"
+
+void rust_tests_c_setup(void) {
+ system_init(NULL);
+
+ flash_init();
+ flash_otp_init();
+
+ unit_properties_init();
+
+ display_init(DISPLAY_RESET_CONTENT);
+
+#if USE_TOUCH
+ touch_init();
+#endif
+
+#ifdef USE_BUTTON
+ button_init();
+#endif
+
+#ifdef USE_TROPIC
+ tropic_init(NULL);
+#endif
+
+ usb_configure(NULL);
+}
+
+void nlr_jump_fail(void *val) {
+ printf("FATAL: uncaught NLR %p\n", val);
+ exit(1);
+}
+
+static void stderr_print_strn(void *env, const char *str, size_t len) {
+ printf("%.*s", (int)len, str);
+}
+
+const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h
index b7387146..2317d2c1 100644
--- a/core/embed/rust/trezorhal.h
+++ b/core/embed/rust/trezorhal.h
@@ -56,8 +56,8 @@
#endif
#ifdef BOOTLOADER
-#include "workflow/debuglink.h"
-#include "workflow/workflow_common.h"
+#include "../projects/bootloader/workflow/debuglink.h"
+#include "../projects/bootloader/workflow/workflow_common.h"
#endif
#include "bip39.h"
diff --git a/core/embed/xbuild/src/clibrary/mod.rs b/core/embed/xbuild/src/clibrary/mod.rs
index b35ac3ee..548d57bc 100644
--- a/core/embed/xbuild/src/clibrary/mod.rs
+++ b/core/embed/xbuild/src/clibrary/mod.rs
@@ -3,6 +3,7 @@ pub mod compile;
pub mod embed;
pub mod rust_bindings;
+use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use color_eyre::Result;
@@ -51,8 +52,9 @@ pub struct CLibrary {
// from other crates and libraries imported via `pkg-config`.
external_libs: Vec<String>,
- // Builder for generating Rust bindings to this library.
- builder: Option<bindgen::Builder>,
+ // Builders for generating Rust bindings to this library, keyed by output
+ // filename.
+ builders: BTreeMap<String, bindgen::Builder>,
}
impl CLibrary {
@@ -70,7 +72,7 @@ impl CLibrary {
public_attrs: CompileAttrs::default(),
libs: Vec::new(),
external_libs: Vec::new(),
- builder: None,
+ builders: BTreeMap::new(),
}
}
diff --git a/core/embed/xbuild/src/clibrary/rust_bindings.rs b/core/embed/xbuild/src/clibrary/rust_bindings.rs
index 288d1b0c..9be8c89e 100644
--- a/core/embed/xbuild/src/clibrary/rust_bindings.rs
+++ b/core/embed/xbuild/src/clibrary/rust_bindings.rs
@@ -6,23 +6,41 @@ use super::CLibrary;
use crate::helpers::{links_name, path_from_env};
impl CLibrary {
- /// Configures the bindgen builder with the provided function, allowing
- /// users to customize the generation of Rust bindings. The function takes
- /// a `bindgen::Builder` as input and returns a modified builder.
+ /// Configures the default bindgen builder with the provided function.
+ ///
+ /// The function takes a `bindgen::Builder` as input and returns a modified
+ /// builder. The generated bindings use the default output filename.
pub fn add_rust_bindings(
&mut self,
func: impl FnOnce(bindgen::Builder) -> Result<bindgen::Builder>,
) -> Result<()> {
- let builder = self.builder.take().unwrap_or_default();
- self.builder = Some(func(builder)?);
+ let name = links_name()?;
+ self.add_rust_bindings_ex(&name, func)
+ }
+
+ /// Configures a named bindgen builder with the provided function.
+ ///
+ /// The generated bindings are written to `<name>.rs` in `OUT_DIR`.
+ pub fn add_rust_bindings_ex(
+ &mut self,
+ name: &str,
+ func: impl FnOnce(bindgen::Builder) -> Result<bindgen::Builder>,
+ ) -> Result<()> {
+ let filename = format!("{name}.rs");
+ let builder = self.builders.remove(&filename).unwrap_or_default();
+ self.builders.insert(filename, func(builder)?);
Ok(())
}
- /// Generates rust bininding (a .rs file) from the configured builder and
- /// writes it to the OUT_DIR.
+ /// Generates Rust bindings from all configured builders and writes them to
+ /// the `OUT_DIR`.
pub(crate) fn generate_rust_bindings(&mut self, use_cc_includes: bool) -> Result<()> {
- let out_file = path_from_env("OUT_DIR")?.join(links_name()? + ".rs");
- let content = if let Some(builder) = self.builder.take() {
+ let out_dir = path_from_env("OUT_DIR")?;
+ let default_filename = format!("{}.rs", links_name()?);
+ let builders = std::mem::take(&mut self.builders);
+ let has_default_builder = builders.contains_key(&default_filename);
+
+ if !builders.is_empty() {
let mut attrs = self.get_merged_attrs();
if use_cc_includes {
@@ -36,35 +54,39 @@ impl CLibrary {
attrs.remove_flag("-mcmse");
attrs.remove_flag("-fsingle-precision-constant");
- let mut content = Vec::<u8>::new();
- builder
- .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()))
- .generate()
- .context("Unable to generate bindings")?
- .write(Box::new(&mut content))
- .context("Unable to write bindings to a buffer")?;
+ for (filename, builder) in builders {
+ let mut content = Vec::<u8>::new();
+ builder
+ .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()))
+ .generate()
+ .context("Unable to generate bindings")?
+ .write(Box::new(&mut content))
+ .context("Unable to write bindings to a buffer")?;
- content
- } else {
- // just empty file
- Vec::<u8>::new()
- };
+ // Bindgen writes the output file even if the content is unchanged,
+ // which causes unnecessary recompilations. To avoid this, we
+ // compare the generated file with the existing one and only replace
+ // it if there are changes.
+ maybe_replace(content, &out_dir.join(filename))?;
+ }
+ }
- // Bindgen writes the output file even if the content is unchanged,
- // which causes unnecessary recompilations. To avoid this, we
- // compare the generated file with the existing one and only replace
- // it if there are changes.
- maybe_replace(content, &out_file)?;
+ // Keep creating an empty default bindings file for crates without a
+ // default bindgen configuration, preserving the existing build-script
+ // contract.
+ if !has_default_builder {
+ maybe_replace(Vec::new(), &out_dir.join(default_filename))?;
+ }
Ok(())
}
}
diff --git a/core/embed/xtask/src/cargo.rs b/core/embed/xtask/src/cargo.rs
index 5d57834f..a7d2710c 100644
--- a/core/embed/xtask/src/cargo.rs
+++ b/core/embed/xtask/src/cargo.rs
@@ -33,14 +33,9 @@ pub fn test(args: TestArgs) -> Result<()> {
for package in &args.packages {
let mut cmd = process::Command::new("cargo");
- let test_feature = match package.as_str() {
- "trezor_lib" => "test_with_new_crates",
- _ => "test",
- };
-
cmd.arg("test")
.args(["--package", package])
- .args(["--features", test_feature])
+ .args(["--features", "test"])
.arg("--")
.arg("--test-threads=1")
.arg("--nocapture")
Why this scored 15/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.