FABRIC-3.10.8 MC-1a: the core table, and amd64's second core online and parked

hal/smp.c: dense logical core ids, a heap-sized core table, one-at-a-time
bring-up under a 1 s bound, park-wake reporting at the idle point.
amd64: MADT enumeration, a relocation-free real->long-mode trampoline
copied below 1 MiB, INIT-SIPI-SIPI via the LAPIC ICR; QEMU -smp 2.
Core 1 reports online with GS on its own block, parks with 0 wakes;
aarch64/riscv64 report 1 core until MC-1b/c. 3-ISA acceptance clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-26 12:40:51 -04:00
co-authored by Claude Opus 5.5
parent 8c068e00e3
commit 24bde47481
19 changed files with 37381 additions and 1 deletions
+37
View File
@@ -837,3 +837,40 @@ The ledger reads pulled 319488 / returned 316703 on all three. That is the K-3 b
- **Parked, not spinning:** no park-wake line in the whole run. On the host, core 1's QEMU vCPU thread sits near 0% CPU (`ps -L`), if TCG gives it its own thread.
- **aarch64 and riscv64:** they report 1 core and are otherwise unchanged.
- **Standard sequence on all three:** the K-10 dict_hash set, G A=40 B=40 byte-identical (still one worker core), all ok `3`, 0 B idle growth.
### 5.1 MC-1a — the core table, and amd64's second core online and parked (2026-09-26)
**Change.**
- **`include/starkernel/smp.h`, `hal/smp.c`: the core table.** It holds dense logical ids, is heap-sized from enumeration, and gives each extra core a heap block and a 16 KiB stack.
- `sk_smp_init()` brings the cores up one at a time, each waited for under a 1 s bound on the raw counter.
- `sk_smp_secondary_main()` records the per-CPU register readback, marks the core online with a release store, and parks.
- `sk_smp_report()` runs at the idle point, after the lock report, and logs park wakes only when they change.
- aarch64 and riscv64 report their boot core only, through stubs in `hal/smp.c` that MC-1b/c replace. Their "hw id 0x0" is that stub, not a real MPIDR or hartid.
- **`sk_percpu_t`** gains `hw_id`, `reg_readback`, `online` and `park_wakes`.
- **`arch/amd64/smp.c`:**
- MADT enumeration: enabled type-0 entries, then type-9 entries with ids up to 255, de-duplicated.
- The trampoline page: the lowest conventional page in [4 KiB, 1 MiB) from the UEFI memory map.
- The control-state copy: CR0/CR3/CR4, CR4 without PCIDE for the 32-bit step, EFER without LMA, PAT, and XCR0 when OSXSAVE is set. The kernel GDTR and IDTR are copied too.
- INIT, 10 ms, STARTUP, 200 µs, then a second STARTUP only if the core isn't online yet.
- **`arch/amd64/ap_trampoline.S`:** the relocation-free blob (§5 path). **`apic_send_ipi()`** in `apic.c` writes ICR high then low, and polls delivery status.
- **Wiring:** `kernel_main_deep()` calls `sk_smp_init()` after the heartbeat init. The Makefile builds the two amd64 files into the loader, and `-smp 2` is on the `make qemu` amd64 line only.
**Two failed debug boots, found and fixed; their logs are deleted as flawed:**
1. **Core 1 triple-faulted and reset the machine.** QEMU runs with `-no-reboot`, so it exited just after the "2 core(s) found" line.
2. **A rerun with `QEMU_EXTRA="-d int,cpu_reset"`** showed core 1 had reached 64-bit mode and loaded the kernel GDT. It then page-faulted on `push 0x08`, the far return's first push, with RSP still 0 (CR2 `0xfffffffffffffff8`).
- The fix loads the stack before the far return.
- EFER.LMA is also masked out of the copied value, since only the CPU may set it.
3. **The traced rerun after the fix** (`logs/20260926-120808`, kept): 0 exceptions on either core over the boot.
**Evidence** (clean builds, no trace; the tracked diff is byte-identical to the saved stage diff):
| ISA | log | SMP lines | standard sequence |
|---|---|---|---|
| amd64 (`-smp 2`) | `logs/20260926-121008` | `SMP: 2 core(s) found; core 0 is the boot core, hw id 0x0`; `SMP: core 1 online: hw id 0x1, block 0x0000000001780130, per-CPU register 0x0000000001780130 (its own block), 59 us, parked`; `SMP: 2 core(s) online` | K-10 hashes, G A=40 B=40 byte-identical, HHH, all ok `3`, ledger unchanged, 0 B idle, 0 / 0; **0 park-wake lines, 0 `LOCK:` lines** |
| aarch64 | `logs/20260926-122030` | 1 core found, 1 online | same |
| riscv64 | `logs/20260926-123103` | 1 core found, 1 online | same |
- The 59 µs is measured from the end of `arch_smp_start()`, which already includes the 10 ms INIT wait and the 200 µs STARTUP wait. The core arrived during the second STARTUP's delivery, not 59 µs after INIT.
- **Not as named in advance:** the host-side check (core 1's vCPU thread near 0% in `ps -L`) could not be made. QEMU names its threads per vCPU only with `-name debug-threads=on`, which is not on the command line. The park-wake counter (0 wakes) is the evidence of record. Adding `-name debug-threads=on` is a candidate for MC-1b's run line.
**MC-1a is complete.** amd64 now boots two cores, and the second is parked with interrupts masked. Next: MC-1b (aarch64, PSCI `CPU_ON`).