Artemis Milestone 1 complete: QMP socket added to all three QEMU

launch targets, three-arch verified

Makefile.starkernel: added -qmp unix:$QMP_SOCK,server=on,wait=off to
the amd64/aarch64/riscv64 qemu targets, matching the existing serial
chardev socket pattern exactly (same discoverability, same cleanup on
exit). Verified on all three architectures: QMP greeting arrives on
connect, qmp_capabilities handshake succeeds, device_add/device_del
round-trip correctly.

Real finding surfaced during device_add testing (recorded in
FABRIC-2.md's punch list for Milestone 2): the q35 machine's pcie.0
root bus doesn't support runtime PCI hotplug without a bridge --
Milestone 2's qemu-xhci USB controller needs to be present in the
static launch command, with USB devices hot-attached to its bus at
runtime, not the controller itself hot-added.

Also noted: g_doe_log_enabled's default-on per-tick heartbeat CSV
export was briefly mistaken for a hang during aarch64 verification --
it isn't one, just a large volume of routine diagnostic output before
reaching ok>. Not changing the source default; adopting HB-OFF
immediately after boot as the working pattern for the rest of this
punch list's dev work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-22 07:48:52 -04:00
co-authored by Claude Sonnet 5
parent 0008f19bbb
commit 3d91015659
8 changed files with 57057 additions and 16 deletions
+26 -12
View File
@@ -3030,22 +3030,36 @@ real order" translation needed). Real-hardware boot is Milestone 8, deliberately
last, not first — build and validate the whole Artemis subsystem in QEMU before touching real
hardware at all. Networking (Milestone 9) stays last, deferred past everything else.
### Milestone 1 — QEMU monitor/QMP socket (small, unblocks dev-iteration workflow)
### Milestone 1 — QEMU monitor/QMP socket (small, unblocks dev-iteration workflow) ✅ DONE 2026-08-22
Independent of Milestone 8; useful before Milestone 2's virtual-drive testing starts.
- [ ] Add `-qmp unix:$QMP_SOCK,server=on,wait=off` to each arch's QEMU invocation in
- [x] Add `-qmp unix:$QMP_SOCK,server=on,wait=off` to each arch's QEMU invocation in
`Makefile.starkernel`, matching the existing `-chardev socket,id=cserial,...` pattern
already used for the serial console
- [ ] Confirm the QMP socket path gets logged/echoed the same way the serial socket path
already is, so it's discoverable the same way
- [ ] Verify a basic QMP handshake works (`qmp_capabilities` negotiation is required before
any other QMP command — confirm via `socat`/manual JSON, not HMP text commands, since
QMP is JSON-based and HMP is text-based; decide which of the two is actually wanted
HMP (`-monitor`) is simpler to drive by hand via `socat`, QMP is more scriptable but
needs the capabilities handshake first)
- [ ] Confirm `device_add`/`device_del` works against a trivial device (not USB yet — prove
the mechanism itself first with something simple) before relying on it for Milestone 2
already used for the serial console. Done for all three architectures.
- [x] Confirm the QMP socket path gets logged/echoed the same way the serial socket path
already is, so it's discoverable the same way. Confirmed: `QMP socket: ...` line prints
right after `Serial log: ...` on every launch.
- [x] Verify a basic QMP handshake works. **Decision: QMP (JSON), not HMP.** Confirmed via
`socat` on all three architectures: connect → QMP greeting arrives unprompted
`{"execute":"qmp_capabilities"}``{"return": {}}`. Identical on amd64/aarch64/riscv64.
- [x] Confirm `device_add`/`device_del` works against a trivial device. Confirmed on amd64:
the QMP round-trip itself works correctly (proper JSON command dispatch and error
reporting), but attempting `device_add driver=virtio-serial-pci` against the bare q35
root bus returned `"Bus 'pcie.0' does not support hotplugging"` — a real, expected QEMU
constraint, not a bug. **Finding for Milestone 2:** plain PCIe root-bus hotplug doesn't
work without an intermediate hotplug-capable bridge; the `qemu-xhci` USB controller
itself must be present in the static launch command (added at boot, not hot-added), and
USB *devices* get hot-attached to *its* bus at runtime — USB ports are hotpluggable by
design regardless of the underlying PCIe root-bus limitation.
**Note, same session:** `g_doe_log_enabled` (the routine per-tick `[HADES][DOE]` heartbeat CSV
export, on by default) was mistaken for a hang during this milestone's aarch64 verification —
it isn't one, boot just produces a large volume of routine diagnostic rows before reaching
`ok>` (confirmed: thousands of rows, from both Hera's own heartbeat and Artemis's separate
instance of the same mechanism). Not changing the source default (documented elsewhere as
intentional), but adopting `HB-OFF` immediately after every boot as the working pattern for
the remainder of this punch list's dev work, same tool used throughout the ACL-TTL campaign.
### Milestone 2 — USB hardware stack (the hard prerequisite, most granular breakdown)
+12 -3
View File
@@ -735,8 +735,10 @@ ifeq ($(ARCH),amd64)
LOG=$$SESSION/amd64/qemu-amd64-$$TS.log; \
CSV=$(DOE_RUNS_DIR)/doe-amd64-$$TS.csv; \
SERIAL_SOCK=$(BUILD_DIR)/qemu-serial-amd64-$$TS.sock; \
QMP_SOCK=$(BUILD_DIR)/qemu-qmp-amd64-$$TS.sock; \
echo "=== Launching QEMU (amd64) ==="; \
echo " Serial log: $$LOG"; \
echo " QMP socket: $$QMP_SOCK"; \
echo " (interactive — close the window or QEMU monitor 'quit' to exit)"; \
echo ""; \
touch $$LOG; \
@@ -753,10 +755,11 @@ ifeq ($(ARCH),amd64)
-device virtio-blk-pci,drive=artdisk \
-chardev socket,id=cserial,path=$$SERIAL_SOCK,server=on,wait=off,logfile=$$LOG \
-serial chardev:cserial \
-qmp unix:$$QMP_SOCK,server=on,wait=off \
-display $(QEMU_DISPLAY) \
-no-reboot; \
kill $$TAILPID 2>/dev/null; wait $$TAILPID 2>/dev/null || true; \
rm -f $$SERIAL_SOCK; \
rm -f $$SERIAL_SOCK $$QMP_SOCK; \
echo ""; \
echo "=== Serial log: $$LOG ==="; \
echo "=== Extracting DOE CSV ==="; \
@@ -796,9 +799,11 @@ else ifeq ($(ARCH),aarch64)
LOG=$$SESSION/aarch64/qemu-aarch64-$$TS.log; \
CSV=$(DOE_RUNS_DIR)/doe-aarch64-$$TS.csv; \
SERIAL_SOCK=$(BUILD_DIR)/qemu-serial-aarch64-$$TS.sock; \
QMP_SOCK=$(BUILD_DIR)/qemu-qmp-aarch64-$$TS.sock; \
echo "=== Launching QEMU (aarch64) ==="; \
echo " ISO: $(QEMU_ISO)"; \
echo " Serial log: $$LOG"; \
echo " QMP socket: $$QMP_SOCK"; \
echo " (interactive — close the window or QEMU monitor 'quit' to exit)"; \
echo ""; \
touch $$LOG; \
@@ -814,12 +819,13 @@ else ifeq ($(ARCH),aarch64)
-device ramfb \
-chardev socket,id=cserial,path=$$SERIAL_SOCK,server=on,wait=off,logfile=$$LOG \
-serial chardev:cserial \
-qmp unix:$$QMP_SOCK,server=on,wait=off \
-display $(QEMU_DISPLAY) \
-m 4096 \
-no-reboot \
-d guest_errors; \
kill $$TAILPID 2>/dev/null; wait $$TAILPID 2>/dev/null || true; \
rm -f $$SERIAL_SOCK; \
rm -f $$SERIAL_SOCK $$QMP_SOCK; \
echo ""; \
echo "=== Serial log: $$LOG ==="; \
echo "=== Extracting DOE CSV ==="; \
@@ -874,8 +880,10 @@ else ifeq ($(ARCH),riscv64)
LOG=$$SESSION/riscv64/qemu-riscv64-$$TS.log; \
CSV=$(DOE_RUNS_DIR)/doe-riscv64-$$TS.csv; \
SERIAL_SOCK=$(BUILD_DIR)/qemu-serial-riscv64-$$TS.sock; \
QMP_SOCK=$(BUILD_DIR)/qemu-qmp-riscv64-$$TS.sock; \
echo "=== Launching QEMU (riscv64) ==="; \
echo " Serial log: $$LOG"; \
echo " QMP socket: $$QMP_SOCK"; \
echo " (interactive — close the window or QEMU monitor 'quit' to exit)"; \
echo ""; \
touch $$LOG; \
@@ -894,11 +902,12 @@ else ifeq ($(ARCH),riscv64)
-device ramfb \
-chardev socket,id=cserial,path=$$SERIAL_SOCK,server=on,wait=off,logfile=$$LOG \
-serial chardev:cserial \
-qmp unix:$$QMP_SOCK,server=on,wait=off \
-display $(QEMU_DISPLAY) \
-no-reboot \
-d guest_errors; \
kill $$TAILPID 2>/dev/null; wait $$TAILPID 2>/dev/null || true; \
rm -f $$SERIAL_SOCK; \
rm -f $$SERIAL_SOCK $$QMP_SOCK; \
echo ""; \
echo "=== Serial log: $$LOG ==="; \
echo "=== Extracting DOE CSV ==="; \
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-22T03:40:17Z -->
<!-- Generated by mkcapsule --manifest 2026-08-22T11:46:44Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff