Skip to content

Commit a317b9b

Browse files
committed
feat: initial libtoob + restructuring of types
1 parent 3e99d29 commit a317b9b

9 files changed

Lines changed: 226 additions & 125 deletions

File tree

cmake/toob_core.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ endif()
112112
# ------------------------------------------------------------------------------
113113

114114
target_include_directories(toob_core PUBLIC
115-
core/include
115+
${CMAKE_SOURCE_DIR}/core/include
116116
${CMAKE_BINARY_DIR}/generated
117+
${CMAKE_SOURCE_DIR}/libtoob/include
117118
)
118119

119120
# Bindung an Third-Party Libs und dynamische Feature-Verwendung

core/boot_main.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
* Handoff Areal (.noinit Shared-RAM) gemäß libtoob_api.md und toob_telemetry.md
2626
* ==============================================================================
2727
*/
28+
/* Die Types werden nun exklusiv via boot_types.h -> libtoob_types.h aufgelöst! */
29+
static inline toob_reset_reason_t translate_reset_reason(reset_reason_t internal_reason) {
30+
/* Da das 1:1 Mapping zentral in boot_types.h per Static Assert verifiziert ist, ist ein O(1) Cast C17 sicher. */
31+
return (toob_reset_reason_t)internal_reason;
32+
}
2833
__attribute__((section(".noinit"))) toob_handoff_t toob_handoff_state;
2934
__attribute__((section(".noinit"))) toob_boot_diag_t toob_diag_state;
3035

