From 7275a5544e53abd4d7b090c7bea0ea42062f3cc2 Mon Sep 17 00:00:00 2001
From: tychovrahe <brunam@seznam.cz>
Date: Mon, 26 Aug 2024 17:53:14 +0200
Subject: [PATCH] refactor(core): move embedded bootloaders and their hashes to
 model folders

[no changelog]
---
 core/SConscript.firmware                      |   2 +-
 core/embed/firmware/bl_check.c                |  70 +-----------------
 core/embed/firmware/bootloader_hashes.py      |  49 +++++++-----
 .../firmware/bootloaders/bootloader_1.bin     |   1 -
 .../firmware/bootloaders/bootloader_T1B1.bin  | Bin 32768 -> 0 bytes
 .../T2B1}/bootloaders/bootloader_T2B1.bin     | Bin
 .../T2B1}/bootloaders/bootloader_T2B1_qa.bin  | Bin
 .../T2B1/bootloaders/bootloader_hashes.h      |  17 +++++
 core/embed/models/T2B1/model_T2B1.h           |   2 +
 .../T2T1}/bootloaders/bootloader_T2T1.bin     | Bin
 .../T2T1}/bootloaders/bootloader_T2T1_qa.bin  | Bin
 .../T2T1/bootloaders/bootloader_hashes.h      |  17 +++++
 core/embed/models/T2T1/model_T2T1.h           |   2 +
 .../T3B1}/bootloaders/bootloader_T3B1.bin     | Bin
 .../T3B1}/bootloaders/bootloader_T3B1_qa.bin  | Bin
 .../T3B1/bootloaders/bootloader_hashes.h      |  17 +++++
 core/embed/models/T3B1/model_T3B1.h           |   2 +
 .../T3T1}/bootloaders/bootloader_T3T1.bin     | Bin
 .../T3T1}/bootloaders/bootloader_T3T1_qa.bin  | Bin
 .../T3T1/bootloaders/bootloader_hashes.h      |  17 +++++
 core/embed/models/T3T1/model_T3T1.h           |   2 +
 21 files changed, 108 insertions(+), 90 deletions(-)
 delete mode 120000 core/embed/firmware/bootloaders/bootloader_1.bin
 delete mode 100644 core/embed/firmware/bootloaders/bootloader_T1B1.bin
 rename core/embed/{firmware => models/T2B1}/bootloaders/bootloader_T2B1.bin (100%)
 rename core/embed/{firmware => models/T2B1}/bootloaders/bootloader_T2B1_qa.bin (100%)
 create mode 100644 core/embed/models/T2B1/bootloaders/bootloader_hashes.h
 rename core/embed/{firmware => models/T2T1}/bootloaders/bootloader_T2T1.bin (100%)
 rename core/embed/{firmware => models/T2T1}/bootloaders/bootloader_T2T1_qa.bin (100%)
 create mode 100644 core/embed/models/T2T1/bootloaders/bootloader_hashes.h
 rename core/embed/{firmware => models/T3B1}/bootloaders/bootloader_T3B1.bin (100%)
 rename core/embed/{firmware => models/T3B1}/bootloaders/bootloader_T3B1_qa.bin (100%)
 create mode 100644 core/embed/models/T3B1/bootloaders/bootloader_hashes.h
 rename core/embed/{firmware => models/T3T1}/bootloaders/bootloader_T3T1.bin (100%)
 rename core/embed/{firmware => models/T3T1}/bootloaders/bootloader_T3T1_qa.bin (100%)
 create mode 100644 core/embed/models/T3T1/bootloaders/bootloader_hashes.h

diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index b80fde68a8..5e199f2617 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -912,7 +912,7 @@ if TREZOR_MODEL not in ('DISC1', 'DISC2'):
             env,
             'bootloader',
             'embed/firmware/bootloaders/bootloader.o',
-            f'embed/firmware/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin',
+            f'embed/models/{MODEL_IDENTIFIER}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin',
             )
 
 
diff --git a/core/embed/firmware/bl_check.c b/core/embed/firmware/bl_check.c
index c5e13f081b..c172df62d6 100644
--- a/core/embed/firmware/bl_check.c
+++ b/core/embed/firmware/bl_check.c
@@ -34,79 +34,13 @@ extern const void
 extern const void
     _binary_embed_firmware_bootloaders_bootloader_bin_deflated_size;
 
-/*
-static secbool known_bootloader(const uint8_t *hash, int len) {
-    if (len != 32) return secfalse;
-    // bootloader-2.0.1.bin (padded with 0x00)
-    if (0 == memcmp(hash,
-"\x91\x37\x46\xd0\x2d\xa7\xc4\xbe\x1d\xae\xef\xb0\x9b\x4e\x31\x88\xed\x38\x23\x5e\x0e\x31\xa7\x8c\x01\xde\x4e\xcc\xc2\xd6\x36\xb3",
-32)) return sectrue;
-    // bootloader-2.0.1.bin (padded with 0xff)
-    if (0 == memcmp(hash,
-"\x2f\xdb\xde\x94\x0a\xd8\x91\x1c\xbd\x07\xb0\xba\x06\x2c\x90\x84\x02\xec\x95\x19\xde\x52\x8d\x4b\xe9\xb9\xed\x30\x71\x91\xb4\xd3",
-32)) return sectrue;
-    // bootloader-2.0.2.bin (padded with 0x00)
-    if (0 == memcmp(hash,
-"\x2e\xf7\x47\xf8\x49\x87\x1e\xc8\xc6\x01\x35\xd6\x32\xe5\x5a\xd1\x56\x18\xf8\x64\x87\xb7\xaa\x7c\x62\x0e\xc3\x0d\x25\x69\x4e\x18",
-32)) return sectrue;
-    // bootloader-2.0.2.bin (padded with 0xff)
-    if (0 == memcmp(hash,
-"\xcc\x6b\x35\xc3\x8f\x29\x5c\xbd\x7d\x31\x69\xaf\xae\xf1\x61\x01\xef\xbe\x9f\x3b\x0a\xfd\xc5\x91\x70\x9b\xf5\xa0\xd5\xa4\xc5\xe0",
-32)) return sectrue;
-    // bootloader-2.0.3.bin (padded with 0x00)
-    if (0 == memcmp(hash,
-"\xb1\x83\xd3\x31\xc7\xff\x3d\xcf\x54\x1e\x7e\x40\xf4\x9e\xc3\x53\x4c\xcc\xf3\x8c\x35\x39\x88\x81\x65\xc0\x5c\x25\xbd\xfc\xea\x14",
-32)) return sectrue;
-    // bootloader-2.0.3.bin (padded with 0xff)
-    if (0 == memcmp(hash,
-"\xab\xdb\x7d\xe2\xef\x44\x66\xa7\xb7\x1f\x2b\x02\xf3\xe1\x40\xe7\xcd\xf2\x8e\xc0\xbb\x33\x04\xce\x0d\xa5\xca\x02\x57\xb6\xd4\x30",
-32)) return sectrue; return secfalse;
-}
-*/
-
-// clang-format off
-// --- BEGIN GENERATED BOOTLOADER SECTION ---
-// bootloader_1.bin version <unknown>
-#define BOOTLOADER_1_00 {0xa5, 0x5a, 0x8b, 0x88, 0x94, 0x8a, 0x33, 0x2b, 0xed, 0x0d, 0xd9, 0x5c, 0x79, 0xd5, 0xbe, 0x0c, 0x73, 0x52, 0xaa, 0xac, 0xb3, 0x4f, 0xea, 0xd0, 0xaa, 0x88, 0x33, 0x23, 0x64, 0xab, 0x77, 0x5a}
-#define BOOTLOADER_1_FF {0x50, 0x6c, 0x5f, 0xd3, 0x73, 0x7b, 0x9b, 0xb7, 0xb9, 0xbf, 0xf9, 0xfa, 0xc6, 0xb9, 0x43, 0x27, 0x8b, 0x06, 0xad, 0x3a, 0xec, 0xce, 0x35, 0xa3, 0x52, 0xc3, 0x6e, 0x9e, 0x9a, 0xb3, 0x50, 0x98}
-// bootloader_T1B1.bin version <unknown>
-#define BOOTLOADER_T1B1_00 {0xc1, 0x01, 0xd3, 0x8a, 0x00, 0x5e, 0x4f, 0x5f, 0x87, 0x1f, 0x49, 0x78, 0x24, 0x9c, 0xf9, 0x82, 0xd1, 0x91, 0x4b, 0xa6, 0x90, 0x03, 0x9c, 0x50, 0x49, 0x61, 0x10, 0x4f, 0xee, 0xe7, 0x1d, 0x7b}
-#define BOOTLOADER_T1B1_FF {0xbd, 0xb2, 0xf7, 0x62, 0xfb, 0x10, 0xbb, 0x30, 0x1f, 0x95, 0xa3, 0x12, 0x6b, 0x41, 0x1f, 0x66, 0xfc, 0x57, 0x28, 0xce, 0x7f, 0x59, 0x42, 0x6c, 0x3e, 0xed, 0xf7, 0x69, 0xbb, 0x96, 0xbd, 0x4b}
-// bootloader_T2B1.bin version 2.1.4.0
-#define BOOTLOADER_T2B1_00 {0x12, 0xf5, 0x51, 0x01, 0x10, 0xb3, 0x59, 0x8e, 0x73, 0x95, 0xa9, 0xa8, 0xc5, 0xbc, 0x3a, 0x53, 0xa3, 0xa8, 0xed, 0x83, 0x32, 0xc2, 0xd2, 0x5b, 0x47, 0x99, 0x27, 0x9f, 0x93, 0x8b, 0xb3, 0xd6}
-#define BOOTLOADER_T2B1_FF {0x19, 0x7c, 0x2a, 0xd1, 0xba, 0x89, 0xeb, 0x2a, 0xfc, 0xe1, 0x7b, 0xf3, 0x62, 0x7d, 0xf8, 0xb2, 0x3c, 0x70, 0x16, 0x03, 0x53, 0xad, 0x8e, 0x90, 0x9b, 0x57, 0xeb, 0x4b, 0x83, 0x4d, 0xa0, 0x34}
-// bootloader_T2B1_qa.bin version 2.1.4.0
-#define BOOTLOADER_T2B1_QA_00 {0x96, 0xe7, 0xfa, 0x21, 0x66, 0x81, 0x6b, 0x27, 0xf6, 0x27, 0xc1, 0x50, 0xaa, 0xf8, 0xbf, 0xac, 0xf5, 0x0d, 0x37, 0xea, 0x10, 0xa9, 0xa2, 0x0c, 0x1a, 0x58, 0xa7, 0x42, 0x23, 0x80, 0xbe, 0x40}
-#define BOOTLOADER_T2B1_QA_FF {0x7c, 0xca, 0xde, 0xf6, 0x8f, 0xf8, 0x9a, 0x08, 0x35, 0x0a, 0x82, 0xe4, 0xb5, 0x76, 0x37, 0x36, 0x51, 0x33, 0x40, 0xd9, 0x66, 0x84, 0xfb, 0x1b, 0x4f, 0x89, 0x34, 0xcd, 0x6f, 0x4c, 0x03, 0x1a}
-// bootloader_T2T1.bin version 2.1.4.0
-#define BOOTLOADER_T2T1_00 {0x37, 0xaf, 0xad, 0xb6, 0x55, 0x7a, 0xd3, 0x82, 0x2c, 0x7b, 0xd3, 0x41, 0x65, 0xb7, 0x4d, 0xce, 0xbe, 0x23, 0x87, 0x90, 0x93, 0x3f, 0xbc, 0x4c, 0x5a, 0x1c, 0x60, 0x8c, 0xf9, 0xf6, 0xec, 0x0c}
-#define BOOTLOADER_T2T1_FF {0x5e, 0x84, 0xd3, 0xf7, 0xfd, 0x55, 0x51, 0xfd, 0x5f, 0x22, 0xc4, 0x83, 0xe2, 0x67, 0xc5, 0x1b, 0x77, 0xce, 0x49, 0xce, 0x42, 0x19, 0xe8, 0x23, 0x84, 0x4a, 0x58, 0x47, 0xaf, 0x80, 0x69, 0x86}
-// bootloader_T2T1_qa.bin version 2.1.4.0
-#define BOOTLOADER_T2T1_QA_00 {0xff, 0xda, 0xfd, 0x0f, 0xe1, 0x89, 0x56, 0xb6, 0x0b, 0x6e, 0x2d, 0x67, 0xf1, 0x63, 0x8c, 0x4c, 0x4d, 0x6f, 0x97, 0xe7, 0xe0, 0xa4, 0xce, 0x76, 0xc9, 0x49, 0x0a, 0x34, 0x3e, 0xd8, 0xcb, 0x1f}
-#define BOOTLOADER_T2T1_QA_FF {0xbe, 0x31, 0x71, 0x7b, 0x8b, 0x31, 0x12, 0xbd, 0x58, 0xc4, 0x81, 0x09, 0x8d, 0xd9, 0x07, 0x51, 0x5c, 0xb6, 0x3d, 0x07, 0x82, 0x00, 0x30, 0x4a, 0xeb, 0x26, 0xf0, 0xe4, 0x00, 0xd4, 0xf2, 0x9c}
-// bootloader_T3B1.bin version 2.1.7.0
-#define BOOTLOADER_T3B1_00 {0x6a, 0x29, 0x58, 0x1f, 0x4f, 0x0c, 0x64, 0xd0, 0x57, 0xb3, 0x36, 0xb7, 0xca, 0xc5, 0x00, 0xc6, 0xbe, 0x87, 0x46, 0x10, 0x48, 0xb0, 0x20, 0xc5, 0xc3, 0x55, 0xaa, 0xf8, 0xec, 0x48, 0xd6, 0xa3}
-#define BOOTLOADER_T3B1_FF {0x57, 0x1e, 0xa2, 0xb8, 0x09, 0xf0, 0xab, 0xb4, 0x35, 0xb9, 0x92, 0xcd, 0xde, 0x28, 0x8a, 0xe2, 0x73, 0x04, 0x92, 0x16, 0x01, 0xac, 0x70, 0x48, 0xad, 0x1d, 0x72, 0x9e, 0x31, 0x42, 0xbf, 0x37}
-// bootloader_T3B1_qa.bin version 2.1.7.0
-#define BOOTLOADER_T3B1_QA_00 {0x2e, 0x90, 0x8a, 0x99, 0x25, 0x93, 0xcd, 0x9c, 0xf1, 0x23, 0x1e, 0x4e, 0x41, 0xfc, 0xc9, 0xf1, 0x4b, 0x06, 0x69, 0x57, 0x6e, 0x64, 0x84, 0x1c, 0xb1, 0xd9, 0x89, 0x0c, 0xa5, 0xb4, 0x38, 0xeb}
-#define BOOTLOADER_T3B1_QA_FF {0x63, 0xd2, 0x2d, 0x7b, 0xe8, 0x17, 0x2b, 0x97, 0x64, 0x06, 0x9b, 0x60, 0xa0, 0x3d, 0xfc, 0xd6, 0xea, 0x8a, 0x8d, 0xaf, 0x12, 0x25, 0x58, 0x93, 0x9e, 0x40, 0x16, 0xf2, 0x25, 0x30, 0x30, 0x6f}
-// bootloader_T3T1.bin version 2.1.6.0
-#define BOOTLOADER_T3T1_00 {0x4a, 0x07, 0x5c, 0x74, 0x0f, 0x9a, 0x84, 0x61, 0xaf, 0x10, 0x34, 0x9c, 0x24, 0x3d, 0x79, 0x5b, 0xc6, 0x12, 0x5e, 0xec, 0x51, 0xb3, 0x91, 0x4b, 0x65, 0xf9, 0x79, 0x17, 0x98, 0xc2, 0x4f, 0xcb}
-#define BOOTLOADER_T3T1_FF {0xd8, 0xee, 0x0d, 0xd8, 0x87, 0x0b, 0xf4, 0x38, 0x73, 0x52, 0x83, 0x5e, 0xa9, 0xef, 0x3e, 0x5a, 0x3e, 0x59, 0xc2, 0x12, 0x5b, 0x24, 0xc9, 0x2d, 0xd4, 0xc5, 0xf5, 0x57, 0x15, 0x8a, 0x34, 0x78}
-// bootloader_T3T1_qa.bin version 2.1.6.0
-#define BOOTLOADER_T3T1_QA_00 {0x53, 0x5f, 0xf9, 0xa8, 0x21, 0x7d, 0xb5, 0x39, 0xe4, 0xfa, 0xf8, 0x3d, 0x0d, 0xe6, 0xf3, 0x65, 0x21, 0x30, 0x46, 0x9e, 0x40, 0x85, 0xd4, 0xd8, 0x49, 0x00, 0xb0, 0xb5, 0x58, 0x39, 0xe3, 0xd4}
-#define BOOTLOADER_T3T1_QA_FF {0x1e, 0x03, 0x50, 0x25, 0xa1, 0xc7, 0x20, 0xe2, 0x04, 0x62, 0x24, 0xa1, 0x31, 0xc2, 0xf5, 0x7b, 0x35, 0xe9, 0x22, 0x42, 0x36, 0x2d, 0xab, 0xcc, 0xb6, 0x3b, 0xfe, 0x88, 0x53, 0x2f, 0x49, 0xa7}
-// --- END GENERATED BOOTLOADER SECTION ---
-
-
 #define CONCAT_NAME_HELPER(prefix, name, suffix) prefix##name##suffix
 #define CONCAT_NAME(name, var) CONCAT_NAME_HELPER(BOOTLOADER_, name, var)
 
-
 #if BOOTLOADER_QA
 // QA bootloaders
-    #define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_00)
-    #define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_FF)
+#define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_00)
+#define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_FF)
 #else
 // normal bootloaders
 #define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _00)
diff --git a/core/embed/firmware/bootloader_hashes.py b/core/embed/firmware/bootloader_hashes.py
index 2661847e60..3e72aeb733 100755
--- a/core/embed/firmware/bootloader_hashes.py
+++ b/core/embed/firmware/bootloader_hashes.py
@@ -7,7 +7,7 @@ from trezorlib.firmware.core import FirmwareImage
 ALIGNED_SIZE = 128 * 1024
 
 HERE = Path(__file__).parent
-BOOTLOADERS = HERE / "bootloaders"
+BOOTLOADERS = HERE / ".." / "models"
 
 BL_CHECK = HERE / "bl_check.c"
 
@@ -74,29 +74,38 @@ def bootloader_str(file: Path) -> str:
 
 
 def main():
-    bl_check_new = []
-    with open(BL_CHECK) as f:
-        # read up to auto-begin
-        for line in f:
-            bl_check_new.append(line)
-            if line == BL_CHECK_AUTO_BEGIN:
-                break
 
-        # write bootloader definitions
-        for file in sorted(BOOTLOADERS.glob("bootloader*.bin")):
-            bl_check_new.append(bootloader_str(file))
+    models = list(BOOTLOADERS.iterdir())
 
