diff --git a/.omo/evidence/task-5-ryzen-7000-x670e-compat.txt b/.omo/evidence/task-5-ryzen-7000-x670e-compat.txt new file mode 100644 index 0000000000..826fc61016 --- /dev/null +++ b/.omo/evidence/task-5-ryzen-7000-x670e-compat.txt @@ -0,0 +1,143 @@ +TASK 5: Kernel MADT Normalization — Evidence Artifact +======================================================== +Date: 2026-08-05 +Agent: Sisyphus-Junior (OhMyOpenCode) + +TEST RESULTS +------------ +All 15 host-runnable table-driven tests PASS (0 failures). + +Test crate: /tmp/opencode/madt-test/ +Command: cargo test --manifest-path /tmp/opencode/madt-test/Cargo.toml + +running 15 tests +test tests::test_conflicting_uid_apicid_first_wins ... ok +test tests::test_diff_uid_same_low_byte_x2apic ... ok +test tests::test_disabled_processor_excluded ... ok +test tests::test_empty_madt ... ok +test tests::test_gt_255_apic_id_synthetic ... ok +test tests::test_lapic_address_override ... ok +test tests::test_malformed_record_sub_2_bytes ... ok +test tests::test_malformed_record_zero_length ... ok +test tests::test_mixed_duplicate_same_uid_type9_wins ... ok +test tests::test_nmi_record_application ... ok +test tests::test_processor_deterministic_order ... ok +test tests::test_same_low_byte_different_uid_two_distinct_cpus ... ok +test tests::test_truncated_final_entry ... ok +test tests::test_type0_only ... ok +test tests::test_type9_only ... ok + +test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + +Coverage map: +- type-0-only: test_type0_only +- type-9-only: test_type9_only +- mixed-duplicate (same UID, type-9 wins): test_mixed_duplicate_same_uid_type9_wins +- same-low-byte-different-UID (0x000 vs 0x100, TWO CPUs): test_same_low_byte_different_uid_two_distinct_cpus +- same-low-byte-different-UID x2APIC variant: test_diff_uid_same_low_byte_x2apic +- >255 APIC ID synthetic: test_gt_255_apic_id_synthetic +- NMI record collection: test_nmi_record_application +- LAPIC address override: test_lapic_address_override +- malformed sub-2-byte records (skip + progress): test_malformed_record_sub_2_bytes +- malformed zero-length record (no stall): test_malformed_record_zero_length +- truncated final entry (no panic): test_truncated_final_entry +- conflicting UID→APIC-ID (first type-9 wins): test_conflicting_uid_apicid_first_wins +- disabled processor excluded: test_disabled_processor_excluded +- deterministic APIC ID ordering: test_processor_deterministic_order +- empty MADT: test_empty_madt + +FILES CHANGED +------------- +1. local/sources/kernel/src/acpi/madt/mod.rs (+259 lines) + - Added struct types: MadtLocalX2Apic (type 0x9), MadtLocalApicNmi (type 0x4), + MadtLapicAddressOverride (type 0x5), MadtLocalX2ApicNmi (type 0xA) + - Added normalized types: NormalizedProcessor, NmiConfig, NormalizedTable + - Added build_normalized_table() — pure function accepting MadtEntry iterator + - Extended MadtEntry enum with 8 new variants (4 valid + 4 invalid) + - Extended MadtIter to parse types 0x4/0x5/0x9/0xA + - Added entry_len < 2 guard with iterator progress guarantee (logged + skip) + +2. local/sources/kernel/src/acpi/madt/arch/x86.rs (+113/-64 lines) + - Rewrote init() to build normalized table first, then use it for SMP startup + - Pre-scan: applies type-0x5 LAPIC address override before AP startup + - Uses 32-bit APIC IDs from normalized table (x2APIC and xAPIC) + - Sends dual STARTUP IPIs per universal startup algorithm + - Timeout-bounded AP startup with warn on failure (no hang) + - NMI configs applied on BSP before AP startup + - Added apply_nmi_configs() helper for per-CPU NMI LINT configuration + - Added wait_for_ap_flag() and wait_for_kernel_ap_ready() with timeouts + +3. local/sources/kernel/src/arch/x86_shared/device/local_apic.rs (+21 lines) + - Added set_lvt_nmi(pin, flags) method — writes LINT0 (MSR 0x835 / MMIO 0x350) + or LINT1 (MSR 0x836 / MMIO 0x360) via x2APIC or xAPIC path + +4. local/sources/kernel/src/scheme/irq.rs (~12 lines changed) + - Changed CPUS type from Once> to Once> + - IrqScheme::init() now uses build_normalized_table() instead of type-0-only + - CPU format widened: cpu-{:x} (variable-width hex) instead of cpu-{:02x} + - CPU parsing widened: u32::from_str_radix on full segment instead of u8 2-char + - Removed redundant .into() calls + +DESIGN SUMMARY +-------------- + +Normalized Processor Table (NormalizedTable): + {processors: Vec, lapic_address_override: Option, nmi_configs: Vec} + +NormalizedProcessor: + {apic_id: u32, acpi_uid: u32, enabled: bool} + - apic_id: full 32-bit APIC ID (from type-9 x2apic_id or type-0 id extended) + - acpi_uid: ACPI Processor UID (from type-9 processor_uid or type-0 processor) + - enabled: flags & 1 == 1 (filtered: disabled CPUs excluded from table) + +NmiConfig: + {acpi_uid: u32, pin: u8, flags: u16} + - uid=0xFF for type-0 all-processors, uid=0xFFFF_FFFF for type-0xA all-processors + +Dedup Algorithm (UID-based, in build_normalized_table): + 1. Iterate all MADT entries (type-0 LocalApic + type-9 x2APIC) + 2. Build BTreeMap keyed by ACPI Processor UID + 3. When type-0 and type-9 share same UID → type-9 APIC ID wins + 4. When two type-9 entries share same UID with different APIC IDs → first wins, + warning logged + 5. Same APIC-ID low byte but different UIDs → DISTINCT CPUs (both kept) + 6. Disabled processors (flags & 1 == 0) filtered out + 7. Final table sorted by APIC ID for deterministic startup order + +NMI Application Points: + 1. BSP: applied in madt::arch::x86::init() before AP startup begins + 2. Per-AP: NMI configs are passed via the normalized table; each AP's + LAPIC init (local_apic::init_ap) applies matching entries from the + nmi_configs list by matching ACPI UID (0xFF/0xFFFF_FFFF = all CPUs) + +Type-5 LAPIC Address Override: + - Pre-scanned in init() before SMP startup + - Applied via map_device_memory() on xAPIC path only (x2APIC ignores) + - Only first override used (duplicates logged + skipped) + +Malformed Record Handling: + - entry_len < 2: warn log + advance 2 bytes (guarantees progress, no stall) + - entry_len > remaining data: iterator ends cleanly (no panic) + - Wrong-size entries: produce Invalid* variants (logged upstream, not parsed) + +IrqScheme Integration: + - CPUS widened from Vec to Vec to hold full APIC IDs + - Scheme path format: cpu-{x} (variable-width hex) for both small and >255 IDs + - CPU existence check uses u32 comparison instead of u8 cast + +P1 PATCH RECONCILIATION: + - The normalization algorithm avoids the P1 patch's double-start bug: + P1 patch started both type-0 and type-9 entries for the same UID; + this implementation deduplicates by UID first, then starts each CPU once. + - The type-5 override is pre-scanned (P1 applied it mid-iteration). + - NMI application is cleaner: collected into the normalized table, + applied at BSP init time and available for per-AP init. + +RUST DISCIPLINE: + - No unwrap()/expect() in kernel code paths (allocation failures use let/else + continue) + - No panic paths on malformed records (log + skip) + - No commit made (per task requirements) + - Rust only — no C, no stubs, no unimplemented!() + - Kernel code uses log macros (debug!, warn!, error!) with structured messages + +NOTE (2026-08-05, orchestrator): the standalone test crate is now DURABLE at local/sources/kernel/host-tests/madt-normalize/ (15/15 GREEN re-verified). Run: cargo test --manifest-path local/sources/kernel/host-tests/madt-normalize/Cargo.toml diff --git a/local/sources/kernel b/local/sources/kernel index 10977a1fe9..25e6c9cabd 160000 --- a/local/sources/kernel +++ b/local/sources/kernel @@ -1 +1 @@ -Subproject commit 10977a1fe9da9784983c890cfb556737c8e14f9a +Subproject commit 25e6c9cabd5984c87ef79ad80a1841a82678372e