refactor(core): move hw_revision to sec layer
What changed, and why it matters
This commit is a straightforward internal code reorganization: it moves the hardware revision detection module from a general utility folder into the security (sec) layer. The actual logic for reading the hardware revision from GPIO pins is unchanged. There is no user-facing behavior change and no indication of a security fix or vulnerability.
No action required. Treat as routine refactoring. Reviewers may verify that the new `SECURE_MODE` guard and TrustZone SECCFGR configuration align with the project's secure-world partitioning expectations.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change relocates hw_revision from core/embed/util/hw_revision/ to core/embed/sys/trustzone/stm32u5/trustzone.c adds TrustZone secure-configuration bits for the hardware revision GPIO ports when USE_HW_REVISION is defined. The implementation is guarded by SECURE_MODE instead of KERNEL_MODE. No functional changes to revision reading, initialization, or deinitialization logic.
Changed components
core/embed/projects/prodtest/cmd/prodtest_hw_revision.ccore/embed/projects/prodtest/main.ccore/embed/sec/hw_revision/inc/sec/hw_revision.hcore/embed/sec/hw_revision/stm32/hw_revision.ccore/embed/sys/trustzone/stm32u5/trustzone.ccore/site_scons/models/T3B1/trezor_t3b1_revB.pycore/site_scons/models/T3T1/trezor_t3t1_revE.pycore/site_scons/models/T3W1/trezor_t3w1_revB.pycore/site_scons/models/T3W1/trezor_t3w1_revC.pyInspect captured patch +162 / −152
diff --git a/core/embed/projects/prodtest/cmd/prodtest_hw_revision.c b/core/embed/projects/prodtest/cmd/prodtest_hw_revision.c
index 9418d448f..5c4ff8225 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_hw_revision.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_hw_revision.c
@@ -20,7 +20,7 @@
#include <trezor_rtl.h>
#include <rtl/cli.h>
-#include <util/hw_revision.h>
+#include <sec/hw_revision.h>
static void prodtest_hw_revision(cli_t* cli) {
uint8_t rev = hw_revision_get();
diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c
index 7f1e9b4e4..c07f7173c 100644
--- a/core/embed/projects/prodtest/main.c
+++ b/core/embed/projects/prodtest/main.c
@@ -102,7 +102,7 @@
#endif
#ifdef USE_HW_REVISION
-#include <util/hw_revision.h>
+#include <sec/hw_revision.h>
#endif
#ifdef USE_TAMPER
diff --git a/core/embed/sec/hw_revision/inc/sec/hw_revision.h b/core/embed/sec/hw_revision/inc/sec/hw_revision.h
new file mode 100644
index 000000000..bccd32209
--- /dev/null
+++ b/core/embed/sec/hw_revision/inc/sec/hw_revision.h
@@ -0,0 +1,28 @@
+/*
+ * 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/>.
+ */
+
+#pragma once
+
+#include <trezor_types.h>
+
+void hw_revision_init(void);
+
+void hw_revision_deinit(void);
+
+uint8_t hw_revision_get(void);
diff --git a/core/embed/sec/hw_revision/stm32/hw_revision.c b/core/embed/sec/hw_revision/stm32/hw_revision.c
new file mode 100644
index 000000000..ffc89f898
--- /dev/null
+++ b/core/embed/sec/hw_revision/stm32/hw_revision.c
@@ -0,0 +1,115 @@
+/*
+ * 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/>.
+ */
+
+#ifdef SECURE_MODE
+
+#include <trezor_bsp.h>
+#include <trezor_model.h>
+#include <trezor_rtl.h>
+
+#include <sec/hw_revision.h>
+
+typedef struct {
+ uint8_t revision;
+ bool initialized;
+} hw_revision_t;
+
+static hw_revision_t g_hw_revision;
+
+static uint8_t hw_revision_read(void) {
+ bool rev0 =
+ GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_0_PORT, HW_REVISION_0_PIN);
+ bool rev1 =
+ GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_1_PORT, HW_REVISION_1_PIN);
+ bool rev2 =
+ GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_2_PORT, HW_REVISION_2_PIN);
+ bool rev3 = false;
+#ifdef HW_REVISION_3_PIN
+ rev3 =
+ GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_3_PORT, HW_REVISION_3_PIN);
+#endif
+
+ uint8_t revision = 0;
+ revision |= rev0 ? 1 : 0;
+ revision |= rev1 ? 2 : 0;
+ revision |= rev2 ? 4 : 0;
+ revision |= rev3 ? 8 : 0;
+
+ return revision;
+}
+
+void hw_revision_init(void) {
+ GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+ HW_REVISION_0_CLOCK_ENABLE();
+ GPIO_InitStructure.Pin = HW_REVISION_0_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStructure.Pull = HW_REVISION_PUPD;
+ GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(HW_REVISION_0_PORT, &GPIO_InitStructure);
+
+ HW_REVISION_1_CLOCK_ENABLE();
+ GPIO_InitStructure.Pin = HW_REVISION_1_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStructure.Pull = HW_REVISION_PUPD;
+ GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(HW_REVISION_1_PORT, &GPIO_InitStructure);
+
+ HW_REVISION_2_CLOCK_ENABLE();
+ GPIO_InitStructure.Pin = HW_REVISION_2_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStructure.Pull = HW_REVISION_PUPD;
+ GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(HW_REVISION_2_PORT, &GPIO_InitStructure);
+
+#ifdef HW_REVISION_3_PIN
+ GPIO_InitStructure.Pin = HW_REVISION_3_PIN;
+ GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStructure.Pull = HW_REVISION_PUPD;
+ GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(HW_REVISION_3_PORT, &GPIO_InitStructure);
+#endif
+
+ memset(&g_hw_revision, 0, sizeof(hw_revision_t));
+ g_hw_revision.revision = hw_revision_read();
+ g_hw_revision.initialized = true;
+
+ // deinit the GPIOs to save power
+ HAL_GPIO_DeInit(HW_REVISION_0_PORT, HW_REVISION_0_PIN);
+ HAL_GPIO_DeInit(HW_REVISION_1_PORT, HW_REVISION_1_PIN);
+ HAL_GPIO_DeInit(HW_REVISION_2_PORT, HW_REVISION_2_PIN);
+#ifdef HW_REVISION_3_PIN
+ HAL_GPIO_DeInit(HW_REVISION_3_PORT, HW_REVISION_3_PIN);
+#endif
+}
+
+void hw_revision_deinit(void) {
+ memset(&g_hw_revision, 0, sizeof(hw_revision_t));
+}
+
+uint8_t hw_revision_get(void) {
+ hw_revision_t *hw_revision = &g_hw_revision;
+ if (!hw_revision->initialized) {
+ hw_revision_init();
+ }
+
+ return hw_revision->revision;
+}
+
+#endif // SECURE_MODE
diff --git a/core/embed/sys/trustzone/stm32u5/trustzone.c b/core/embed/sys/trustzone/stm32u5/trustzone.c
index a2e48bf6f..42de43a8f 100644
--- a/core/embed/sys/trustzone/stm32u5/trustzone.c
+++ b/core/embed/sys/trustzone/stm32u5/trustzone.c
@@ -618,6 +618,15 @@ void tz_init(void) {
GPIOJ->SECCFGR &= ~0xFFFF;
#endif
+#ifdef USE_HW_REVISION
+ HW_REVISION_0_PORT->SECCFGR |= HW_REVISION_0_PIN;
+ HW_REVISION_1_PORT->SECCFGR |= HW_REVISION_1_PIN;
+ HW_REVISION_2_PORT->SECCFGR |= HW_REVISION_2_PIN;
+#ifdef HW_REVISION_3_PIN
+ HW_REVISION_3_PORT->SECCFGR |= HW_REVISION_3_PIN;
+#endif
+#endif
+
#ifdef USE_TAMPER
// Set TAMPER interrupt as secure
NVIC_ClearTargetState(TAMP_IRQn);
diff --git a/core/embed/util/hw_revision/inc/util/hw_revision.h b/core/embed/util/hw_revision/inc/util/hw_revision.h
deleted file mode 100644
index bccd32209..000000000
--- a/core/embed/util/hw_revision/inc/util/hw_revision.h
+++ /dev/null
@@ -1,28 +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/>.
- */
-
-#pragma once
-
-#include <trezor_types.h>
-
-void hw_revision_init(void);
-
-void hw_revision_deinit(void);
-
-uint8_t hw_revision_get(void);
diff --git a/core/embed/util/hw_revision/stm32/hw_revision.c b/core/embed/util/hw_revision/stm32/hw_revision.c
deleted file mode 100644
index cdc63bc45..000000000
--- a/core/embed/util/hw_revision/stm32/hw_revision.c
+++ /dev/null
@@ -1,114 +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/>.
- */
-#ifdef KERNEL_MODE
-
-#include <trezor_bsp.h>
-#include <trezor_model.h>
-#include <trezor_rtl.h>
-
-#include <util/hw_revision.h>
-
-typedef struct {
- uint8_t revision;
- bool initialized;
-} hw_revision_t;
-
-static hw_revision_t g_hw_revision;
-
-static uint8_t hw_revision_read(void) {
- bool rev0 =
- GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_0_PORT, HW_REVISION_0_PIN);
- bool rev1 =
- GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_1_PORT, HW_REVISION_1_PIN);
- bool rev2 =
- GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_2_PORT, HW_REVISION_2_PIN);
- bool rev3 = false;
-#ifdef HW_REVISION_3_PIN
- rev3 =
- GPIO_PIN_SET == HAL_GPIO_ReadPin(HW_REVISION_3_PORT, HW_REVISION_3_PIN);
-#endif
-
- uint8_t revision = 0;
- revision |= rev0 ? 1 : 0;
- revision |= rev1 ? 2 : 0;
- revision |= rev2 ? 4 : 0;
- revision |= rev3 ? 8 : 0;
-
- return revision;
-}
-
-void hw_revision_init(void) {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
-
- HW_REVISION_0_CLOCK_ENABLE();
- GPIO_InitStructure.Pin = HW_REVISION_0_PIN;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
- GPIO_InitStructure.Pull = HW_REVISION_PUPD;
- GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
- HAL_GPIO_Init(HW_REVISION_0_PORT, &GPIO_InitStructure);
-
- HW_REVISION_1_CLOCK_ENABLE();
- GPIO_InitStructure.Pin = HW_REVISION_1_PIN;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
- GPIO_InitStructure.Pull = HW_REVISION_PUPD;
- GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
- HAL_GPIO_Init(HW_REVISION_1_PORT, &GPIO_InitStructure);
-
- HW_REVISION_2_CLOCK_ENABLE();
- GPIO_InitStructure.Pin = HW_REVISION_2_PIN;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
- GPIO_InitStructure.Pull = HW_REVISION_PUPD;
- GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
- HAL_GPIO_Init(HW_REVISION_2_PORT, &GPIO_InitStructure);
-
-#ifdef HW_REVISION_3_PIN
- GPIO_InitStructure.Pin = HW_REVISION_3_PIN;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
- GPIO_InitStructure.Pull = HW_REVISION_PUPD;
- GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
- HAL_GPIO_Init(HW_REVISION_3_PORT, &GPIO_InitStructure);
-#endif
-
- memset(&g_hw_revision, 0, sizeof(hw_revision_t));
- g_hw_revision.revision = hw_revision_read();
- g_hw_revision.initialized = true;
-
- // deinit the GPIOs to save power
- HAL_GPIO_DeInit(HW_REVISION_0_PORT, HW_REVISION_0_PIN);
- HAL_GPIO_DeInit(HW_REVISION_1_PORT, HW_REVISION_1_PIN);
- HAL_GPIO_DeInit(HW_REVISION_2_PORT, HW_REVISION_2_PIN);
-#ifdef HW_REVISION_3_PIN
- HAL_GPIO_DeInit(HW_REVISION_3_PORT, HW_REVISION_3_PIN);
-#endif
-}
-
-void hw_revision_deinit(void) {
- memset(&g_hw_revision, 0, sizeof(hw_revision_t));
-}
-
-uint8_t hw_revision_get(void) {
- hw_revision_t *hw_revision = &g_hw_revision;
- if (!hw_revision->initialized) {
- hw_revision_init();
- }
-
- return hw_revision->revision;
-}
-
-#endif
diff --git a/core/site_scons/models/T3B1/trezor_t3b1_revB.py b/core/site_scons/models/T3B1/trezor_t3b1_revB.py
index 08827b0cf..72b3984a2 100644
--- a/core/site_scons/models/T3B1/trezor_t3b1_revB.py
+++ b/core/site_scons/models/T3B1/trezor_t3b1_revB.py
@@ -90,8 +90,8 @@ def configure(
if "hw_revision" in features_wanted:
defines += [("USE_HW_REVISION", "1")]
- paths += ["embed/util/hw_revision/inc"]
- sources += ["embed/util/hw_revision/stm32/hw_revision.c"]
+ paths += ["embed/sec/hw_revision/inc"]
+ sources += ["embed/sec/hw_revision/stm32/hw_revision.c"]
defines += [
("USE_HASH_PROCESSOR", "1"),
diff --git a/core/site_scons/models/T3T1/trezor_t3t1_revE.py b/core/site_scons/models/T3T1/trezor_t3t1_revE.py
index 17868aa37..509bd778e 100644
--- a/core/site_scons/models/T3T1/trezor_t3t1_revE.py
+++ b/core/site_scons/models/T3T1/trezor_t3t1_revE.py
@@ -123,8 +123,8 @@ def configure(
if "hw_revision" in features_wanted:
defines += [("USE_HW_REVISION", "1")]
- paths += ["embed/util/hw_revision/inc"]
- sources += ["embed/util/hw_revision/stm32/hw_revision.c"]
+ paths += ["embed/sec/hw_revision/inc"]
+ sources += ["embed/sec/hw_revision/stm32/hw_revision.c"]
defines += [
("USE_HASH_PROCESSOR", "1"),
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
index 1ebbd38e8..cd61e81b5 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
@@ -236,8 +236,8 @@ def configure(
if "hw_revision" in features_wanted:
defines += [("USE_HW_REVISION", "1")]
- paths += ["embed/util/hw_revision/inc"]
- sources += ["embed/util/hw_revision/stm32/hw_revision.c"]
+ paths += ["embed/sec/hw_revision/inc"]
+ sources += ["embed/sec/hw_revision/stm32/hw_revision.c"]
defines += [
"FRAMEBUFFER",
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
index 92391ffc5..5200d78f3 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
@@ -234,8 +234,8 @@ def configure(
if "hw_revision" in features_wanted:
defines += [("USE_HW_REVISION", "1")]
- paths += ["embed/util/hw_revision/inc"]
- sources += ["embed/util/hw_revision/stm32/hw_revision.c"]
+ paths += ["embed/sec/hw_revision/inc"]
+ sources += ["embed/sec/hw_revision/stm32/hw_revision.c"]
if "telemetry" in features_wanted:
sources += ["embed/util/telemetry/telemetry.c"]
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.