CHANGELOG 0.3.3.md — Notepad

Added

  • Audio on VirtualBox: AC'97 driver + audio HAL with backends. Audio only worked with virtio-sound-pci, so everything was mute on VBox, Doom included. The subsystem moves to a HAL mirroring the display one, with a backend-agnostic /dev/audio0 and two backends: virtio_sound and the new ac97 (kernel/ac97.cpp), driving the Intel ICH over bus-master DMA with pure CIV polling to dodge the INTx VBox never delivers.

  • LiveCD: a self-contained /disk in the ISO through a writable ramdisk. disk.img travels as a second Limine module and the kernel exposes it as an in-memory block device, so the ISO boots with /disk mounted. It is writable-ephemeral: changes are lost on reboot. A persistent IDE disk keeps priority.

  • Doom with Freedoom (a free IWAD) on the LiveCD. sdk/doomgeneric/build.ps1 bakes freedoom1.wad into /disk/games/doom/, so the ISO ships a playable Doom with no proprietary content. The engine still detects doom1.wad/doom.wad if supplied.

  • IOAPIC/MADT layer and IRQ routing by GSI. It parses the MADT, programs the redirection entries and routes GSIs to IDT vectors through the Local APIC (ioapic::route_gsi / route_legacy_irq), with vectors 50-63 reserved. PS/2 migrates to it, falling back to the legacy PIC without a MADT. Prerequisite for the ACPI SCI and for INTx through _PRT.

  • ACPI: SCI routed through the IOAPIC + power button. acpi::start_sci() enables ACPI mode, masks every GPE (no AML interpreter, to avoid storms on the level-triggered SCI), enables PWRBTN and routes the SCI. The handler triggers acpi::shutdown() (S5), with no graceful userland teardown.

  • uACPI vendored and integrated: a real AML interpreter. A baked copy of v6.0.0 under vendor/uacpi/, with glue in kernel/uacpi_glue.cpp over heap/vmm/pci/timer/ioapic and time from the TSC, because interrupts are off during bringup. It runs alongside the hand-rolled ACPI; uacpi_namespace_initialize() is deferred to the events stage.

  • INTx routing through uACPI's _PRT, closed end to end. route_pci_intx() resolves the link device to its real GSI by evaluating _CRS and programs the IOAPIC with the firmware's polarity and trigger. rtl8139 moves to interrupt-driven over this path. Legacy INTx now arrives on q35+APIC, the bottleneck that had forced MSI-X for virtio-gpu.

  • Native subsystem — Phase 2: native ABI v1 + a real runtime. savanxp_native_abi.h is the single source: a partitioned syscall space (< 0x1000 delegated to posix, >= 0x1000 its own), a mandatory version handshake (exit 132 on mismatch) and the first two native syscalls (SXN_SYS_INFO, SXN_SYS_LOG). The runtime gains a heap, operator new/delete and a mini freestanding <memory>, so Haxe classes run.

  • Native subsystem — _std override: real Haxe String and Array. reflaxe.CPP's _std is exposed as build-generated *.cross.hx overrides, Haxe's official per-platform mechanism. Two codegen fixes without patching the pinned libs: a Math.hx shadow and the UniqueLocalNames preprocessor, because flattened sibling blocks collided two for-in counters in one C++ scope.

  • Native subsystem — gfx ABI + a GUI hello in Haxe. A graphics syscall block (0x1010: GFX_INFO / ACQUIRE / RELEASE / PRESENT). The display is first-class ABI, with no /dev/gpu0 and no ioctls, sharing display::'s internals and the per-pid session. Haxe's Float does not work in freestanding yet.

  • Native subsystem — compositor client protocol (windowed apps). An sxn_gui_* layer speaking the v3 surface contract over fds 3..9, on baseline syscalls only. First native windowed app: nativegui, verified headless with test/guihost.c — also the first test of a subsystem switch through exec.

  • A generic waitable header in the Object Manager (object::Header). The signalling state duplicated per type moves into the common base, so a new waitable type no longer forces touching the wait dispatcher.

  • A real semaphore (SAVANXP_SYS_SEMAPHORE_CREATE/_RELEASE). The first use of the generic header: it saturates at max_count and rejects a release that would exceed it, with SDK wrappers and semaphoretest in the smoke suite.

  • build.ps1 run/debug: -Accel whpx support. It forces -cpu qemu64 because -cpu max/host under whpx crash OVMF with a #GP in PlatformPei. The automated targets stay on TCG on purpose.

  • virtio-sound: the end of silent muting. If the device responds but no output stream offers the ABI's fixed format, the failure is logged instead of leaving /dev/audio0 unregistered without a trace.

Changed

  • Kernel+userland compilation through Ninja. It replaces build.ps1's sequential, non-incremental phase (~250-300 sources) with parallel builds and header dependency tracking through -MMD, pinned in the toolchain. The link, the image, the ISO and QEMU are unchanged.

  • savanxp_mode_bits (SDK) loses the enum's fixed underlying type, which triggered -Wfixed-enum-extension in every TU including syscall.h. No functional change.

Fixed

  • virtio-gpu: SET_SCANOUT hung forever under WHPX. The boot got stuck at "Preparing display": the second wait tier fell to HLT, and during early boot the kernel runs with IF=0, so it only wakes on an NMI. The wait now uses timer::monotonic_ns() with a bounded busy spin.

  • virtio-sound: async multi-buffer TX playback. The TX path sent one period and spun waiting for the device with interrupts disabled. The queue now uses a ring of kTxSlots periods and drops instead of blocking when it is full.

  • AC'97: non-blocking playback, a silence cushion and no IOC. Three fixes for choppy audio on VirtualBox: submit_period stops spinning with IRQs off (it froze the guest clock Doom uses to pace audio and its logic); the BDL entries lose the interrupt-on-completion bit nobody serviced; and periods of silence are preloaded to absorb producer jitter. New ac97-count and ac97-stream.

  • "Robotic"/stuttering audio in Doom (underfeeding the device). DG_Sound_Update advanced every channel's position but wrote only the total rounded down to the period, feeding the device at ~0.75x and running effects ~1.34x fast. It was in the glue's common layer, so it sounded the same on both drivers.

  • Visual cursor residue over compositor elements. sx_painter_draw_frame drew the frame of the rect already intersected with the clip, so a fragmented repaint gave each fragment its own border. It now traces the original rect as four clipped strips. New headless regression build.ps1 cursor-repro.

  • Polish for fb_gpu and virtio-gpu. present_region read the origin from row 0 instead of the surface offset and GET_STATS returned zeros; refresh_scanouts no longer clobbers a fullscreen flip; the cursor queue's used header is read volatile; notify_off_multiplier == 0 no longer skips the notify; and REFRESH_SCANOUTS requires the graphics session.

  • build.ps1 silently forked to PowerShell 5.1 to generate assets. & powershell always resolves to Windows PowerShell, so running everything with pwsh 7 gave a false sense of portability. The scripts are now invoked in-process.

  • Join-Path paths with an embedded \, incompatible outside Windows. On Windows it worked by accident; on Linux \ stays a literal character. ~18 occurrences normalized to /.

Version 0.3.32026-07-0924 changes