FABRIC-3.10.8 MC-3b: waking a worker core

Each worker core sets up its own IPI receiver before going online (amd64
LAPIC + vector 0x22 with its own stub, aarch64 banked GIC SGI 0, riscv64
sie.SSIE); core 0 sends by ICR / GICD_SGIR / SBI IPI. Park lets exactly
one interrupt in without a lost-wake window. Boot self-test: IPI round
trips 3/3 and 'woke x3, IPIs x3' on all three ISAs; worker vCPU threads
0.0% on the host. 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 16:31:01 -04:00
co-authored by Claude Opus 5.5
parent d7745b49be
commit 71e0be96b0
24 changed files with 46016 additions and 8 deletions
+25
View File
@@ -1104,3 +1104,28 @@ The boot hart HSM chose (0) is the one OpenSBI names as `Boot HART ID`.
- **All three ISAs:** `SMP: core 1: IPI round trips 3/3`, then one idle-point line with **3 wakes, 3 IPIs**, and no later line in the run (no further wake).
- **The standard sequence unchanged:** K-10 hashes, G byte-identical, all ok `3`, 0 B idle growth, 0 order violations, 0 double claims.
- **Host `ps -L` on aarch64 and riscv64:** `CPU 1/TCG` stays at about 0% after boot.
### 7.8 MC-3b — executed (2026-09-26)
**Change**, as planned (§7.7), in these files:
- **Common** (`hal/smp.c`, `smp.h`, `percpu.h`): `arch_smp_secondary_init()` is called on the worker core before it marks itself online. `arch_smp_send_ipi()`, `sk_smp_ipi_received()`, the per-core `ipi_target` / `ipi_received`, the boot round-trip self-test, and the idle-point line `SMP: core N woke xW, IPIs xI`.
- **amd64:** `SK_IPI_VECTOR` 0x22 with its own stub `isr_stub34` (hidden, in the table; the default range is now 35–255). `isr_common_handler` counts and EOIs it. `apic_secondary_enable()` sets SIVR enable and TPR 0. Park is `sti; hlt; cli`; send is a fixed ICR IPI to the APIC id.
- **aarch64:** `apic_secondary_init_gic()` sets the banked SGI 0 priority and enable, then PMR and the CPU interface, and returns this core's mask from its banked `GICD_ITARGETSR0`. `apic_send_wake_sgi()` writes `GICD_SGIR`. `aarch64_irq_handler` counts INTIDs 0–15 and EOIs the full IAR value. Park is `wfi` masked, then a one-instant `daifclr`/`daifset`.
- **riscv64:** `sie.SSIE` on the worker hart. Sending is SBI IPI `send_ipi` (`0x735049`). The handler takes cause 1: clear `sip.SSIP`, then count. Park is `wfi` with SIE clear, then a one-instant `csrsi`/`csrci`.
**One change after the first aarch64 run** (`logs/20260926-154915`, kept as the record):
- That run gave `IPI round trips 3/3` but `woke x1, IPIs x3`. The self-test sent each next IPI as soon as the previous one was *counted*. Under TCG, core 1 was still inside its brief interrupt-open window, so IPIs 2 and 3 were taken there, and one return from `wfi` covered all three.
- Nothing was lost and nothing was spurious: wakes ≤ IPIs, which is the property that matters.
- The self-test now waits for the IPI count **and** the wake count before sending the next IPI, so each round trip is one IPI and one wake. amd64 was re-run on that final code.
**Evidence** (clean builds; the tree is byte-identical to the saved stage diff):
| ISA | log | SMP | host `ps -L` after O-A | standard sequence |
|---|---|---|---|---|
| amd64 | `logs/20260926-162111` | `IPI round trips 3/3`; one idle line `woke x3, IPIs x3`, none after | (threads unnamed on amd64) | K-10 hashes, G byte-identical, all ok `3`, 0 B idle, 0 order violations, 0 refusals, 0 `LOCK:` |
| aarch64 | `logs/20260926-160029` | `3/3`; `woke x3, IPIs x3`, none after | `CPU 1/TCG` **0.0%, 0:00** (`CPU 0` 64.4%) | same |
| riscv64 | `logs/20260926-161120` | `3/3`; `woke x3, IPIs x3`, none after | `CPU 1/TCG` **0.0%, 0:00** (`CPU 0` 65.3%) | same; 0 `timed out` |
The first amd64 run (`logs/20260926-153859`, before the self-test change) also gave `3/3` and `woke x3, IPIs x3`.
**MC-3b is complete.** Core 0 can wake any worker core, and a worker core wakes only for an IPI. Next: MC-3c, the per-core idle context and wake on work, where participants actually run on core 1.