refactor(core/build): stop treating emulator as a separate HW board, instead use it to emulate the selected board
What changed, and why it matters
This commit is a build-system cleanup. It removes separate 'emulator board' configuration files and instead makes the emulator reuse the real hardware board's settings, only swapping in a special emulator header and the Unix display/touch drivers. There is no user-facing change or security fix visible in the diff.
No security action required. Treat as ordinary build-refactor review; verify emulator builds still match intended hardware behavior in CI.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The refactor eliminates per-model unix.toml board definitions and the emulator_board field in model.toml. Board configs now carry an optional emulator_header; xtask selects that header when args.emulator is true but otherwise resolves the same board features as hardware builds. display/build.rs and touch/build.rs now key off the emulator feature rather than display_unix/touch_unix to choose the Unix driver, while still inheriting the emulated board’s panel and framebuffer configuration. Cargo features display_unix and touch_unix are removed.
Changed components
core/embed/io/Cargo.tomlcore/embed/io/display/build.rscore/embed/io/touch/build.rscore/embed/models/*/boards/*.tomlcore/embed/models/*/model.tomlcore/embed/xtask/src/config.rscore/embed/xtask/src/feature_resolver.rsInspect captured patch +51 / −123
diff --git a/core/embed/io/Cargo.toml b/core/embed/io/Cargo.toml
index 0d20183f..4519fa26 100644
--- a/core/embed/io/Cargo.toml
+++ b/core/embed/io/Cargo.toml
@@ -101,9 +101,9 @@ framebuffer = []
# Drivers below that always need framebuffer pull it in implicitly,
# so any project selecting them via the board peripheral chain doesn't have
-# to also advertise `framebuffer` in its target.toml. display_unix and
-# display_st7789 support both modes — the model.toml decides.
-display_unix = []
+# to also advertise `framebuffer` in its target.toml. display_st7789 supports
+# both modes — the model.toml decides.
+# The emulator's unix driver is selected by display/build.rs (not a feature).
display_ltdc_dsi = ["framebuffer"]
display_st7789 = []
display_vg2864 = ["framebuffer"]
@@ -115,8 +115,3 @@ display_panel_t2t1 = []
display_panel_lx154a2482 = []
display_panel_vg2864 = []
-touch_unix = []
-
-
-
-
diff --git a/core/embed/io/display/build.rs b/core/embed/io/display/build.rs
index cca2c805..4201abff 100644
--- a/core/embed/io/display/build.rs
+++ b/core/embed/io/display/build.rs
@@ -19,7 +19,9 @@ pub fn def_module(lib: &mut CLibrary) -> Result<()> {
lib.add_define("FRAMEBUFFER", Some("1"));
}
- if cfg!(feature = "display_unix") {
+ if cfg!(feature = "emulator") {
+ // The emulator reuses the emulated board's display configuration (panel,
+ // framebuffer) but always builds the unix driver instead of the HW one.
add_driver_unix(lib)?;
} else if cfg!(feature = "display_ltdc_dsi") {
add_driver_ltdc_dsi(lib)?;
diff --git a/core/embed/io/touch/build.rs b/core/embed/io/touch/build.rs
index 7c115af1..8bcc6ced 100644
--- a/core/embed/io/touch/build.rs
+++ b/core/embed/io/touch/build.rs
@@ -18,7 +18,8 @@ pub fn def_module(lib: &mut CLibrary) -> Result<()> {
lib.add_define("USE_TOUCH_WAKEUP", Some("1"));
}
- if cfg!(feature = "touch_unix") {
+ if cfg!(feature = "emulator") {
+ // The emulator always builds the unix touch driver instead of the HW one.
lib.add_source("touch/unix/touch.c");
} else if cfg!(feature = "touch_ft3168") {
lib.add_define("TOUCH_WAKEUP_ENABLED", Some("0"));
diff --git a/core/embed/models/T2B1/boards/rev10.toml b/core/embed/models/T2B1/boards/rev10.toml
index b71e77cc..1b39764f 100644
--- a/core/embed/models/T2B1/boards/rev10.toml
+++ b/core/embed/models/T2B1/boards/rev10.toml
@@ -1,4 +1,5 @@
header = "T2B1/boards/trezor_r_v10.h"
+emulator_header = "T2B1/boards/t2b1-unix.h"
[display]
driver = "io/display_vg2864"
diff --git a/core/embed/models/T2B1/boards/unix.toml b/core/embed/models/T2B1/boards/unix.toml
deleted file mode 100644
index 32b7760e..00000000
--- a/core/embed/models/T2B1/boards/unix.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-header = "T2B1/boards/t2b1-unix.h"
-
-[display]
-driver = "display_unix"
-panel = "display_panel_vg2864"
-
-[button]
-
-[optiga]
-
-[sbu]
diff --git a/core/embed/models/T2B1/model.toml b/core/embed/models/T2B1/model.toml
index 2fa4d764..7747fe62 100644
--- a/core/embed/models/T2B1/model.toml
+++ b/core/embed/models/T2B1/model.toml
@@ -1,6 +1,5 @@
mcu = "stm32f427"
default_board = "rev10"
-emulator_board = "unix"
features = [
"consumption_mask",
diff --git a/core/embed/models/T2T1/boards/hw.toml b/core/embed/models/T2T1/boards/hw.toml
index e7f17b58..30740d47 100644
--- a/core/embed/models/T2T1/boards/hw.toml
+++ b/core/embed/models/T2T1/boards/hw.toml
@@ -1,4 +1,5 @@
header = "T2T1/boards/trezor_t.h"
+emulator_header = "T2T1/boards/t2t1-unix.h"
[display]
driver = "io/display_st7789"
diff --git a/core/embed/models/T2T1/boards/unix.toml b/core/embed/models/T2T1/boards/unix.toml
deleted file mode 100644
index 58cd7f7b..00000000
--- a/core/embed/models/T2T1/boards/unix.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-header = "T2T1/boards/t2t1-unix.h"
-
-[display]
-driver = "display_unix"
-panel = "display_panel_t2t1"
-
-[backlight]
-
-[touch]
-driver = "touch_unix"
-
-[sd_card]
-
-[sbu]
diff --git a/core/embed/models/T2T1/model.toml b/core/embed/models/T2T1/model.toml
index e6611025..9082154e 100644
--- a/core/embed/models/T2T1/model.toml
+++ b/core/embed/models/T2T1/model.toml
@@ -1,6 +1,5 @@
mcu = "stm32f427"
default_board = "hw"
-emulator_board = "unix"
features = [
"dma2d",
diff --git a/core/embed/models/T3B1/boards/revB.toml b/core/embed/models/T3B1/boards/revB.toml
index 41c6d4fe..10aad0fc 100644
--- a/core/embed/models/T3B1/boards/revB.toml
+++ b/core/embed/models/T3B1/boards/revB.toml
@@ -1,4 +1,5 @@
header = "T3B1/boards/trezor_t3b1_revB.h"
+emulator_header = "T3B1/boards/t3b1-unix.h"
[display]
driver = "io/display_vg2864"
diff --git a/core/embed/models/T3B1/boards/unix.toml b/core/embed/models/T3B1/boards/unix.toml
deleted file mode 100644
index 99f5bc64..00000000
--- a/core/embed/models/T3B1/boards/unix.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-header = "T3B1/boards/t3b1-unix.h"
-
-[display]
-driver = "display_unix"
-panel = "display_panel_vg2864"
-
-[button]
-
-[optiga]
-
-[sbu]
diff --git a/core/embed/models/T3B1/model.toml b/core/embed/models/T3B1/model.toml
index d1c38414..c31cb702 100644
--- a/core/embed/models/T3B1/model.toml
+++ b/core/embed/models/T3B1/model.toml
@@ -1,6 +1,5 @@
mcu = "stm32u58"
default_board = "revB"
-emulator_board = "unix"
features = [
"consumption_mask",
diff --git a/core/embed/models/T3T1/boards/revE.toml b/core/embed/models/T3T1/boards/revE.toml
index ef3ae188..6bef27b0 100644
--- a/core/embed/models/T3T1/boards/revE.toml
+++ b/core/embed/models/T3T1/boards/revE.toml
@@ -1,4 +1,5 @@
header = "T3T1/boards/trezor_t3t1_revE.h"
+emulator_header = "T3T1/boards/t3t1-unix.h"
[display]
driver = "io/display_st7789"
diff --git a/core/embed/models/T3T1/boards/unix.toml b/core/embed/models/T3T1/boards/unix.toml
deleted file mode 100644
index 6e6f5714..00000000
--- a/core/embed/models/T3T1/boards/unix.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-header = "T3T1/boards/t3t1-unix.h"
-
-[display]
-driver = "display_unix"
-panel = "display_panel_lx154a2482"
-
-[backlight]
-
-[touch]
-driver = "touch_unix"
-
-[haptic]
-
-[sd_card]
-
-[optiga]
-
-[sbu]
diff --git a/core/embed/models/T3T1/model.toml b/core/embed/models/T3T1/model.toml
index d53cad71..43c57ac7 100644
--- a/core/embed/models/T3T1/model.toml
+++ b/core/embed/models/T3T1/model.toml
@@ -1,6 +1,5 @@
mcu = "stm32u58"
default_board = "revE"
-emulator_board = "unix"
features = [
"dma2d",
diff --git a/core/embed/models/T3W1/boards/revA.toml b/core/embed/models/T3W1/boards/revA.toml
index d8590e40..cbfd99d3 100644
--- a/core/embed/models/T3W1/boards/revA.toml
+++ b/core/embed/models/T3W1/boards/revA.toml
@@ -1,4 +1,5 @@
header = "T3W1/boards/trezor_t3w1_revA.h"
+emulator_header = "T3W1/boards/t3w1-unix.h"
[display]
driver = "io/display_ltdc_dsi"
diff --git a/core/embed/models/T3W1/boards/revB.toml b/core/embed/models/T3W1/boards/revB.toml
index 5948093a..1035c76d 100644
--- a/core/embed/models/T3W1/boards/revB.toml
+++ b/core/embed/models/T3W1/boards/revB.toml
@@ -1,4 +1,5 @@
header = "T3W1/boards/trezor_t3w1_revB.h"
+emulator_header = "T3W1/boards/t3w1-unix.h"
[display]
driver = "io/display_ltdc_dsi"
diff --git a/core/embed/models/T3W1/boards/revC.toml b/core/embed/models/T3W1/boards/revC.toml
index ec51a558..01f6f20e 100644
--- a/core/embed/models/T3W1/boards/revC.toml
+++ b/core/embed/models/T3W1/boards/revC.toml
@@ -1,4 +1,5 @@
header = "T3W1/boards/trezor_t3w1_revC.h"
+emulator_header = "T3W1/boards/t3w1-unix.h"
[display]
driver = "io/display_ltdc_dsi"
diff --git a/core/embed/models/T3W1/boards/unix.toml b/core/embed/models/T3W1/boards/unix.toml
deleted file mode 100644
index ec8de698..00000000
--- a/core/embed/models/T3W1/boards/unix.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-header = "T3W1/boards/t3w1-unix.h"
-
-[display]
-driver = "display_unix"
-panel = "display_panel_lx250a2401a"
-
-[backlight]
-
-[touch]
-driver = "touch_unix"
-
-[button]
-
-[haptic]
-
-[ble]
-
-[nrf]
-
-[nrf_auth]
-
-[rgb_led]
-
-[power_manager]
-
-[nfc]
-
-[optiga]
-
-[tropic]
-
-[sbu]
diff --git a/core/embed/models/T3W1/model.toml b/core/embed/models/T3W1/model.toml
index 9d9dc7c8..61f79fea 100644
--- a/core/embed/models/T3W1/model.toml
+++ b/core/embed/models/T3W1/model.toml
@@ -1,6 +1,5 @@
mcu = "stm32u5g"
default_board = "revC"
-emulator_board = "unix"
secmon = true
bootloader_header_tool = "headertool_pq"
diff --git a/core/embed/xtask/src/config.rs b/core/embed/xtask/src/config.rs
index 33bf214f..1f473c30 100644
--- a/core/embed/xtask/src/config.rs
+++ b/core/embed/xtask/src/config.rs
@@ -13,7 +13,6 @@ pub struct ModelConfig {
pub model_id: String,
pub mcu: String,
pub default_board: String,
- pub emulator_board: Option<String>,
pub features: Vec<String>,
#[serde(default)]
pub secmon: bool,
@@ -70,6 +69,10 @@ pub struct Peripheral {
pub struct BoardConfig {
pub header: String,
+ /// Header with the emulator configuration for this board. Present only for
+ /// boards that support being emulated; selected instead of `header` when
+ /// building the emulator.
+ pub emulator_header: Option<String>,
pub peripherals: Vec<Peripheral>,
}
@@ -98,9 +101,14 @@ impl BoardConfig {
.ok_or_else(|| anyhow!("Board config missing 'header' field"))?
.to_string();
+ let emulator_header = table
+ .get("emulator_header")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string());
+
let mut peripherals = Vec::new();
for (key, val) in table {
- if key == "header" {
+ if key == "header" || key == "emulator_header" {
continue;
}
let periph_table = val
@@ -119,6 +127,7 @@ impl BoardConfig {
Ok(BoardConfig {
header,
+ emulator_header,
peripherals,
})
}
@@ -171,6 +180,7 @@ pub fn resolve_board_features(
model_config: &ModelConfig,
board_id: &str,
component: Component,
+ emulator: bool,
) -> Result<BoardFeatures> {
let board_config = BoardConfig::load(&model_config.model_id, board_id)?;
let target_profile = TargetProfile::load(component)?;
@@ -210,8 +220,21 @@ pub fn resolve_board_features(
// MCU feature
features.push(model_config.mcu_feature());
+ // The emulator reuses the emulated board's feature set but swaps in the
+ // board's emulator configuration header.
+ let board_header = if emulator {
+ board_config.emulator_header.ok_or_else(|| {
+ anyhow!(
+ "Board '{board_id}' of model '{}' does not support emulation (missing 'emulator_header')",
+ model_config.model_id
+ )
+ })?
+ } else {
+ board_config.header
+ };
+
Ok(BoardFeatures {
features,
- board_header: board_config.header,
+ board_header,
})
}
diff --git a/core/embed/xtask/src/feature_resolver.rs b/core/embed/xtask/src/feature_resolver.rs
index e92af9fa..44518b0f 100644
--- a/core/embed/xtask/src/feature_resolver.rs
+++ b/core/embed/xtask/src/feature_resolver.rs
@@ -1,4 +1,4 @@
-use anyhow::{Result, anyhow, bail};
+use anyhow::{Result, bail};
use std::process;
use crate::{
@@ -139,25 +139,16 @@ pub fn resolve_features(args: &BuildArgs) -> Result<ResolvedBuild> {
features.push("frozen".into());
}
- // Board and model-intrinsic features from TOML config
+ // Board and model-intrinsic features from TOML config. The emulator emulates
+ // the same board it would build for on real hardware (`default_board`, or an
+ // explicit `--board`); only the configuration header differs.
let model_config = args.model.config()?;
- let board_id = if args.emulator {
- model_config
- .emulator_board
- .as_deref()
- .ok_or_else(|| anyhow!("Model {} has no emulator board", args.model.model_id()))?
- .to_string()
- } else {
- args.board
- .clone()
- .unwrap_or_else(|| model_config.default_board.clone())
- };
- let board_features = config::resolve_board_features(
- args.model.model_id(),
- &model_config,
- &board_id,
- args.component,
- )?;
+ let board_id = args
+ .board
+ .clone()
+ .unwrap_or_else(|| model_config.default_board.clone());
+ let board_features =
+ config::resolve_board_features(&model_config, &board_id, args.component, args.emulator)?;
let mut board_feat = board_features.features;
if args.disable_optiga {
board_feat.retain(|f| f != "optiga");
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.