@@ -226,7 +231,7 @@ boot_status_t boot_main(const boot_platform_t *platform,
226231
* ==============================================================================
227232
*/
228233
if (status != BOOT_OK) {
229-
toob_diag_state.fallback_occurred = true;
234+
toob_diag_state.last_error_code = status;
230235
boot_panic(platform, status);
231236
return status;
232237
}
@@ -239,7 +244,7 @@ boot_status_t boot_main(const boot_platform_t *platform,
239244
target_out->active_image_size == 0 ||
240245
/* Subtraktiver Check umgeht `uint32_t` Wrapping wenn OOB! */
241246
target_out->active_image_size > (CHIP_FLASH_TOTAL_SIZE - target_out->active_entry_point)) {
242-
toob_diag_state.fallback_occurred = true;
247+
toob_diag_state.last_error_code = BOOT_ERR_FLASH_BOUNDS;
243248
boot_panic(platform, BOOT_ERR_FLASH_BOUNDS);
244249
return BOOT_ERR_FLASH_BOUNDS;
245250
}
@@ -261,9 +266,10 @@ boot_status_t boot_main(const boot_platform_t *platform,
261266

262267
/* Basic Handoff Population */
263268
toob_handoff_state.magic = TOOB_STATE_COMMITTED; /* 0x55AA55AA */
264-
toob_handoff_state.struct_version = 0x01000000; /* V1.0.0 */
269+
toob_handoff_state.struct_version = TOOB_DIAG_STRUCT_VERSION;
265270
toob_handoff_state.boot_nonce = target_out->generated_nonce;
266-
toob_handoff_state.reset_reason = platform->clock->get_reset_reason();
271+
toob_handoff_state.reset_reason = translate_reset_reason(platform->clock->get_reset_reason());
272+
toob_handoff_state.booted_partition = TOOB_PARTITION_APP; /* Gemäß concept_fusion zwingend OS In-Place Execution! */
267273

268274
/* Die Wear-Counters und Failure-Counters uebernimmt boot_state.c,
269275
* ebenso active_slot, da diese Logik tief im WAL Journal verankert ist.

core/include/boot_hal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
/* --- 1. Flash HAL (Non-Volatile Storage) --- */
2626

27+
#define TOOB_HAL_ABI_V2 0x02000000
28+
2729
/**
2830
* @brief Flash / NVS Abstraction
2931
* Handles raw physical reads and writes. Requires OTFDEC capability for

core/include/boot_types.h

Lines changed: 36 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,33 @@
2626
* @brief Universal Bootloader Return Type (GAP-06)
2727
* Uses high-hamming-distance constants to prevent 0x00 / 0x01 glitching.
2828
*/
29-
#define TOOB_HAL_ABI_V2 0x02000000
30-
3129
typedef enum {
3230
BOOT_OK = 0x55AA55AA, /**< Clean success (AUTOSAR Anti-Glitch) */
3331

3432
/* HAL Errors (from hals.md) */
35-
BOOT_ERR_FLASH = 1, /**< Flash-Operation fehlgeschlagen */
36-
BOOT_ERR_FLASH_ALIGN = 2, /**< Adresse/Länge nicht aligned */
37-
BOOT_ERR_FLASH_BOUNDS = 3, /**< Adresse außerhalb des Flashs */
38-
BOOT_ERR_CRYPTO = 4, /**< Kryptografische Operation fehlgeschlagen */
39-
BOOT_ERR_VERIFY = 5, /**< Signatur/Hash ungültig */
40-
BOOT_ERR_TIMEOUT = 6, /**< Operation hat Zeitlimit überschritten */
41-
BOOT_ERR_POWER = 7, /**< Batteriespannung zu niedrig */
42-
BOOT_ERR_NOT_SUPPORTED = 8, /**< Feature auf diesem Chip nicht verfügbar */
43-
BOOT_ERR_INVALID_ARG = 9, /**< Ungültiger Parameter (NULL, 0-Länge, etc.) */
44-
BOOT_ERR_STATE = 10, /**< Ungültiger Zustand (z.B. init nicht aufgerufen) */
45-
BOOT_ERR_FLASH_NOT_ERASED = 11, /**< Zielsektor wurde vor Write nicht gelöscht */
46-
BOOT_ERR_COUNTER_EXHAUSTED = 12, /**< OTP/eFuse Counter am Limit */
47-
BOOT_ERR_ECC_HARDFAULT = 13, /**< FATAL: NMI Unkorrigierbarer Bit-Rot (hals.md Z.47) */
33+
BOOT_ERR_FLASH = 0xE1A1A1A1, /**< Flash-Operation fehlgeschlagen */
34+
BOOT_ERR_FLASH_ALIGN = 0xE2B2B2B2, /**< Adresse/Länge nicht aligned */
35+
BOOT_ERR_FLASH_BOUNDS = 0xE3C3C3C3, /**< Adresse außerhalb des Flashs */
36+
BOOT_ERR_CRYPTO = 0xE4D4D4D4, /**< Kryptografische Operation fehlgeschlagen */
37+
BOOT_ERR_VERIFY = 0xE5E5E5E5, /**< Signatur/Hash ungültig */
38+
BOOT_ERR_TIMEOUT = 0xE6F6F6F6, /**< Operation hat Zeitlimit überschritten */
39+
BOOT_ERR_POWER = 0xE7171717, /**< Batteriespannung zu niedrig */
40+
BOOT_ERR_NOT_SUPPORTED = 0xE8282828, /**< Feature auf diesem Chip nicht verfügbar */
41+
BOOT_ERR_INVALID_ARG = 0xE9393939, /**< Ungültiger Parameter (NULL, 0-Länge, etc.) */
42+
BOOT_ERR_STATE = 0xEA4A4A4A, /**< Ungültiger Zustand (z.B. init nicht aufgerufen) */
43+
BOOT_ERR_FLASH_NOT_ERASED = 0xEB5B5B5B, /**< Zielsektor wurde vor Write nicht gelöscht */
44+
BOOT_ERR_COUNTER_EXHAUSTED = 0xEC6C6C6C, /**< OTP/eFuse Counter am Limit */
45+
BOOT_ERR_ECC_HARDFAULT = 0xED7D7D7D, /**< FATAL: NMI Unkorrigierbarer Bit-Rot (hals.md Z.47) */
4846

4947
/* Core State-Machine Errors */
50-
BOOT_ERR_NOT_FOUND = 14, /**< Erwartetes Image/Metadata nicht gefunden */
51-
BOOT_ERR_WDT_TRIGGER = 15, /**< Watchdog Timeout simuliert/registriert */
52-
BOOT_ERR_INVALID_STATE = 16, /**< State-Machine Fehler (z.B. Delta base_mismatch) */
53-
BOOT_ERR_WAL_FULL = 17, /**< Journal Ring blockiert/voll */
54-
BOOT_ERR_WAL_LOCKED = 18, /**< Transaktion über WAL-Grenzen verboten */
55-
BOOT_RECOVERY_REQUESTED = 19, /**< Manueller/Hardware-Ausgelöster Fallback auf Serial Rescue */
56-
BOOT_ERR_ABI_MISMATCH = 20, /**< HAL ABI-Version eines Structs ist zu alt/inkompatibel */
57-
BOOT_ERR_DOWNGRADE = 21 /**< Hybrid SVN Check fehlgeschlagen (Anti-Rollback) */
48+
BOOT_ERR_NOT_FOUND = 0xF1818181, /**< Erwartetes Image/Metadata nicht gefunden */
49+
BOOT_ERR_WDT_TRIGGER = 0xF2929292, /**< Watchdog Timeout simuliert/registriert */
50+
BOOT_ERR_INVALID_STATE = 0xF3A3A3A3, /**< State-Machine Fehler (z.B. Delta base_mismatch) */
51+
BOOT_ERR_WAL_FULL = 0xF4B4B4B4, /**< Journal Ring blockiert/voll */
52+
BOOT_ERR_WAL_LOCKED = 0xF5C5C5C5, /**< Transaktion über WAL-Grenzen verboten */
53+
BOOT_RECOVERY_REQUESTED = 0xF6D6D6D6, /**< Manueller/Hardware-Ausgelöster Fallback auf Serial Rescue */
54+
BOOT_ERR_ABI_MISMATCH = 0xF7E7E7E7, /**< HAL ABI-Version eines Structs ist zu alt/inkompatibel */
55+
BOOT_ERR_DOWNGRADE = 0xF8F8F8F8 /**< Hybrid SVN Check fehlgeschlagen (Anti-Rollback) */
5856
} boot_status_t;
5957

6058
/* --- 2. Hardware Reset Reasons --- */
@@ -90,84 +88,24 @@ typedef struct {
9088
uint32_t magic; /**< TOOB_MAGIC_HEADER für S0 Validierung */
9189
uint32_t image_size; /**< Gesamte Payload-Größe für XIP Bounds */
9290
uint32_t entry_point; /**< XIP Entry-Vector Offset */
93-
uint32_t base_fingerprint; /**< 4-Byte SHA256-Hash Prefix für Delta-Bases */
91+
uint8_t base_fingerprint[8]; /**< 8-Byte SHA256-Hash Prefix für Delta-Bases (gemäß CDDL) */
9492
} toob_image_header_t;
9593

96-
/* --- 4. OS-Boundary Structures (libtoob ABI) --- */
97-
98-
/** \def TOOB_STATE_TENTATIVE Boot-Zustand des unbestätigten Trial-Boots */
99-
#define TOOB_STATE_TENTATIVE 0xAAAA5555
100-
101-
/** \def TOOB_STATE_COMMITTED Boot-Zustand des gesichterten, bestätigten Boots
102-
*/
103-
#define TOOB_STATE_COMMITTED 0x55AA55AA
104-
105-
/**
106-
* @brief Shared Memory Struct (.noinit) für Handoff zwischen Bootloader und OS.
107-
* GAP-11: Struct Versioning
108-
* GAP-39: Explizites 8-Byte Alignment zwingend für 64-bit Kernel
109-
* Kompatibilität.
110-
*/
111-
typedef struct __attribute__((aligned(8))) {
112-
uint32_t magic; /**< Always 0x55AA55AA */
113-
uint32_t struct_version; /**< ABI-Version (z.B. 0x01000000) */
114-
uint64_t boot_nonce; /**< Deterministische Anti-Replay Nonce für Verify-Call */
115-
uint32_t active_slot; /**< 0 = Slot A, 1 = Slot B */
116-
uint32_t reset_reason; /**< Gemappter Grund aus reset_reason_t */
117-
uint32_t boot_failure_count; /**< Aktueller Stand des Recovery-Counters */
118-
119-
/* Wear-Counters (vorab allokiert um Segfaults auf alten Images zu verhindern) */
120-
uint32_t ext_health_app_erasures; /**< Flash-Erasures auf der App-Partition */
121-
uint32_t ext_health_staging_erasures; /**< Verschleiß des Staging-Bereichs */
122-
uint32_t ext_health_wal_erasures; /**< Verschleiß des Ringpuffers */
123-
uint32_t ext_health_swap_erasures; /**< Verschleiß der Swap-Sektoren */
124-
125-
/* Session & Integrity (GAP-F14 / Schicht 4b) */
126-
uint32_t boot_session_id; /**< Boot-Session Vektor für OS-Tracking */
127-
uint32_t crc32_trailer; /**< CRC-32 Validierung gegen Handoff-RAM Garbage nach WDT-Resets */
128-
uint8_t _padding[4]; /**< Padding für striktes 56-Byte Alignment (NASA P10 GAP-39) */
129-
} toob_handoff_t;
94+
_Static_assert(sizeof(toob_image_header_t) == 20, "toob_image_header_t ABI Size Mismatch!");
13095

131-
/* P10 Size-Safety Asserts auf Handoff-ABI - Bricht bei inkompatiblen
132-
* Compiler-Packs */
133-
_Static_assert(sizeof(toob_handoff_t) == 56,
134-
"toob_handoff_t ABI Size Mismatch!");
135-
_Static_assert(sizeof(toob_handoff_t) % 8 == 0,
136-
"toob_handoff_t Alignment Failure!");
137-
138-
/**
139-
* @brief Telemetrie & Boot-Diagnostics (gem. toob_telemetry.md)
140-
* Bildet exakt die 8 CBOR-Felder ab. Wird via libtoob in das OS
141-
* projiziert (Zero-Allocation).
142-
*/
143-
typedef struct {
144-
uint32_t boot_duration_ms; /**< Dauer des letzten Bootvorgangs */
145-
uint32_t edge_recovery_events; /**< Anzahl an Auto-Rollbacks */
146-
uint32_t hardware_fault_record; /**< Hard-Fault Register/Flags */
147-
uint32_t vendor_error; /**< HAL spezifischer Error Code */
148-
uint32_t wdt_kicks; /**< Summe der generierten Watchdog-Kicks */
149-
uint32_t current_svn; /**< Doublecheck Fix: SVN an das OS weiterleiten */
150-
uint8_t active_key_index; /**< Genutzter eFuse Key-Slot */
151-
bool fallback_occurred; /**< Wahrheitswert für OS-Panic Auslösung */
152-
uint8_t schema_version; /**< CDDL Review Fix: Broker Abwärtskompatibilität */
153-
uint8_t sbom_digest[32]; /**< SHA-256 Digest des aktiven OS-Images */
154-
uint8_t _padding[5]; /**< P10 Alignment für den 64-Bit Frame (59 active bytes) */
155-
} toob_boot_diag_t;
156-
157-
/* --- 5. P10 Defense Macros --- */
96+
/* --- 4. OS-Boundary Structures (libtoob ABI) --- */
15897

159-
/**
160-
* @brief Bounded-Loop Assert.
161-
* Beendet bei Ausbruch aus definierten O(1)/O(n) State-Limits sofort mit
162-
* SystemReset.
163-
*/
164-
#define P10_ASSERT(condition) \
165-
do { \
166-
if (!(condition)) { \
167-
/* In Produktion zwingend ein WDT-Reset via Endlos-Loop oder Panic */ \
168-
while (1) { \
169-
} \
170-
} \
171-
} while (0)
98+
/* Integriert die externe OS-Boundary, um struct-Redundanzen und ABI-Verletzungen zu eliminieren. */
99+
#include "libtoob_types.h"
100+
101+
/* P10 Zero-Dependency Sicherung: Zentraler Translation-Layer Check gegen ABI-Drift der Boundaries */
102+
_Static_assert((uint32_t)BOOT_OK == (uint32_t)TOOB_OK, "BOOT_OK and TOOB_OK must share value");
103+
_Static_assert((int)RESET_REASON_UNKNOWN == (int)TOOB_RESET_UNKNOWN, "ABI Drift: Unknown Reason");
104+
_Static_assert((int)RESET_REASON_POWER_ON == (int)TOOB_RESET_POWER_ON, "ABI Drift: Power On Reason");
105+
_Static_assert((int)RESET_REASON_PIN_RESET == (int)TOOB_RESET_PIN, "ABI Drift: Pin Reset Reason");
106+
_Static_assert((int)RESET_REASON_WATCHDOG == (int)TOOB_RESET_WATCHDOG, "ABI Drift: Watchdog Reason");
107+
_Static_assert((int)RESET_REASON_BROWNOUT == (int)TOOB_RESET_BROWNOUT, "ABI Drift: Brownout Reason");
108+
_Static_assert((int)RESET_REASON_SOFTWARE == (int)TOOB_RESET_SOFTWARE, "ABI Drift: Software Reason");
109+
_Static_assert((int)RESET_REASON_HARD_FAULT == (int)TOOB_RESET_HARD_FAULT, "ABI Drift: Hard Fault Reason");
172110

173111
#endif /* TOOB_BOOT_TYPES_H */

docs/concept_fusion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Host-Ebene: Das `device.toml` beschreibt die Partitionsarchitektur abstrakt. Da
3232
Ein rein passiver Notfall-Zugang (UART / USB-DFU) direkt im Bootloader für das Labor/Werk, falls lokal absolut nichts mehr geht. (Komplexe Flash-Logiken wie XMODEM sind strikt verboten und zwingend in das externe Recovery-OS ausgelagert, **siehe [stage_1_5_spec.md](file:///c:/Users/Robin/Desktop/Toob-Loader/docs/stage_1_5_spec.md)** für weitere Protokolldetails).
3333
**WICHTIG (Offline 2FA-Handshake & Anti-Replay):** Um "Evil-Maid"-Angriffe auf die offene serielle Konsole zu vereiteln, erzwingt Stage 1 einen 104-Byte kryptografischen Auth-Token-Transfer. Um Desynchronisationen bei fehlerhaften UART-Übertragungen abzufangen, wird der Payload strikt über **COBS (Consistent Overhead Byte Stuffing)** mit Ping-Pong "READY" Flow-Control kodiert. **Faktor 1 (Besitz):** Der Techniker liest vor Ort einen plattformspezifischen DSLC ("Device Specific Lock Code") per UART aus. **Faktor 2 (Autorisation):** Das HQ signiert diesen DSLC zusammen mit einem 8-Byte UNIX Timestamp mittels Ed25519 `Root-Key`. Um die Notwendigkeit einer RTC zu umgehen, nutzt Stage 1 das **"Highest-Seen-Timestamp" Pattern**: Der lokal gespeicherte Timestamp muss strikt überboten werden (`New_Token > NVRAM_Highest`). **WICHTIGE HARDWARE-REGEL:** Dieser Counter darf *niemals* in das rotierende WAL-Journal gelegt werden. Er MUSS physisch in einer verschleißfesten Persistenzschicht (Stand-Alone Daten-EEPROM / E-Fuse / Option-Bytes) verankert werden. Nur so fungiert er persistent als monotoner Schutz.
3434
**Schicht 4b: Diagnostics (Das Handoff-Areal)**
35-
Stage 1 sammelt passive IDS Timings (Baseline-Kalibrierung der Hardware-Timings obliegt dabei strikt dem Fleet-Manager!) und CRA-Regulatorik Hashes (`boot_diag`). Da das obligatorische `hal_deinit()` vor dem Jump zum Feature-OS das RAM nullt (`__bss_start`), instruiert das Manifest-Build-System das Linker-Script, eine **exklusive `.noinit` Shared-RAM Sektion** auszusparen. Zum Schutz vor RAM-Garbage nach unkontrollierten WDT-Resets erzwingt Stage 1 dort einen harten Contract: Die `.noinit` Daten besitzen ein Magic-Header, einen Boot-Session-ID Vektor und einen CRC-16 Trailer. Stimmt die CRC beim Boot-Übergang nicht, wird der Inhalt abgewiesen. Scheitert ein Pflicht-Platform-Modul hart, weicht Toob-Boot auf ein aus `device.toml` konfiguriertes `diagnostics.sos` SOS-LED-Blinkmuster aus, da Serials fehlen. **Essenzielles Entwickler-UX:** Über dieses Areal streamt S1 ebenfalls den aktiven WDT-Status und eine `boot_diag_get_last_error()` ID an das OS. Tritt während Stage 1 ein Delta-Crash oder "Base_Mismatch" auf, weiß der OTA-Agent beim Hochfahren des Features-OS sofort, woran es lag, und kann beim Backend den Upload eines `/full` Images anstatt eines erneut fehlschlagenden `/delta` Pakets anfordern. Zwingend: `.noinit` ist streng unidirektional (S1 -> OS). Rückkommunikation muss zum Schutz vor OS-RAM-Manipulation zwingend über geflushte WAL-Flash-Entries erfolgen.
35+
Stage 1 sammelt passive IDS Timings (Baseline-Kalibrierung der Hardware-Timings obliegt dabei strikt dem Fleet-Manager!) und CRA-Regulatorik Hashes (`boot_diag`). Da das obligatorische `hal_deinit()` vor dem Jump zum Feature-OS das RAM nullt (`__bss_start`), instruiert das Manifest-Build-System das Linker-Script, eine **exklusive `.noinit` Shared-RAM Sektion** auszusparen. Zum Schutz vor RAM-Garbage nach unkontrollierten WDT-Resets erzwingt Stage 1 dort einen harten Contract: Die `.noinit` Daten besitzen ein Magic-Header, einen Boot-Session-ID Vektor und einen CRC-32 Trailer. Stimmt die CRC-32 beim Boot-Übergang nicht, wird der Inhalt abgewiesen. Scheitert ein Pflicht-Platform-Modul hart, weicht Toob-Boot auf ein aus `device.toml` konfiguriertes `diagnostics.sos` SOS-LED-Blinkmuster aus, da Serials fehlen. **Essenzielles Entwickler-UX:** Über dieses Areal streamt S1 ebenfalls den aktiven WDT-Status und eine `boot_diag_get_last_error()` ID an das OS. Tritt während Stage 1 ein Delta-Crash oder "Base_Mismatch" auf, weiß der OTA-Agent beim Hochfahren des Features-OS sofort, woran es lag, und kann beim Backend den Upload eines `/full` Images anstatt eines erneut fehlschlagenden `/delta` Pakets anfordern. Zwingend: `.noinit` ist streng unidirektional (S1 -> OS). Rückkommunikation muss zum Schutz vor OS-RAM-Manipulation zwingend über geflushte WAL-Flash-Entries erfolgen.
3636

3737
**Schicht 3: Core Engine**
3838
Reine Business-Logik: Update-State-Machine, Signatur-Verifikation, Journal, Merkle-Verify, SUIT-Manifest-Parser (Zwingend als strikter Stream-Parser wie zcbor, der unbekannte `suit-conditions` als FAIL evaluiert, `suit-directives` ignoriert und eine `min_parser_version` erzwingt) sowie **Anti-Rollback Protection** und **Key-Revocation**. Toob-Boot nutzt eine **hybride SVN**: Tägliche Minor-Updates protokollieren ihre SVN-Inkremente _virtuell_ sicher im WAL (ohne endliche E-Fuses rasch zu verschwenden). Ein Manifest wird nur akzeptiert, wenn `manifest.svn > persisted_svn`, um Replay-Angriffe älterer, noch gültiger Firmware zu blockieren. Tritt ein extrem kritischer CVE-Exploit auf, signalisiert das Update einen "Epoch Change". Erst dann brennt Stage 1 irreversibel eine Hardware-eFuse durch. Ebenso fordert das Manifest via `Required_Key_Epoch` Feld bei Diebstahl des Root-Keys einen Epochenwechsel. Ist ein höherer HW-Epochen-Key gebrannt, weist der Bootloader bidirektional alle Manifeste mit niedrigerer oder gleicher Epoch unwiderruflich ab, selbst wenn diese noch valider Teil der SVN-Historie wären.

0 commit comments

Comments
 (0)