-        # consume up to auto-end
-        for line in f:
-            if line == BL_CHECK_AUTO_END:
-                bl_check_new.append(line)
-                break
+    models = [model for model in models if model.is_dir()]
 
-        # read the rest
-        bl_check_new.extend(f)
+    for model in models:
 
-    # write the file
-    BL_CHECK.write_text("".join(bl_check_new))
+        path = model / "bootloaders"
+
+        if path.is_dir():
+
+            header_file = path / "bootloader_hashes.h"
+
+            content = []
+            content.append("#ifndef BOOTLOADER_HASHES_H\n")
+            content.append("#define BOOTLOADER_HASHES_H\n")
+            content.append("\n")
+            content.append("// Auto-generated file, do not edit.\n")
+            content.append("\n")
+            content.append("// clang-format off\n")
+
+            bootloaders = sorted(path.glob("bootloader*.bin"))
+            for bootloader in bootloaders:
+                if bootloader.is_file():
+                    print(f"Processing {bootloader}")
+                    content.append(bootloader_str(bootloader))
+
+            content.append("// clang-format on\n")
+            content.append("\n")
+            content.append("#endif\n")
+
+            header_file.write_text("".join(content))
 
 
 if __name__ == "__main__":
diff --git a/core/embed/firmware/bootloaders/bootloader_1.bin b/core/embed/firmware/bootloaders/bootloader_1.bin
deleted file mode 120000
index 6a019c96b1..0000000000
--- a/core/embed/firmware/bootloaders/bootloader_1.bin
+++ /dev/null
@@ -1 +0,0 @@
-../../../../legacy/firmware/bootloader.dat
\ No newline at end of file
diff --git a/core/embed/firmware/bootloaders/bootloader_T1B1.bin b/core/embed/firmware/bootloaders/bootloader_T1B1.bin
deleted file mode 100644
index ac9d56f2307c80722bd3ca49998efa776cac2de7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 32768
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
RdoQ>lH%j0}3H)zM;CFAsl2iZy

diff --git a/core/embed/firmware/bootloaders/bootloader_T2B1.bin b/core/embed/models/T2B1/bootloaders/bootloader_T2B1.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T2B1.bin
rename to core/embed/models/T2B1/bootloaders/bootloader_T2B1.bin
diff --git a/core/embed/firmware/bootloaders/bootloader_T2B1_qa.bin b/core/embed/models/T2B1/bootloaders/bootloader_T2B1_qa.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T2B1_qa.bin
rename to core/embed/models/T2B1/bootloaders/bootloader_T2B1_qa.bin
diff --git a/core/embed/models/T2B1/bootloaders/bootloader_hashes.h b/core/embed/models/T2B1/bootloaders/bootloader_hashes.h
new file mode 100644
index 0000000000..2e65297edc
--- /dev/null
+++ b/core/embed/models/T2B1/bootloaders/bootloader_hashes.h
@@ -0,0 +1,17 @@
+#ifndef BOOTLOADER_HASHES_H
+#define BOOTLOADER_HASHES_H
+
+// Auto-generated file, do not edit.
+
+// clang-format off
+// bootloader_T2B1.bin version 2.1.4.0
+#define BOOTLOADER_T2B1_00 {0x12, 0xf5, 0x51, 0x01, 0x10, 0xb3, 0x59, 0x8e, 0x73, 0x95, 0xa9, 0xa8, 0xc5, 0xbc, 0x3a, 0x53, 0xa3, 0xa8, 0xed, 0x83, 0x32, 0xc2, 0xd2, 0x5b, 0x47, 0x99, 0x27, 0x9f, 0x93, 0x8b, 0xb3, 0xd6}
+#define BOOTLOADER_T2B1_FF {0x19, 0x7c, 0x2a, 0xd1, 0xba, 0x89, 0xeb, 0x2a, 0xfc, 0xe1, 0x7b, 0xf3, 0x62, 0x7d, 0xf8, 0xb2, 0x3c, 0x70, 0x16, 0x03, 0x53, 0xad, 0x8e, 0x90, 0x9b, 0x57, 0xeb, 0x4b, 0x83, 0x4d, 0xa0, 0x34}
+
+// bootloader_T2B1_qa.bin version 2.1.4.0
+#define BOOTLOADER_T2B1_QA_00 {0x96, 0xe7, 0xfa, 0x21, 0x66, 0x81, 0x6b, 0x27, 0xf6, 0x27, 0xc1, 0x50, 0xaa, 0xf8, 0xbf, 0xac, 0xf5, 0x0d, 0x37, 0xea, 0x10, 0xa9, 0xa2, 0x0c, 0x1a, 0x58, 0xa7, 0x42, 0x23, 0x80, 0xbe, 0x40}
+#define BOOTLOADER_T2B1_QA_FF {0x7c, 0xca, 0xde, 0xf6, 0x8f, 0xf8, 0x9a, 0x08, 0x35, 0x0a, 0x82, 0xe4, 0xb5, 0x76, 0x37, 0x36, 0x51, 0x33, 0x40, 0xd9, 0x66, 0x84, 0xfb, 0x1b, 0x4f, 0x89, 0x34, 0xcd, 0x6f, 0x4c, 0x03, 0x1a}
+
+// clang-format on
+
+#endif
diff --git a/core/embed/models/T2B1/model_T2B1.h b/core/embed/models/T2B1/model_T2B1.h
index 9b384605db..d82aefc89b 100644
--- a/core/embed/models/T2B1/model_T2B1.h
+++ b/core/embed/models/T2B1/model_T2B1.h
@@ -1,6 +1,8 @@
 #ifndef MODELS_MODEL_T2B1_H_
 #define MODELS_MODEL_T2B1_H_
 
