Qualify GAT562 bootloader updates
This commit is contained in:
1 parent
dea2ce495f
commit
f2c15225cc
4 files changed
+56
-2
No files matched your search
@@ -103,7 +103,8 @@ manifest identity:
|
||||
| `ThinkNode_M3_repeater_lora_ota_no_external_sensors` | `239A00DA / TNM3_DFU` | `0CA41DB2` |
|
||||
| `RAK_3401_repeater_lora_ota_no_external_sensors` | `239A0029 / 3401_DFU` | `23818A80` |
|
||||
| RAK4631 lean repeater and both lean RS232 bridges | `239A0029 / 4631_DFU` | `2D0DF000` |
|
||||
| GAT562 30S/Tracker Pro/EVB Pro and R1Neo lean carrier aliases | `239A0029 / 4631_DFU` | `2D0DF000` |
|
||||
| GAT562 30S/Tracker Pro/EVB Pro lean targets | `239A0029 / GAT562_DFU` | `D50D2D44` |
|
||||
| `R1Neo_repeater_lora_ota_no_external_sensors` | `239A0029 / 4631_DFU` | `2D0DF000` |
|
||||
| `RAK_WisMesh_Tag_repeater_lora_ota_no_external_sensors` | `239A0029 / RTAG_DFU` | `C72E9C9C` |
|
||||
|
||||
Board IDs are not globally unique. For generic targets, the signed hardware ID
|
||||
@@ -118,6 +119,12 @@ duplicates and collisions with application target IDs. Generic image parsing
|
||||
can inspect a future canonical identity, but signing/building a package fails
|
||||
until that exact identity is in the qualified inventory.
|
||||
|
||||
Earlier GAT562 installations may report the RAK-compatible `4631_DFU`
|
||||
identity. The installed and candidate identity pair must match exactly, so a
|
||||
remote bootloader update cannot migrate one of those devices to `GAT562_DFU`.
|
||||
Provision the GAT562-specific OTAFIX bootloader once through USB/BLE DFU or SWD;
|
||||
subsequent signed bootloader mOTA updates use target `D50D2D44`.
|
||||
|
||||
## Embedded continuity and version policy
|
||||
|
||||
Every remotely supplied successor retains the legacy 44-byte CRC-valid `BLMF`
|
||||
|
||||
@@ -378,14 +378,19 @@ TEST(OtaBootPackage, SdApprovalTokenBindsTheAuthenticatedImageHash) {
|
||||
|
||||
TEST(OtaBootPackage, GenericIdentityUsesBoardAndNameForCollisionSafeTarget) {
|
||||
const uint32_t shared_board_id = 0x239A0029u;
|
||||
const uint8_t gat562_name[16] = {'G','A','T','5','6','2','_','D','F','U',0,0,0,0,0,0};
|
||||
const uint8_t rak3401_name[16] = {'3','4','0','1','_','D','F','U',0,0,0,0,0,0,0,0};
|
||||
const uint8_t rak4631_name[16] = {'4','6','3','1','_','D','F','U',0,0,0,0,0,0,0,0};
|
||||
uint8_t hw3401[32], hw4631[32];
|
||||
uint8_t hw_gat562[32], hw3401[32], hw4631[32];
|
||||
ASSERT_TRUE(ota_bootloader_hw_id(shared_board_id, gat562_name, hw_gat562));
|
||||
ASSERT_TRUE(ota_bootloader_hw_id(shared_board_id, rak3401_name, hw3401));
|
||||
ASSERT_TRUE(ota_bootloader_hw_id(shared_board_id, rak4631_name, hw4631));
|
||||
EXPECT_EQ(0, memcmp(hw_gat562, "NRF_BL_239A0029_GAT562_DFU", 26));
|
||||
EXPECT_EQ(0, memcmp(hw3401, "NRF_BL_239A0029_3401_DFU", 24));
|
||||
EXPECT_EQ(0, memcmp(hw4631, "NRF_BL_239A0029_4631_DFU", 24));
|
||||
EXPECT_NE(0, memcmp(hw_gat562, hw4631, sizeof(hw_gat562)));
|
||||
EXPECT_NE(0, memcmp(hw3401, hw4631, sizeof(hw3401)));
|
||||
EXPECT_EQ(ota_bootloader_target_id(shared_board_id, gat562_name), 0xD50D2D44u);
|
||||
EXPECT_EQ(ota_bootloader_target_id(shared_board_id, rak3401_name), 0x23818A80u);
|
||||
EXPECT_EQ(ota_bootloader_target_id(shared_board_id, rak4631_name), 0x2D0DF000u);
|
||||
|
||||
@@ -418,6 +423,7 @@ TEST(OtaBootPackage, GenericIdentityUsesBoardAndNameForCollisionSafeTarget) {
|
||||
|
||||
struct KnownIdentity { uint32_t board_id; const char* name; uint32_t target_id; };
|
||||
const KnownIdentity known[] = {
|
||||
{0x239A0029u, "GAT562_DFU", 0xD50D2D44u},
|
||||
{0x239A0071u, "TOWER_V2_OTA", 0x1150F50Eu},
|
||||
{0x239A0071u, "T096_DFU", 0x42354C85u},
|
||||
{0x239A0071u, "T1_DFU", 0xFC556FFCu},
|
||||
|
||||
@@ -119,6 +119,7 @@ BOOT_REQUIRED_APP_CODEC_MASK = ((1 << CODEC_FULL) |
|
||||
# aliases use the same installed bootloader identity and therefore do not add
|
||||
# rows here.
|
||||
INTERNAL_BOOTLOADER_IDENTITIES = (
|
||||
(0x239A0029, "GAT562_DFU"),
|
||||
(0x239A0071, "TOWER_V2_OTA"),
|
||||
(0x239A0071, "T096_DFU"),
|
||||
(0x239A0071, "T1_DFU"),
|
||||
|
||||
@@ -53,6 +53,13 @@ def test_internal_bootloader_target_wiring_is_central_and_not_duplicated():
|
||||
]
|
||||
assert len(inventory) == len(set(inventory))
|
||||
assert len(inventory) == 21
|
||||
gat_targets = {
|
||||
"GAT562_30S_Mesh_Kit_repeater_lora_ota_no_external_sensors",
|
||||
"GAT562_Mesh_Tracker_Pro_repeater_lora_ota_no_external_sensors",
|
||||
"GAT562_Mesh_EVB_Pro_repeater_lora_ota_no_external_sensors",
|
||||
}
|
||||
assert gat_targets <= set(inventory)
|
||||
assert not any("GAT562_Mesh_Watch13" in target for target in inventory)
|
||||
|
||||
target_header = (root / "src/helpers/ota/OtaTargets.h").read_text(encoding="utf-8")
|
||||
for target in inventory:
|
||||
@@ -1379,6 +1386,38 @@ def test_generic_internal_bootloader_build_parse_and_strict_contract():
|
||||
pass
|
||||
|
||||
|
||||
def test_gat562_internal_bootloader_profile_is_exact():
|
||||
priv = Ed25519PrivateKey.generate()
|
||||
image = _generic_bootloader_image(device_name="GAT562_DFU")
|
||||
identity = ml.validate_bootloader_image(image)
|
||||
assert (identity.board_id, identity.device_name) == (0x239A0029, "GAT562_DFU")
|
||||
profile = ml.bootloader_qualified_platform_profile(
|
||||
identity.board_id, identity.device_name)
|
||||
assert profile == (
|
||||
ml.BOOT_CONTINUITY_FAMILY_S140,
|
||||
ml.BOOTLOADER_S140_V6_FWID,
|
||||
ml.NRF52_APP_BASE_S140_V6,
|
||||
ml.BOOT_CONTINUITY_LAYOUT_ABI,
|
||||
)
|
||||
storages = ml.bootloader_qualified_storage_profiles(
|
||||
identity.board_id, identity.device_name)
|
||||
assert storages == (ml.BOOT_STORAGE_INTERNAL_UPDATE,)
|
||||
|
||||
target = ml.bootloader_target_id(identity.board_id, identity.device_name)
|
||||
expected_hw = b"NRF_BL_239A0029_GAT562_DFU".ljust(32, b"\0")
|
||||
assert target == 0xD50D2D44
|
||||
assert ml.bootloader_hw_id(identity.board_id, identity.device_name) == expected_hw
|
||||
manifest = ml.build_manifest(
|
||||
target_id=target, fw_version=identity.boot_version,
|
||||
image_size=len(image), payload=image, block_size=1024,
|
||||
image_hash=ml.mh32(image), codec_id=ml.CODEC_FULL, is_full=True,
|
||||
sign_priv=priv, bootloader=True)
|
||||
parsed = ml.parse_container(ml.build_container(manifest, image))
|
||||
assert parsed.manifest.target_id == target
|
||||
assert parsed.manifest.hw_id == expected_hw
|
||||
assert ml.verify(parsed, expect_pub=ml.ed25519_public_bytes(priv)) == []
|
||||
|
||||
|
||||
def test_meshtower_sd_bootloader_profile_builds_the_same_exact_identity():
|
||||
priv = Ed25519PrivateKey.generate()
|
||||
image = _generic_bootloader_image(
|
||||
@@ -1418,6 +1457,7 @@ def test_bootloader_build_inventory_is_unique_and_disjoint_from_app_targets():
|
||||
import re
|
||||
|
||||
expected = {
|
||||
(0x239A0029, "GAT562_DFU"): 0xD50D2D44,
|
||||
(0x239A0071, "TOWER_V2_OTA"): 0x1150F50E,
|
||||
(0x239A0071, "T096_DFU"): 0x42354C85,
|
||||
(0x239A0071, "T1_DFU"): 0xFC556FFC,
|
||||
|
||||
Reference in new issue
Block a user