refactor(core): move backup_ram driver from sys to sec
What changed, and why it matters
This commit is a pure code reorganization: it moves the backup RAM driver from the 'sys' directory to the 'sec' directory and updates all include paths accordingly. The actual C source code for the driver is identical before and after the move. There is no functional change, no bug fix, and no security patch visible in the diff.
No security action required. Treat as a normal refactoring commit. If reviewing for defense-in-depth, verify that the new 'sec' location matches the intended trust-zone/secure-world placement and that build/linker scripts expose backup RAM only to the expected secure contexts.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change relocates core/embed/sys/backup_ram/ to core/embed/sec/backup_ram/ and changes all #include
Changed components
core/embed/sec/backup_ram drivercore/embed/projects/bootloadercore/embed/projects/kernelcore/embed/projects/prodtestcore/embed/projects/secmoncore/embed/sys/power_managercore/embed/sys/smcallcore/embed/io/blecore/site_scons/models/T3W1 build configurationInspect captured patch +759 / −759
diff --git a/core/embed/io/ble/stm32/ble.c b/core/embed/io/ble/stm32/ble.c
index 4441dadb..1756f05e 100644
--- a/core/embed/io/ble/stm32/ble.c
+++ b/core/embed/io/ble/stm32/ble.c
@@ -27,7 +27,7 @@
#include <io/ble.h>
#include <io/nrf.h>
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#include <sys/irq.h>
#include <sys/sysevent_source.h>
#include <sys/systick.h>
diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c
index 91d681bc..41d97620 100644
--- a/core/embed/projects/bootloader/main.c
+++ b/core/embed/projects/bootloader/main.c
@@ -48,7 +48,7 @@
#include <io/touch.h>
#endif
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_BUTTON
#include <io/button.h>
diff --git a/core/embed/projects/bootloader/workflow/wf_empty_device.c b/core/embed/projects/bootloader/workflow/wf_empty_device.c
index 474134be..52e208ba 100644
--- a/core/embed/projects/bootloader/workflow/wf_empty_device.c
+++ b/core/embed/projects/bootloader/workflow/wf_empty_device.c
@@ -31,7 +31,7 @@
#endif
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_BLE
diff --git a/core/embed/projects/bootloader/workflow/wf_firmware_update.c b/core/embed/projects/bootloader/workflow/wf_firmware_update.c
index c868f27b..917e5010 100644
--- a/core/embed/projects/bootloader/workflow/wf_firmware_update.c
+++ b/core/embed/projects/bootloader/workflow/wf_firmware_update.c
@@ -32,7 +32,7 @@
#endif
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#include "bootui.h"
diff --git a/core/embed/projects/bootloader/workflow/wf_unlock_bootloader.c b/core/embed/projects/bootloader/workflow/wf_unlock_bootloader.c
index 1c94ce7b..dba308be 100644
--- a/core/embed/projects/bootloader/workflow/wf_unlock_bootloader.c
+++ b/core/embed/projects/bootloader/workflow/wf_unlock_bootloader.c
@@ -24,7 +24,7 @@
#include <util/flash_utils.h>
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#include "bootui.h"
diff --git a/core/embed/projects/bootloader/workflow/wf_wipe_device.c b/core/embed/projects/bootloader/workflow/wf_wipe_device.c
index 5c789c85..d806162e 100644
--- a/core/embed/projects/bootloader/workflow/wf_wipe_device.c
+++ b/core/embed/projects/bootloader/workflow/wf_wipe_device.c
@@ -28,7 +28,7 @@
#endif
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_RGB_LED
diff --git a/core/embed/projects/kernel/main.c b/core/embed/projects/kernel/main.c
index 71b35c2c..5b0d77a4 100644
--- a/core/embed/projects/kernel/main.c
+++ b/core/embed/projects/kernel/main.c
@@ -63,7 +63,7 @@
#endif
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_TROPIC
diff --git a/core/embed/projects/prodtest/cmd/prodtest_backup_ram.c b/core/embed/projects/prodtest/cmd/prodtest_backup_ram.c
index 369e41cc..a33a2725 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_backup_ram.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_backup_ram.c
@@ -22,7 +22,7 @@
#include <trezor_rtl.h>
#include <rtl/cli.h>
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#include <sys/power_manager.h>
#include <sys/systick.h>
diff --git a/core/embed/projects/prodtest/cmd/prodtest_power_manager.c b/core/embed/projects/prodtest/cmd/prodtest_power_manager.c
index 9b31d1ef..9782e190 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_power_manager.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_power_manager.c
@@ -27,7 +27,7 @@
#include <rtl/printf.h>
#include <rtl/unit_test.h>
#include <rust_ui_prodtest.h>
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#include <sys/bootutils.h>
#include <sys/power_manager.h>
#include <sys/rtc.h>
diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c
index 438c8251..8648cf43 100644
--- a/core/embed/projects/prodtest/main.c
+++ b/core/embed/projects/prodtest/main.c
@@ -51,7 +51,7 @@
#endif
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_TOUCH
diff --git a/core/embed/projects/secmon/main.c b/core/embed/projects/secmon/main.c
index ed53951e..afbe4e8f 100644
--- a/core/embed/projects/secmon/main.c
+++ b/core/embed/projects/secmon/main.c
@@ -33,7 +33,7 @@
#include <util/unit_properties.h>
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_OPTIGA
diff --git a/core/embed/sec/backup_ram/backup_ram_crc.c b/core/embed/sec/backup_ram/backup_ram_crc.c
new file mode 100644
index 00000000..948da38f
--- /dev/null
+++ b/core/embed/sec/backup_ram/backup_ram_crc.c
@@ -0,0 +1,41 @@
+/*
+ * 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 "backup_ram_crc.h"
+
+uint16_t backup_ram_crc16(const void* data, size_t size, uint16_t initial_crc) {
+ uint16_t crc = initial_crc;
+ const uint8_t* ptr = (const uint8_t*)data;
+
+ // CRC-16-CCITT polynomial x^16 + x^12 + x^5 + 1
+ const uint16_t polynomial = 0x1021;
+
+ for (size_t i = 0; i < size; i++) {
+ crc ^= (uint16_t)ptr[i] << 8;
+ for (uint8_t bit = 0; bit < 8; bit++) {
+ if (crc & 0x8000) {
+ crc = (crc << 1) ^ polynomial;
+ } else {
+ crc = crc << 1;
+ }
+ }
+ }
+
+ return crc;
+}
diff --git a/core/embed/sec/backup_ram/backup_ram_crc.h b/core/embed/sec/backup_ram/backup_ram_crc.h
new file mode 100644
index 00000000..ae3041e8
--- /dev/null
+++ b/core/embed/sec/backup_ram/backup_ram_crc.h
@@ -0,0 +1,37 @@
+/*
+ * 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>
+
+#define BACKUP_RAM_CRC16_INITIAL 0xFFFF /** Initial value for CRC-16-CCITT*/
+
+/**
+ * @brief Calculate CRC-16-CCITT for the backup RAM storage.
+ *
+ * @param data Pointer to the data to calculate CRC for.
+ * @param size Length of the data in bytes.
+ * @param initial_crc Initial CRC value to start the calculation from. Use
+ * BACKUP_RAM_CRC16_INITIAL for a fresh calculation. Use the last calculated
+ * CRC value to continue the calculation from a previous state.
+ *
+ * @return uint16_t Calculated CRC value.
+ */
+uint16_t backup_ram_crc16(const void *data, size_t size, uint16_t initial_crc);
diff --git a/core/embed/sec/backup_ram/inc/sec/backup_ram.h b/core/embed/sec/backup_ram/inc/sec/backup_ram.h
new file mode 100644
index 00000000..33683afe
--- /dev/null
+++ b/core/embed/sec/backup_ram/inc/sec/backup_ram.h
@@ -0,0 +1,137 @@
+/*
+ * 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>
+
+/** Global keys for items stored in the backup RAM */
+#define BACKUP_RAM_KEY_PM_RECOVERY 0x0001 // Power management recovery data
+#define BACKUP_RAM_KEY_BLE_SETTINGS 0x0002 // BLE settings
+#define BACKUP_RAM_KEY_TELEMETRY 0x0003 // Telemetry data (min/max temps etc.)
+
+/** Maximum size of data stored under a single key in backup RAM */
+#define BACKUP_RAM_MAX_KEY_DATA_SIZE 512
+
+typedef enum {
+ BACKUP_RAM_ITEM_PUBLIC =
+ 0, /**< Public data - will be preserved on device wipe */
+ BACKUP_RAM_ITEM_PROTECTED =
+ 1, /**< Protected data - will be erased on device wipe */
+} backup_ram_item_type_t;
+
+/**
+ * @brief Initializes backup RAM driver
+ *
+ * This function initializes the backup RAM driver, checks the consistency of
+ * the backup RAM storage, and initializes it if necessary.
+ *
+ * @return true if the operation was successful
+ *
+ */
+bool backup_ram_init(void);
+
+/**
+ * @brief Deinitialize backup RAM driver
+ *
+ * The function does not erase the backup RAM, it just deinitializes
+ * the driver.
+ */
+void backup_ram_deinit(void);
+
+/**
+ * @brief Erases the backup RAM content
+ *
+ * @return true if the operation was successful, false otherwise.
+ */
+
+bool backup_ram_erase(void);
+
+/**
+ * @brief Erases protected backup RAM content
+ *
+ * @return true if the operation was successful, false otherwise.
+ */
+bool backup_ram_erase_protected(void);
+
+/**
+ * @brief Erases a single item in backup RAM by its key.
+ *
+ * If the item with the given key does not exist, the function does nothing.
+ *
+ * @param key Key of the item to erase
+ *
+ * @return true if the operation was successful, false otherwise.
+ */
+bool backup_ram_erase_item(uint16_t key);
+
+#define BACKUP_RAM_INVALID_KEY 0xFFFF
+
+/**
+ * @brief Finds the first key in backup RAM that is greater than or equal to
+ * min_key.
+ *
+ * @param min_key Minimum key to search for
+ *
+ * @return The first key found that is greater than or equal to min_key, or
+ * BACKUP_RAM_INVALID_KEY if no such key exists.
+ */
+uint16_t backup_ram_search(uint16_t min_key);
+
+/**
+ * @brief Writes key-value data in backup RAM.
+ *
+ * @param key Key to identify the data
+ * @param data Pointer to the data to be stored
+ * @param type Type of the data being stored
+ * @param data_size Size of the data in bytes. If the key does not exist, this
+ * value will be set to 0. If data_size == 0, the item will be removed.
+ *
+ * @return true if the operation was successful, false otherwise.
+ */
+bool backup_ram_write(uint16_t key, backup_ram_item_type_t type,
+ const void* data, size_t data_size);
+
+/**
+ * @brief Reads key-value data from backup RAM.
+ *
+ * Writes key-value data in backup RAM. If the value with the give key
+ * exists, it will be overwritten with the new data. If the data_size is
+ * zero, the key will be removed from the backup RAM.
+ *
+ * @param key Key to identify the data
+ * @param buffer Pointer to the buffer where the data will be stored
+ * @param buffer_size Size of the buffer in bytes
+ * @param data_size Pointer to a variable where the size of the data
+ *
+ * If data_size is NULL, the size will not be retrieved. If buffer is NULL,
+ * the data will not be copied, but the size will still be retrieved.
+ *
+ * @return backup_ram_status_t BACKUP_RAM_OK if the operation was
+ * successful.
+ */
+bool backup_ram_read(uint16_t key, void* buffer, size_t buffer_size,
+ size_t* data_size);
+
+/**
+ * @brief Determines if a key is accessible by the kernel.
+ * @param key Key to check
+ * @return true if the key is accessible by the kernel, false otherwise
+ */
+bool backup_ram_kernel_accessible(uint16_t key);
diff --git a/core/embed/sec/backup_ram/stm32u5/backup_ram.c b/core/embed/sec/backup_ram/stm32u5/backup_ram.c
new file mode 100644
index 00000000..aa8013ff
--- /dev/null
+++ b/core/embed/sec/backup_ram/stm32u5/backup_ram.c
@@ -0,0 +1,519 @@
+
+/*
+ * 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_rtl.h>
+
+#include <rtl/sizedefs.h>
+#include <sec/backup_ram.h>
+#include <sys/irq.h>
+
+#include "../backup_ram_crc.h"
+
+// Guard values for backup RAM slots
+#define BACKUP_RAM_GUARD_OK 0xFFFF5555 // Used to mark a valid slot
+#define BACKUP_RAM_GUARD_NOK 0x0000AAAA // Used to mark an invalid slot
+
+// Backup RAM address and configuration
+#define BACKUP_RAM_BASE_ADDRESS (PERIPH_BASE + 0x36400)
+#define BACKUP_RAM_SLOT_COUNT 2
+#define BACKUP_RAM_SLOT_SIZE 1024
+#define BACKUP_RAM_MAX_PAYLOAD_SIZE \
+ (BACKUP_RAM_SLOT_SIZE - sizeof(backup_ram_payload_header_t) - 8)
+
+// Backup RAM slot header
+typedef struct {
+ // Slot sequence number
+ uint16_t seq;
+ // Payload size in bytes
+ uint16_t size;
+ // Reserved for future use (must be zero)
+ uint8_t reserved[4];
+} backup_ram_payload_header_t;
+
+_Static_assert(sizeof(backup_ram_payload_header_t) == 8,
+ "backup_ram_slot_header_t size mismatch");
+
+// Structure of a single backup RAM slot
+typedef struct {
+ // BACKUP_RAM_GUARD_xxx
+ uint32_t guard;
+ // CRC-16 of the header and payload
+ uint16_t crc;
+ // Reserved for future use (must be zero)
+ uint16_t reserved;
+ // Header containing metadata about the slot
+ backup_ram_payload_header_t header;
+ // Payload data containing TLV-encoded data
+ uint8_t payload[BACKUP_RAM_MAX_PAYLOAD_SIZE];
+} backup_ram_slot_t;
+
+_Static_assert(sizeof(backup_ram_slot_t) == BACKUP_RAM_SLOT_SIZE,
+ "backup_ram_slot_t size mismatch");
+
+// g_backup_ram points to the backup RAM in peripheral memory region.
+// It's more like a memory-mapped peripheral (nGnRnE) than a regular RAM region.
+backup_ram_slot_t* const g_backup_ram =
+ (backup_ram_slot_t*)BACKUP_RAM_BASE_ADDRESS;
+
+#define SEQ_TO_INDEX(seq) ((seq) % BACKUP_RAM_SLOT_COUNT)
+
+// Backup ram driver structure
+typedef struct {
+ // Set if the driver is initialized
+ bool initialized;
+ // Handle of RAMCFG peripheral driver
+ RAMCFG_HandleTypeDef hramcfg;
+ // Next sequence number to write
+ uint16_t next_seq;
+ // Copy of the data in the backup RAM (if valid)
+ uint8_t payload[BACKUP_RAM_MAX_PAYLOAD_SIZE];
+ // Current payload size
+ size_t payload_size;
+
+} backup_ram_driver_t;
+
+// Global driver instance
+static backup_ram_driver_t g_backup_ram_driver = {.initialized = false};
+
+// forward declarations
+static void backup_ram_reload(void);
+static bool is_payload_valid(const uint8_t* payload, size_t payload_size);
+
+bool backup_ram_init(void) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (drv->initialized) {
+ // Already initialized
+ return true;
+ }
+
+ memset(drv, 0, sizeof(*drv));
+
+ // Enable backup SRAM clock
+ __HAL_RCC_RAMCFG_FORCE_RESET();
+ __HAL_RCC_RAMCFG_RELEASE_RESET();
+ __HAL_RCC_RAMCFG_CLK_ENABLE();
+ __HAL_RCC_BKPSRAM_CLK_ENABLE();
+
+ drv->hramcfg.Instance = RAMCFG_BKPRAM;
+
+ HAL_StatusTypeDef hal_status = HAL_RAMCFG_Init(&drv->hramcfg);
+ if (hal_status != HAL_OK) {
+ drv->hramcfg.Instance = NULL;
+ goto cleanup;
+ }
+
+ // Initialize storage
+ backup_ram_reload();
+
+ drv->initialized = true;
+ return true;
+
+cleanup:
+ backup_ram_deinit();
+ return false;
+}
+
+void backup_ram_deinit(void) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (drv->hramcfg.Instance != NULL) {
+ HAL_RAMCFG_DeInit(&drv->hramcfg);
+ }
+
+ // Disable backup SRAM clock
+ __HAL_RCC_BKPSRAM_CLK_DISABLE();
+ __HAL_RCC_RAMCFG_CLK_DISABLE();
+
+ memset(drv, 0, sizeof(*drv));
+}
+
+bool backup_ram_erase(void) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (!drv->initialized) {
+ return false;
+ }
+
+ irq_key_t irq_key = irq_lock();
+
+ memset(g_backup_ram, 0, sizeof(backup_ram_slot_t) * BACKUP_RAM_SLOT_COUNT);
+
+ memset(drv->payload, 0, sizeof(drv->payload));
+ drv->next_seq = 0;
+ drv->payload_size = 0;
+
+ irq_unlock(irq_key);
+
+ return true;
+}
+
+static bool is_slot_valid(const backup_ram_slot_t* slot) {
+ if (slot->guard != BACKUP_RAM_GUARD_OK) {
+ // Invalid guard value, slot is not valid
+ return false;
+ }
+
+ if (slot->reserved != 0) {
+ // Reserved bytes must be zero
+ return false;
+ }
+
+ if (slot->header.size > BACKUP_RAM_MAX_PAYLOAD_SIZE) {
+ // Invalid reported size
+ return false;
+ }
+
+ uint16_t crc = BACKUP_RAM_CRC16_INITIAL;
+ crc = backup_ram_crc16(&slot->header, sizeof(slot->header), crc);
+ crc = backup_ram_crc16(slot->payload, slot->header.size, crc);
+
+ if (crc != slot->crc) {
+ // CRC mismatch, slot is invalid
+ return false;
+ }
+
+ if (!is_payload_valid(slot->payload, slot->header.size)) {
+ // Invalid key-value pairs in the payload
+ return false;
+ }
+
+ return true;
+}
+
+static void backup_ram_reload(void) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ int newest_seq = -1;
+
+ // Find the newest valid slot & clear invalid slots
+ for (int i = 0; i < BACKUP_RAM_SLOT_COUNT; ++i) {
+ backup_ram_slot_t* slot = &g_backup_ram[i];
+ if (is_slot_valid(slot) && (SEQ_TO_INDEX(slot->header.seq) == i)) {
+ if (newest_seq < 0) {
+ newest_seq = slot->header.seq;
+ } else if ((int16_t)(slot->header.seq - newest_seq) > 0) {
+ newest_seq = slot->header.seq;
+ }
+ } else {
+ // Slot is invalid, clear it
+ memset(slot, 0, sizeof(backup_ram_slot_t));
+ }
+ }
+
+ memset(drv->payload, 0, sizeof(drv->payload));
+ drv->payload_size = 0;
+ drv->next_seq = 0;
+
+ if (newest_seq >= 0) {
+ backup_ram_slot_t* slot = &g_backup_ram[SEQ_TO_INDEX(newest_seq)];
+ memcpy(drv->payload, slot->payload, slot->header.size);
+ drv->payload_size = slot->header.size;
+ drv->next_seq = newest_seq + 1;
+ }
+}
+
+static bool backup_ram_commit(void) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (!drv->initialized) {
+ return false;
+ }
+
+ backup_ram_payload_header_t header = {
+ .seq = drv->next_seq,
+ .size = drv->payload_size,
+ };
+
+ uint16_t crc = BACKUP_RAM_CRC16_INITIAL;
+ crc = backup_ram_crc16(&header, sizeof(header), crc);
+ crc = backup_ram_crc16(drv->payload, drv->payload_size, crc);
+
+ volatile backup_ram_slot_t* slot = &g_backup_ram[SEQ_TO_INDEX(drv->next_seq)];
+
+ // Invalidate the slot first
+ slot->guard = BACKUP_RAM_GUARD_NOK;
+ slot->crc = 0;
+
+ // Update crc and payload header
+ slot->header = header;
+
+ // Copy the payload data
+ uint32_t* src = (uint32_t*)drv->payload;
+ volatile uint32_t* dst = (uint32_t*)slot->payload;
+ volatile uint32_t* end = (uint32_t*)(slot->payload + drv->payload_size);
+ while (dst < end) {
+ *dst++ = *src++;
+ }
+
+ // Fill the rest of the slot with zeros
+ end = (uint32_t*)(slot->payload + BACKUP_RAM_MAX_PAYLOAD_SIZE);
+ while (dst < end) {
+ *dst++ = 0;
+ }
+
+ // Make slot valid again
+ slot->reserved = 0;
+ slot->crc = crc;
+ slot->guard = BACKUP_RAM_GUARD_OK;
+
+ ++drv->next_seq;
+
+ return true;
+}
+
+typedef struct {
+ // Key for the item
+ uint16_t key;
+ // Size of the data in bytes
+ uint16_t data_size;
+ // Type of the item
+ uint8_t item_type;
+ // reserved, must be zero
+ uint8_t reserved;
+ // Value data (variable length, aligned to 4 bytes)
+ uint8_t data[];
+} backup_ram_item_t;
+
+_Static_assert(sizeof(backup_ram_item_t) == 6,
+ "backup_ram_item_t size mismatch");
+
+#define ITEM_SIZE(data_size) \
+ (sizeof(backup_ram_item_t) + ALIGN_UP(data_size, 4))
+
+static bool is_payload_valid(const uint8_t* payload, size_t payload_size) {
+ uint32_t offset = 0;
+
+ while (offset + ITEM_SIZE(0) <= payload_size) {
+ backup_ram_item_t* item = (backup_ram_item_t*)(payload + offset);
+ offset += ITEM_SIZE(item->data_size);
+ }
+
+ return offset == payload_size;
+}
+
+// Find an item in the backup RAM by its key
+static backup_ram_item_t* backup_ram_find_item(uint16_t key) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (!drv->initialized) {
+ return NULL;
+ }
+
+ uint32_t offset = 0;
+
+ while (offset + ITEM_SIZE(0) <= drv->payload_size) {
+ backup_ram_item_t* item = (backup_ram_item_t*)(drv->payload + offset);
+
+ if (item->key == key) {
+ return item;
+ }
+
+ offset += ITEM_SIZE(item->data_size);
+ }
+
+ return NULL;
+}
+
+uint16_t backup_ram_search(uint16_t min_key) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (!drv->initialized) {
+ return BACKUP_RAM_INVALID_KEY;
+ }
+
+ uint32_t offset = 0;
+ uint16_t key = BACKUP_RAM_INVALID_KEY;
+
+ while (offset + ITEM_SIZE(0) <= drv->payload_size) {
+ backup_ram_item_t* item = (backup_ram_item_t*)(drv->payload + offset);
+
+ if (item->key >= min_key && item->key < key) {
+ key = item->key;
+ }
+
+ offset += ITEM_SIZE(item->data_size);
+ }
+
+ return key;
+}
+
+bool backup_ram_erase_item(uint16_t key) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (!drv->initialized) {
+ return false;
+ }
+
+ irq_key_t irq_key = irq_lock();
+ // Writing data_size==0 will just remove the item with the given key
+ // Type is don't care in this case.
+ bool status = backup_ram_write(key, BACKUP_RAM_ITEM_PUBLIC, NULL, 0);
+ irq_unlock(irq_key);
+
+ return status;
+}
+
+bool backup_ram_erase_protected(void) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+ if (!drv->initialized) {
+ return false;
+ }
+
+ // Lock interrupts while we mutate the in-RAM copy of the payload
+ irq_key_t irq_key = irq_lock();
+
+ uint32_t offset = 0;
+ // Walk the payload buffer
+ while (offset + ITEM_SIZE(0) <= drv->payload_size) {
+ backup_ram_item_t* item = (backup_ram_item_t*)(drv->payload + offset);
+ size_t this_size = ITEM_SIZE(item->data_size);
+
+ if (item->item_type != BACKUP_RAM_ITEM_PUBLIC) {
+ // Remove this item by sliding the remainder of the payload down over it
+ uint8_t* next_item = (uint8_t*)item + this_size;
+ size_t tail_bytes = drv->payload_size - (offset + this_size);
+ memmove(item, next_item, tail_bytes);
+ drv->payload_size -= this_size;
+ // don't advance offset: new item has just been shifted into this slot
+ } else {
+ // keep this public item: skip over it
+ offset += this_size;
+ }
+ }
+
+ // write the cleaned payload back into flash-backed RAM
+ bool success = backup_ram_commit();
+ irq_unlock(irq_key);
+ return success;
+}
+
+bool backup_ram_read(uint16_t key, void* buffer, size_t buffer_size,
+ size_t* data_size) {
+ bool success = false;
+ irq_key_t irq_key = irq_lock();
+
+ backup_ram_item_t* item = backup_ram_find_item(key);
+
+ if (data_size != NULL) {
+ *data_size = item ? item->data_size : 0;
+ }
+
+ if (item == NULL) {
+ goto cleanup;
+ }
+
+ if (buffer != NULL && item->data_size > buffer_size) {
+ // Not enough space in the buffer
+ goto cleanup;
+ }
+
+ if (buffer != NULL) {
+ memcpy(buffer, item->data, item->data_size);
+ }
+
+ success = true;
+
+cleanup:
+ irq_unlock(irq_key);
+ return success;
+}
+
+bool backup_ram_write(uint16_t key, backup_ram_item_type_t type,
+ const void* data, size_t data_size) {
+ backup_ram_driver_t* drv = &g_backup_ram_driver;
+
+ if (!drv->initialized) {
+ return false;
+ }
+
+ if (data_size > BACKUP_RAM_MAX_KEY_DATA_SIZE) {
+ // Data size exceeds maximum allowed size
+ return false;
+ }
+
+ bool success = false;
+
+ irq_key_t irq_key = irq_lock();
+
+ backup_ram_item_t* item = backup_ram_find_item(key);
+
+ if (item != NULL && item->item_type != type && data_size != 0) {
+ // Item exists but has a different type, not supported
+ goto cleanup;
+ }
+
+ if (item != NULL && item->data_size == data_size) {
+ // The most common case: item exists and has the same size
+ memcpy(item->data, data, data_size);
+ } else {
+ // Check if we have enough space for the new item
+ size_t free_space = BACKUP_RAM_MAX_PAYLOAD_SIZE - drv->payload_size;
+
+ if (item != NULL) {
+ // Add the size of the existing item to the free space
+ free_space += ITEM_SIZE(item->data_size);
+ }
+
+ if (ITEM_SIZE(data_size) > free_space) {
+ // Not enough space for the new item
+ goto cleanup;
+ }
+
+ // Remove the item if it exists
+ if (item != NULL) {
+ size_t deleted_size = ITEM_SIZE(item->data_size);
+ uint8_t* next_item = (uint8_t*)item + deleted_size;
+ uint8_t* end_of_payload = drv->payload + drv->payload_size;
+ assert(next_item <= end_of_payload);
+ memmove(item, next_item, end_of_payload - next_item);
+ drv->payload_size -= deleted_size;
+ }
+
+ // Add a new item at the end of the payload
+ if (data_size > 0) {
+ item = (backup_ram_item_t*)&drv->payload[drv->payload_size];
+ item->key = key;
+ item->data_size = data_size;
+ item->item_type = type;
+ item->reserved = 0;
+ memcpy(item->data, data, data_size);
+ memset(&item->data[data_size], 0, ALIGN_UP(data_size, 4) - data_size);
+ drv->payload_size += ITEM_SIZE(data_size);
+ }
+ }
+
+ // Commit the changes to backup RAM
+ success = backup_ram_commit();
+
+cleanup:
+ irq_unlock(irq_key);
+ return success;
+}
+
+bool backup_ram_kernel_accessible(uint16_t key) {
+ return (key == BACKUP_RAM_KEY_PM_RECOVERY ||
+ key == BACKUP_RAM_KEY_BLE_SETTINGS);
+}
+
+#endif // SECURE_MODE
diff --git a/core/embed/sys/backup_ram/backup_ram_crc.c b/core/embed/sys/backup_ram/backup_ram_crc.c
deleted file mode 100644
index 948da38f..00000000
--- a/core/embed/sys/backup_ram/backup_ram_crc.c
+++ /dev/null
@@ -1,41 +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 "backup_ram_crc.h"
-
-uint16_t backup_ram_crc16(const void* data, size_t size, uint16_t initial_crc) {
- uint16_t crc = initial_crc;
- const uint8_t* ptr = (const uint8_t*)data;
-
- // CRC-16-CCITT polynomial x^16 + x^12 + x^5 + 1
- const uint16_t polynomial = 0x1021;
-
- for (size_t i = 0; i < size; i++) {
- crc ^= (uint16_t)ptr[i] << 8;
- for (uint8_t bit = 0; bit < 8; bit++) {
- if (crc & 0x8000) {
- crc = (crc << 1) ^ polynomial;
- } else {
- crc = crc << 1;
- }
- }
- }
-
- return crc;
-}
diff --git a/core/embed/sys/backup_ram/backup_ram_crc.h b/core/embed/sys/backup_ram/backup_ram_crc.h
deleted file mode 100644
index ae3041e8..00000000
--- a/core/embed/sys/backup_ram/backup_ram_crc.h
+++ /dev/null
@@ -1,37 +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>
-
-#define BACKUP_RAM_CRC16_INITIAL 0xFFFF /** Initial value for CRC-16-CCITT*/
-
-/**
- * @brief Calculate CRC-16-CCITT for the backup RAM storage.
- *
- * @param data Pointer to the data to calculate CRC for.
- * @param size Length of the data in bytes.
- * @param initial_crc Initial CRC value to start the calculation from. Use
- * BACKUP_RAM_CRC16_INITIAL for a fresh calculation. Use the last calculated
- * CRC value to continue the calculation from a previous state.
- *
- * @return uint16_t Calculated CRC value.
- */
-uint16_t backup_ram_crc16(const void *data, size_t size, uint16_t initial_crc);
diff --git a/core/embed/sys/backup_ram/inc/sys/backup_ram.h b/core/embed/sys/backup_ram/inc/sys/backup_ram.h
deleted file mode 100644
index 33683afe..00000000
--- a/core/embed/sys/backup_ram/inc/sys/backup_ram.h
+++ /dev/null
@@ -1,137 +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>
-
-/** Global keys for items stored in the backup RAM */
-#define BACKUP_RAM_KEY_PM_RECOVERY 0x0001 // Power management recovery data
-#define BACKUP_RAM_KEY_BLE_SETTINGS 0x0002 // BLE settings
-#define BACKUP_RAM_KEY_TELEMETRY 0x0003 // Telemetry data (min/max temps etc.)
-
-/** Maximum size of data stored under a single key in backup RAM */
-#define BACKUP_RAM_MAX_KEY_DATA_SIZE 512
-
-typedef enum {
- BACKUP_RAM_ITEM_PUBLIC =
- 0, /**< Public data - will be preserved on device wipe */
- BACKUP_RAM_ITEM_PROTECTED =
- 1, /**< Protected data - will be erased on device wipe */
-} backup_ram_item_type_t;
-
-/**
- * @brief Initializes backup RAM driver
- *
- * This function initializes the backup RAM driver, checks the consistency of
- * the backup RAM storage, and initializes it if necessary.
- *
- * @return true if the operation was successful
- *
- */
-bool backup_ram_init(void);
-
-/**
- * @brief Deinitialize backup RAM driver
- *
- * The function does not erase the backup RAM, it just deinitializes
- * the driver.
- */
-void backup_ram_deinit(void);
-
-/**
- * @brief Erases the backup RAM content
- *
- * @return true if the operation was successful, false otherwise.
- */
-
-bool backup_ram_erase(void);
-
-/**
- * @brief Erases protected backup RAM content
- *
- * @return true if the operation was successful, false otherwise.
- */
-bool backup_ram_erase_protected(void);
-
-/**
- * @brief Erases a single item in backup RAM by its key.
- *
- * If the item with the given key does not exist, the function does nothing.
- *
- * @param key Key of the item to erase
- *
- * @return true if the operation was successful, false otherwise.
- */
-bool backup_ram_erase_item(uint16_t key);
-
-#define BACKUP_RAM_INVALID_KEY 0xFFFF
-
-/**
- * @brief Finds the first key in backup RAM that is greater than or equal to
- * min_key.
- *
- * @param min_key Minimum key to search for
- *
- * @return The first key found that is greater than or equal to min_key, or
- * BACKUP_RAM_INVALID_KEY if no such key exists.
- */
-uint16_t backup_ram_search(uint16_t min_key);
-
-/**
- * @brief Writes key-value data in backup RAM.
- *
- * @param key Key to identify the data
- * @param data Pointer to the data to be stored
- * @param type Type of the data being stored
- * @param data_size Size of the data in bytes. If the key does not exist, this
- * value will be set to 0. If data_size == 0, the item will be removed.
- *
- * @return true if the operation was successful, false otherwise.
- */
-bool backup_ram_write(uint16_t key, backup_ram_item_type_t type,
- const void* data, size_t data_size);
-
-/**
- * @brief Reads key-value data from backup RAM.
- *
- * Writes key-value data in backup RAM. If the value with the give key
- * exists, it will be overwritten with the new data. If the data_size is
- * zero, the key will be removed from the backup RAM.
- *
- * @param key Key to identify the data
- * @param buffer Pointer to the buffer where the data will be stored
- * @param buffer_size Size of the buffer in bytes
- * @param data_size Pointer to a variable where the size of the data
- *
- * If data_size is NULL, the size will not be retrieved. If buffer is NULL,
- * the data will not be copied, but the size will still be retrieved.
- *
- * @return backup_ram_status_t BACKUP_RAM_OK if the operation was
- * successful.
- */
-bool backup_ram_read(uint16_t key, void* buffer, size_t buffer_size,
- size_t* data_size);
-
-/**
- * @brief Determines if a key is accessible by the kernel.
- * @param key Key to check
- * @return true if the key is accessible by the kernel, false otherwise
- */
-bool backup_ram_kernel_accessible(uint16_t key);
diff --git a/core/embed/sys/backup_ram/stm32u5/backup_ram.c b/core/embed/sys/backup_ram/stm32u5/backup_ram.c
deleted file mode 100644
index e982d7c6..00000000
--- a/core/embed/sys/backup_ram/stm32u5/backup_ram.c
+++ /dev/null
@@ -1,519 +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 SECURE_MODE
-
-#include <trezor_bsp.h>
-#include <trezor_rtl.h>
-
-#include <rtl/sizedefs.h>
-#include <sys/backup_ram.h>
-#include <sys/irq.h>
-
-#include "../backup_ram_crc.h"
-
-// Guard values for backup RAM slots
-#define BACKUP_RAM_GUARD_OK 0xFFFF5555 // Used to mark a valid slot
-#define BACKUP_RAM_GUARD_NOK 0x0000AAAA // Used to mark an invalid slot
-
-// Backup RAM address and configuration
-#define BACKUP_RAM_BASE_ADDRESS (PERIPH_BASE + 0x36400)
-#define BACKUP_RAM_SLOT_COUNT 2
-#define BACKUP_RAM_SLOT_SIZE 1024
-#define BACKUP_RAM_MAX_PAYLOAD_SIZE \
- (BACKUP_RAM_SLOT_SIZE - sizeof(backup_ram_payload_header_t) - 8)
-
-// Backup RAM slot header
-typedef struct {
- // Slot sequence number
- uint16_t seq;
- // Payload size in bytes
- uint16_t size;
- // Reserved for future use (must be zero)
- uint8_t reserved[4];
-} backup_ram_payload_header_t;
-
-_Static_assert(sizeof(backup_ram_payload_header_t) == 8,
- "backup_ram_slot_header_t size mismatch");
-
-// Structure of a single backup RAM slot
-typedef struct {
- // BACKUP_RAM_GUARD_xxx
- uint32_t guard;
- // CRC-16 of the header and payload
- uint16_t crc;
- // Reserved for future use (must be zero)
- uint16_t reserved;
- // Header containing metadata about the slot
- backup_ram_payload_header_t header;
- // Payload data containing TLV-encoded data
- uint8_t payload[BACKUP_RAM_MAX_PAYLOAD_SIZE];
-} backup_ram_slot_t;
-
-_Static_assert(sizeof(backup_ram_slot_t) == BACKUP_RAM_SLOT_SIZE,
- "backup_ram_slot_t size mismatch");
-
-// g_backup_ram points to the backup RAM in peripheral memory region.
-// It's more like a memory-mapped peripheral (nGnRnE) than a regular RAM region.
-backup_ram_slot_t* const g_backup_ram =
- (backup_ram_slot_t*)BACKUP_RAM_BASE_ADDRESS;
-
-#define SEQ_TO_INDEX(seq) ((seq) % BACKUP_RAM_SLOT_COUNT)
-
-// Backup ram driver structure
-typedef struct {
- // Set if the driver is initialized
- bool initialized;
- // Handle of RAMCFG peripheral driver
- RAMCFG_HandleTypeDef hramcfg;
- // Next sequence number to write
- uint16_t next_seq;
- // Copy of the data in the backup RAM (if valid)
- uint8_t payload[BACKUP_RAM_MAX_PAYLOAD_SIZE];
- // Current payload size
- size_t payload_size;
-
-} backup_ram_driver_t;
-
-// Global driver instance
-static backup_ram_driver_t g_backup_ram_driver = {.initialized = false};
-
-// forward declarations
-static void backup_ram_reload(void);
-static bool is_payload_valid(const uint8_t* payload, size_t payload_size);
-
-bool backup_ram_init(void) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (drv->initialized) {
- // Already initialized
- return true;
- }
-
- memset(drv, 0, sizeof(*drv));
-
- // Enable backup SRAM clock
- __HAL_RCC_RAMCFG_FORCE_RESET();
- __HAL_RCC_RAMCFG_RELEASE_RESET();
- __HAL_RCC_RAMCFG_CLK_ENABLE();
- __HAL_RCC_BKPSRAM_CLK_ENABLE();
-
- drv->hramcfg.Instance = RAMCFG_BKPRAM;
-
- HAL_StatusTypeDef hal_status = HAL_RAMCFG_Init(&drv->hramcfg);
- if (hal_status != HAL_OK) {
- drv->hramcfg.Instance = NULL;
- goto cleanup;
- }
-
- // Initialize storage
- backup_ram_reload();
-
- drv->initialized = true;
- return true;
-
-cleanup:
- backup_ram_deinit();
- return false;
-}
-
-void backup_ram_deinit(void) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (drv->hramcfg.Instance != NULL) {
- HAL_RAMCFG_DeInit(&drv->hramcfg);
- }
-
- // Disable backup SRAM clock
- __HAL_RCC_BKPSRAM_CLK_DISABLE();
- __HAL_RCC_RAMCFG_CLK_DISABLE();
-
- memset(drv, 0, sizeof(*drv));
-}
-
-bool backup_ram_erase(void) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (!drv->initialized) {
- return false;
- }
-
- irq_key_t irq_key = irq_lock();
-
- memset(g_backup_ram, 0, sizeof(backup_ram_slot_t) * BACKUP_RAM_SLOT_COUNT);
-
- memset(drv->payload, 0, sizeof(drv->payload));
- drv->next_seq = 0;
- drv->payload_size = 0;
-
- irq_unlock(irq_key);
-
- return true;
-}
-
-static bool is_slot_valid(const backup_ram_slot_t* slot) {
- if (slot->guard != BACKUP_RAM_GUARD_OK) {
- // Invalid guard value, slot is not valid
- return false;
- }
-
- if (slot->reserved != 0) {
- // Reserved bytes must be zero
- return false;
- }
-
- if (slot->header.size > BACKUP_RAM_MAX_PAYLOAD_SIZE) {
- // Invalid reported size
- return false;
- }
-
- uint16_t crc = BACKUP_RAM_CRC16_INITIAL;
- crc = backup_ram_crc16(&slot->header, sizeof(slot->header), crc);
- crc = backup_ram_crc16(slot->payload, slot->header.size, crc);
-
- if (crc != slot->crc) {
- // CRC mismatch, slot is invalid
- return false;
- }
-
- if (!is_payload_valid(slot->payload, slot->header.size)) {
- // Invalid key-value pairs in the payload
- return false;
- }
-
- return true;
-}
-
-static void backup_ram_reload(void) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- int newest_seq = -1;
-
- // Find the newest valid slot & clear invalid slots
- for (int i = 0; i < BACKUP_RAM_SLOT_COUNT; ++i) {
- backup_ram_slot_t* slot = &g_backup_ram[i];
- if (is_slot_valid(slot) && (SEQ_TO_INDEX(slot->header.seq) == i)) {
- if (newest_seq < 0) {
- newest_seq = slot->header.seq;
- } else if ((int16_t)(slot->header.seq - newest_seq) > 0) {
- newest_seq = slot->header.seq;
- }
- } else {
- // Slot is invalid, clear it
- memset(slot, 0, sizeof(backup_ram_slot_t));
- }
- }
-
- memset(drv->payload, 0, sizeof(drv->payload));
- drv->payload_size = 0;
- drv->next_seq = 0;
-
- if (newest_seq >= 0) {
- backup_ram_slot_t* slot = &g_backup_ram[SEQ_TO_INDEX(newest_seq)];
- memcpy(drv->payload, slot->payload, slot->header.size);
- drv->payload_size = slot->header.size;
- drv->next_seq = newest_seq + 1;
- }
-}
-
-static bool backup_ram_commit(void) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (!drv->initialized) {
- return false;
- }
-
- backup_ram_payload_header_t header = {
- .seq = drv->next_seq,
- .size = drv->payload_size,
- };
-
- uint16_t crc = BACKUP_RAM_CRC16_INITIAL;
- crc = backup_ram_crc16(&header, sizeof(header), crc);
- crc = backup_ram_crc16(drv->payload, drv->payload_size, crc);
-
- volatile backup_ram_slot_t* slot = &g_backup_ram[SEQ_TO_INDEX(drv->next_seq)];
-
- // Invalidate the slot first
- slot->guard = BACKUP_RAM_GUARD_NOK;
- slot->crc = 0;
-
- // Update crc and payload header
- slot->header = header;
-
- // Copy the payload data
- uint32_t* src = (uint32_t*)drv->payload;
- volatile uint32_t* dst = (uint32_t*)slot->payload;
- volatile uint32_t* end = (uint32_t*)(slot->payload + drv->payload_size);
- while (dst < end) {
- *dst++ = *src++;
- }
-
- // Fill the rest of the slot with zeros
- end = (uint32_t*)(slot->payload + BACKUP_RAM_MAX_PAYLOAD_SIZE);
- while (dst < end) {
- *dst++ = 0;
- }
-
- // Make slot valid again
- slot->reserved = 0;
- slot->crc = crc;
- slot->guard = BACKUP_RAM_GUARD_OK;
-
- ++drv->next_seq;
-
- return true;
-}
-
-typedef struct {
- // Key for the item
- uint16_t key;
- // Size of the data in bytes
- uint16_t data_size;
- // Type of the item
- uint8_t item_type;
- // reserved, must be zero
- uint8_t reserved;
- // Value data (variable length, aligned to 4 bytes)
- uint8_t data[];
-} backup_ram_item_t;
-
-_Static_assert(sizeof(backup_ram_item_t) == 6,
- "backup_ram_item_t size mismatch");
-
-#define ITEM_SIZE(data_size) \
- (sizeof(backup_ram_item_t) + ALIGN_UP(data_size, 4))
-
-static bool is_payload_valid(const uint8_t* payload, size_t payload_size) {
- uint32_t offset = 0;
-
- while (offset + ITEM_SIZE(0) <= payload_size) {
- backup_ram_item_t* item = (backup_ram_item_t*)(payload + offset);
- offset += ITEM_SIZE(item->data_size);
- }
-
- return offset == payload_size;
-}
-
-// Find an item in the backup RAM by its key
-static backup_ram_item_t* backup_ram_find_item(uint16_t key) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (!drv->initialized) {
- return NULL;
- }
-
- uint32_t offset = 0;
-
- while (offset + ITEM_SIZE(0) <= drv->payload_size) {
- backup_ram_item_t* item = (backup_ram_item_t*)(drv->payload + offset);
-
- if (item->key == key) {
- return item;
- }
-
- offset += ITEM_SIZE(item->data_size);
- }
-
- return NULL;
-}
-
-uint16_t backup_ram_search(uint16_t min_key) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (!drv->initialized) {
- return BACKUP_RAM_INVALID_KEY;
- }
-
- uint32_t offset = 0;
- uint16_t key = BACKUP_RAM_INVALID_KEY;
-
- while (offset + ITEM_SIZE(0) <= drv->payload_size) {
- backup_ram_item_t* item = (backup_ram_item_t*)(drv->payload + offset);
-
- if (item->key >= min_key && item->key < key) {
- key = item->key;
- }
-
- offset += ITEM_SIZE(item->data_size);
- }
-
- return key;
-}
-
-bool backup_ram_erase_item(uint16_t key) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (!drv->initialized) {
- return false;
- }
-
- irq_key_t irq_key = irq_lock();
- // Writing data_size==0 will just remove the item with the given key
- // Type is don't care in this case.
- bool status = backup_ram_write(key, BACKUP_RAM_ITEM_PUBLIC, NULL, 0);
- irq_unlock(irq_key);
-
- return status;
-}
-
-bool backup_ram_erase_protected(void) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
- if (!drv->initialized) {
- return false;
- }
-
- // Lock interrupts while we mutate the in-RAM copy of the payload
- irq_key_t irq_key = irq_lock();
-
- uint32_t offset = 0;
- // Walk the payload buffer
- while (offset + ITEM_SIZE(0) <= drv->payload_size) {
- backup_ram_item_t* item = (backup_ram_item_t*)(drv->payload + offset);
- size_t this_size = ITEM_SIZE(item->data_size);
-
- if (item->item_type != BACKUP_RAM_ITEM_PUBLIC) {
- // Remove this item by sliding the remainder of the payload down over it
- uint8_t* next_item = (uint8_t*)item + this_size;
- size_t tail_bytes = drv->payload_size - (offset + this_size);
- memmove(item, next_item, tail_bytes);
- drv->payload_size -= this_size;
- // don't advance offset: new item has just been shifted into this slot
- } else {
- // keep this public item: skip over it
- offset += this_size;
- }
- }
-
- // write the cleaned payload back into flash-backed RAM
- bool success = backup_ram_commit();
- irq_unlock(irq_key);
- return success;
-}
-
-bool backup_ram_read(uint16_t key, void* buffer, size_t buffer_size,
- size_t* data_size) {
- bool success = false;
- irq_key_t irq_key = irq_lock();
-
- backup_ram_item_t* item = backup_ram_find_item(key);
-
- if (data_size != NULL) {
- *data_size = item ? item->data_size : 0;
- }
-
- if (item == NULL) {
- goto cleanup;
- }
-
- if (buffer != NULL && item->data_size > buffer_size) {
- // Not enough space in the buffer
- goto cleanup;
- }
-
- if (buffer != NULL) {
- memcpy(buffer, item->data, item->data_size);
- }
-
- success = true;
-
-cleanup:
- irq_unlock(irq_key);
- return success;
-}
-
-bool backup_ram_write(uint16_t key, backup_ram_item_type_t type,
- const void* data, size_t data_size) {
- backup_ram_driver_t* drv = &g_backup_ram_driver;
-
- if (!drv->initialized) {
- return false;
- }
-
- if (data_size > BACKUP_RAM_MAX_KEY_DATA_SIZE) {
- // Data size exceeds maximum allowed size
- return false;
- }
-
- bool success = false;
-
- irq_key_t irq_key = irq_lock();
-
- backup_ram_item_t* item = backup_ram_find_item(key);
-
- if (item != NULL && item->item_type != type && data_size != 0) {
- // Item exists but has a different type, not supported
- goto cleanup;
- }
-
- if (item != NULL && item->data_size == data_size) {
- // The most common case: item exists and has the same size
- memcpy(item->data, data, data_size);
- } else {
- // Check if we have enough space for the new item
- size_t free_space = BACKUP_RAM_MAX_PAYLOAD_SIZE - drv->payload_size;
-
- if (item != NULL) {
- // Add the size of the existing item to the free space
- free_space += ITEM_SIZE(item->data_size);
- }
-
- if (ITEM_SIZE(data_size) > free_space) {
- // Not enough space for the new item
- goto cleanup;
- }
-
- // Remove the item if it exists
- if (item != NULL) {
- size_t deleted_size = ITEM_SIZE(item->data_size);
- uint8_t* next_item = (uint8_t*)item + deleted_size;
- uint8_t* end_of_payload = drv->payload + drv->payload_size;
- assert(next_item <= end_of_payload);
- memmove(item, next_item, end_of_payload - next_item);
- drv->payload_size -= deleted_size;
- }
-
- // Add a new item at the end of the payload
- if (data_size > 0) {
- item = (backup_ram_item_t*)&drv->payload[drv->payload_size];
- item->key = key;
- item->data_size = data_size;
- item->item_type = type;
- item->reserved = 0;
- memcpy(item->data, data, data_size);
- memset(&item->data[data_size], 0, ALIGN_UP(data_size, 4) - data_size);
- drv->payload_size += ITEM_SIZE(data_size);
- }
- }
-
- // Commit the changes to backup RAM
- success = backup_ram_commit();
-
-cleanup:
- irq_unlock(irq_key);
- return success;
-}
-
-bool backup_ram_kernel_accessible(uint16_t key) {
- return (key == BACKUP_RAM_KEY_PM_RECOVERY ||
- key == BACKUP_RAM_KEY_BLE_SETTINGS);
-}
-
-#endif // SECURE_MODE
diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c
index 0be0746e..ed9b7aa6 100644
--- a/core/embed/sys/power_manager/stm32u5/power_manager.c
+++ b/core/embed/sys/power_manager/stm32u5/power_manager.c
@@ -20,7 +20,7 @@
#include <trezor_rtl.h>
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#include <sys/irq.h>
#include <sys/pmic.h>
#include <sys/suspend.h>
diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c
index 8b3900a1..2ff4116f 100644
--- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c
+++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c
@@ -18,7 +18,7 @@
*/
#ifdef KERNEL_MODE
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#include <sys/irq.h>
#include <sys/notify.h>
#include <sys/pmic.h>
diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c
index f3f6ffe1..bfcb9b4c 100644
--- a/core/embed/sys/smcall/stm32/smcall_dispatch.c
+++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c
@@ -34,7 +34,7 @@
#include <util/unit_properties.h>
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
#endif
#ifdef USE_OPTIGA
diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c
index 220245a0..cf227b8e 100644
--- a/core/embed/sys/smcall/stm32/smcall_stubs.c
+++ b/core/embed/sys/smcall/stm32/smcall_stubs.c
@@ -375,7 +375,7 @@ bool tropic_data_read(uint16_t udata_slot, uint8_t *data, uint16_t *size) {
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
uint16_t backup_ram_search(uint16_t min_key) {
return (bool)smcall_invoke1(min_key, SMCALL_BACKUP_RAM_SEARCH);
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.h b/core/embed/sys/smcall/stm32/smcall_verifiers.h
index d627b6c4..beedbfe8 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.h
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.h
@@ -144,7 +144,7 @@ bool tropic_data_read__verified(uint16_t udata_slot, uint8_t *data,
#ifdef USE_BACKUP_RAM
-#include <sys/backup_ram.h>
+#include <sec/backup_ram.h>
bool backup_ram_read__verified(uint16_t key, void *buffer, size_t buffer_size,
size_t *data_size);
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
index a572fed0..5bdc16d3 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
@@ -104,10 +104,10 @@ def configure(
defines += [("USE_I2C", "1")]
sources += [
- "embed/sys/backup_ram/backup_ram_crc.c",
- "embed/sys/backup_ram/stm32u5/backup_ram.c",
+ "embed/sec/backup_ram/backup_ram_crc.c",
+ "embed/sec/backup_ram/stm32u5/backup_ram.c",
]
- paths += ["embed/sys/backup_ram/inc"]
+ paths += ["embed/sec/backup_ram/inc"]
defines += [("USE_BACKUP_RAM", "1")]
if "rtc" in features_wanted:
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
index 4108709a..b2a007a3 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
@@ -104,11 +104,11 @@ def configure(
defines += [("USE_I2C", "1")]
sources += [
- "embed/sys/backup_ram/backup_ram_crc.c",
- "embed/sys/backup_ram/stm32u5/backup_ram.c",
+ "embed/sec/backup_ram/backup_ram_crc.c",
+ "embed/sec/backup_ram/stm32u5/backup_ram.c",
]
- paths += ["embed/sys/backup_ram/inc"]
+ paths += ["embed/sec/backup_ram/inc"]
defines += [("USE_BACKUP_RAM", "1")]
if "rtc" in features_wanted:
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
index 3c7e1caa..fed9d25a 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
@@ -104,10 +104,10 @@ def configure(
defines += [("USE_I2C", "1")]
sources += [
- "embed/sys/backup_ram/backup_ram_crc.c",
- "embed/sys/backup_ram/stm32u5/backup_ram.c",
+ "embed/sec/backup_ram/backup_ram_crc.c",
+ "embed/sec/backup_ram/stm32u5/backup_ram.c",
]
- paths += ["embed/sys/backup_ram/inc"]
+ paths += ["embed/sec/backup_ram/inc"]
defines += [("USE_BACKUP_RAM", "1")]
if "rtc" in features_wanted:
Why this scored 13/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.