+#include "bootloaders/bootloader_hashes.h"
+
 #define MODEL_NAME "Safe 3"
 #define MODEL_FULL_NAME "Trezor Safe 3"
 #define MODEL_INTERNAL_NAME "T2B1"
diff --git a/core/embed/firmware/bootloaders/bootloader_T2T1.bin b/core/embed/models/T2T1/bootloaders/bootloader_T2T1.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T2T1.bin
rename to core/embed/models/T2T1/bootloaders/bootloader_T2T1.bin
diff --git a/core/embed/firmware/bootloaders/bootloader_T2T1_qa.bin b/core/embed/models/T2T1/bootloaders/bootloader_T2T1_qa.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T2T1_qa.bin
rename to core/embed/models/T2T1/bootloaders/bootloader_T2T1_qa.bin
diff --git a/core/embed/models/T2T1/bootloaders/bootloader_hashes.h b/core/embed/models/T2T1/bootloaders/bootloader_hashes.h
new file mode 100644
index 0000000000..de3db66f3d
--- /dev/null
+++ b/core/embed/models/T2T1/bootloaders/bootloader_hashes.h
@@ -0,0 +1,17 @@
+#ifndef BOOTLOADER_HASHES_H
+#define BOOTLOADER_HASHES_H
+
+// Auto-generated file, do not edit.
+
+// clang-format off
+// bootloader_T2T1.bin version 2.1.4.0
+#define BOOTLOADER_T2T1_00 {0x37, 0xaf, 0xad, 0xb6, 0x55, 0x7a, 0xd3, 0x82, 0x2c, 0x7b, 0xd3, 0x41, 0x65, 0xb7, 0x4d, 0xce, 0xbe, 0x23, 0x87, 0x90, 0x93, 0x3f, 0xbc, 0x4c, 0x5a, 0x1c, 0x60, 0x8c, 0xf9, 0xf6, 0xec, 0x0c}
+#define BOOTLOADER_T2T1_FF {0x5e, 0x84, 0xd3, 0xf7, 0xfd, 0x55, 0x51, 0xfd, 0x5f, 0x22, 0xc4, 0x83, 0xe2, 0x67, 0xc5, 0x1b, 0x77, 0xce, 0x49, 0xce, 0x42, 0x19, 0xe8, 0x23, 0x84, 0x4a, 0x58, 0x47, 0xaf, 0x80, 0x69, 0x86}
+
+// bootloader_T2T1_qa.bin version 2.1.4.0
+#define BOOTLOADER_T2T1_QA_00 {0xff, 0xda, 0xfd, 0x0f, 0xe1, 0x89, 0x56, 0xb6, 0x0b, 0x6e, 0x2d, 0x67, 0xf1, 0x63, 0x8c, 0x4c, 0x4d, 0x6f, 0x97, 0xe7, 0xe0, 0xa4, 0xce, 0x76, 0xc9, 0x49, 0x0a, 0x34, 0x3e, 0xd8, 0xcb, 0x1f}
+#define BOOTLOADER_T2T1_QA_FF {0xbe, 0x31, 0x71, 0x7b, 0x8b, 0x31, 0x12, 0xbd, 0x58, 0xc4, 0x81, 0x09, 0x8d, 0xd9, 0x07, 0x51, 0x5c, 0xb6, 0x3d, 0x07, 0x82, 0x00, 0x30, 0x4a, 0xeb, 0x26, 0xf0, 0xe4, 0x00, 0xd4, 0xf2, 0x9c}
+
+// clang-format on
+
+#endif
diff --git a/core/embed/models/T2T1/model_T2T1.h b/core/embed/models/T2T1/model_T2T1.h
index 47c75409c9..fc29eaf94c 100644
--- a/core/embed/models/T2T1/model_T2T1.h
+++ b/core/embed/models/T2T1/model_T2T1.h
@@ -1,6 +1,8 @@
 #ifndef MODELS_MODEL_T2T1_H_
 #define MODELS_MODEL_T2T1_H_
 
+#include "bootloaders/bootloader_hashes.h"
+
 #define MODEL_NAME "T"
 #define MODEL_FULL_NAME "Trezor Model T"
 #define MODEL_INTERNAL_NAME "T2T1"
diff --git a/core/embed/firmware/bootloaders/bootloader_T3B1.bin b/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T3B1.bin
rename to core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin
diff --git a/core/embed/firmware/bootloaders/bootloader_T3B1_qa.bin b/core/embed/models/T3B1/bootloaders/bootloader_T3B1_qa.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T3B1_qa.bin
rename to core/embed/models/T3B1/bootloaders/bootloader_T3B1_qa.bin
diff --git a/core/embed/models/T3B1/bootloaders/bootloader_hashes.h b/core/embed/models/T3B1/bootloaders/bootloader_hashes.h
new file mode 100644
index 0000000000..e01f324ce0
--- /dev/null
+++ b/core/embed/models/T3B1/bootloaders/bootloader_hashes.h
@@ -0,0 +1,17 @@
+#ifndef BOOTLOADER_HASHES_H
+#define BOOTLOADER_HASHES_H
+
+// Auto-generated file, do not edit.
+
+// clang-format off
+// bootloader_T3B1.bin version 2.1.7.0
+#define BOOTLOADER_T3B1_00 {0x6a, 0x29, 0x58, 0x1f, 0x4f, 0x0c, 0x64, 0xd0, 0x57, 0xb3, 0x36, 0xb7, 0xca, 0xc5, 0x00, 0xc6, 0xbe, 0x87, 0x46, 0x10, 0x48, 0xb0, 0x20, 0xc5, 0xc3, 0x55, 0xaa, 0xf8, 0xec, 0x48, 0xd6, 0xa3}
+#define BOOTLOADER_T3B1_FF {0x57, 0x1e, 0xa2, 0xb8, 0x09, 0xf0, 0xab, 0xb4, 0x35, 0xb9, 0x92, 0xcd, 0xde, 0x28, 0x8a, 0xe2, 0x73, 0x04, 0x92, 0x16, 0x01, 0xac, 0x70, 0x48, 0xad, 0x1d, 0x72, 0x9e, 0x31, 0x42, 0xbf, 0x37}
+
+// bootloader_T3B1_qa.bin version 2.1.7.0
+#define BOOTLOADER_T3B1_QA_00 {0x2e, 0x90, 0x8a, 0x99, 0x25, 0x93, 0xcd, 0x9c, 0xf1, 0x23, 0x1e, 0x4e, 0x41, 0xfc, 0xc9, 0xf1, 0x4b, 0x06, 0x69, 0x57, 0x6e, 0x64, 0x84, 0x1c, 0xb1, 0xd9, 0x89, 0x0c, 0xa5, 0xb4, 0x38, 0xeb}
+#define BOOTLOADER_T3B1_QA_FF {0x63, 0xd2, 0x2d, 0x7b, 0xe8, 0x17, 0x2b, 0x97, 0x64, 0x06, 0x9b, 0x60, 0xa0, 0x3d, 0xfc, 0xd6, 0xea, 0x8a, 0x8d, 0xaf, 0x12, 0x25, 0x58, 0x93, 0x9e, 0x40, 0x16, 0xf2, 0x25, 0x30, 0x30, 0x6f}
+
+// clang-format on
+
+#endif
diff --git a/core/embed/models/T3B1/model_T3B1.h b/core/embed/models/T3B1/model_T3B1.h
index 3ed7683535..3e973c8ff5 100644
--- a/core/embed/models/T3B1/model_T3B1.h
+++ b/core/embed/models/T3B1/model_T3B1.h
@@ -1,6 +1,8 @@
 #ifndef MODELS_MODEL_T3B1_H_
 #define MODELS_MODEL_T3B1_H_
 
+#include "bootloaders/bootloader_hashes.h"
+
 #include "sizedefs.h"
 
 #define MODEL_NAME "Safe 3"
diff --git a/core/embed/firmware/bootloaders/bootloader_T3T1.bin b/core/embed/models/T3T1/bootloaders/bootloader_T3T1.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T3T1.bin
rename to core/embed/models/T3T1/bootloaders/bootloader_T3T1.bin
diff --git a/core/embed/firmware/bootloaders/bootloader_T3T1_qa.bin b/core/embed/models/T3T1/bootloaders/bootloader_T3T1_qa.bin
similarity index 100%
rename from core/embed/firmware/bootloaders/bootloader_T3T1_qa.bin
rename to core/embed/models/T3T1/bootloaders/bootloader_T3T1_qa.bin
diff --git a/core/embed/models/T3T1/bootloaders/bootloader_hashes.h b/core/embed/models/T3T1/bootloaders/bootloader_hashes.h
new file mode 100644
index 0000000000..d4dcbffc2a
--- /dev/null
+++ b/core/embed/models/T3T1/bootloaders/bootloader_hashes.h
@@ -0,0 +1,17 @@
+#ifndef BOOTLOADER_HASHES_H
+#define BOOTLOADER_HASHES_H
+
+// Auto-generated file, do not edit.
+
+// clang-format off
+// bootloader_T3T1.bin version 2.1.6.0
+#define BOOTLOADER_T3T1_00 {0x4a, 0x07, 0x5c, 0x74, 0x0f, 0x9a, 0x84, 0x61, 0xaf, 0x10, 0x34, 0x9c, 0x24, 0x3d, 0x79, 0x5b, 0xc6, 0x12, 0x5e, 0xec, 0x51, 0xb3, 0x91, 0x4b, 0x65, 0xf9, 0x79, 0x17, 0x98, 0xc2, 0x4f, 0xcb}
+#define BOOTLOADER_T3T1_FF {0xd8, 0xee, 0x0d, 0xd8, 0x87, 0x0b, 0xf4, 0x38, 0x73, 0x52, 0x83, 0x5e, 0xa9, 0xef, 0x3e, 0x5a, 0x3e, 0x59, 0xc2, 0x12, 0x5b, 0x24, 0xc9, 0x2d, 0xd4, 0xc5, 0xf5, 0x57, 0x15, 0x8a, 0x34, 0x78}
+
+// bootloader_T3T1_qa.bin version 2.1.6.0
+#define BOOTLOADER_T3T1_QA_00 {0x53, 0x5f, 0xf9, 0xa8, 0x21, 0x7d, 0xb5, 0x39, 0xe4, 0xfa, 0xf8, 0x3d, 0x0d, 0xe6, 0xf3, 0x65, 0x21, 0x30, 0x46, 0x9e, 0x40, 0x85, 0xd4, 0xd8, 0x49, 0x00, 0xb0, 0xb5, 0x58, 0x39, 0xe3, 0xd4}
+#define BOOTLOADER_T3T1_QA_FF {0x1e, 0x03, 0x50, 0x25, 0xa1, 0xc7, 0x20, 0xe2, 0x04, 0x62, 0x24, 0xa1, 0x31, 0xc2, 0xf5, 0x7b, 0x35, 0xe9, 0x22, 0x42, 0x36, 0x2d, 0xab, 0xcc, 0xb6, 0x3b, 0xfe, 0x88, 0x53, 0x2f, 0x49, 0xa7}
+
+// clang-format on
+
+#endif
diff --git a/core/embed/models/T3T1/model_T3T1.h b/core/embed/models/T3T1/model_T3T1.h
index 28cf69b542..cbada112e4 100644
--- a/core/embed/models/T3T1/model_T3T1.h
+++ b/core/embed/models/T3T1/model_T3T1.h
@@ -1,6 +1,8 @@
 #ifndef MODELS_MODEL_T3T1_H_
 #define MODELS_MODEL_T3T1_H_
 
+#include "bootloaders/bootloader_hashes.h"
+
 #include "sizedefs.h"
 
 #define MODEL_NAME "Safe 5"