Skip to content

M53 Card 1: GOWIN.ELF — a Go program owns a raw ADR 0007 window (Closes #1245) - #1282

Merged
drawmeanelephant merged 1 commit into
mainfrom
agent/autocoder/m53-go-first-app
Sep 15, 2026
Merged

drawmeanelephant merged 1 commit into
mainfrom
agent/autocoder/m53-go-first-app

Conversation

@drawmeanelephant

@drawmeanelephant drawmeanelephant commented Sep 15, 2026

Copy link
Copy Markdown
Owner

M53 Card 1 (umbrella #1244 is context only — it stays open).

Closes #1245

What this is

GOWIN.ELF — the first Go consumer of the raw ADR 0007 window seam, in the same family as tools/go/hello.go. One window, one filled rect, no chrome:

sys_win_open (12) -> id
sys_mmap (63)     -> a shared-anonymous back-buffer (MAP_ANONYMOUS|M33_MAP_SHARED)
sys_win_fill (13) -> a visible rect, drawn from that buffer
sys_win_present (14)
sys_poll_event (21) until CloseRequested / WIN_CLOSE (kind 8)
sys_win_close + sys_exit (15 + 3)

No LIBUI, no webrender, no browser, no HTTP, no tabs, no new syscall, kernel untouched, docs/status.md untouched, boot default unchanged. Each of the five markers is printed only after its syscall succeeded, so the marker chain is the syscall chain:

gowin: open id=2
gowin: fill
gowin: present
gowin: close
gowin OK

Files

Path Change
tools/go/gowin.go new — the program
tools/go/build-go.sh gowin -> GOWIN name mapping; links user/go into GOPATH as virelai so a fixture can import the shared guest SDK (the build-web.sh pattern). The five existing fixtures still build.
tools/gate/specs/go-win.spec new declarative class-B gate, cloned from go-hello.spec
docs/gate-fleet-inventory.md re-rendered (the repo requires this; never hand-edited)

The gate

Stages .build/go/GOWIN.ELF, execs it, holds dui close 2 (script2) until the program's own gowin: present line arrives, then asserts the five markers plus serial-absent '[EXC] parking:' and serial-absent 'exited status=139'.

dui close <n> is the privileged release path (driving_award.user_close -> remove_user_at), which is what pushes WIN_CLOSE to the window's owner; the first user window of a boot is id 2 (the terminal and the clock are the fixed windows) and the run asserts the program's own gowin: open id= line, so drift shows up as a failed gate rather than a silent pass.

Evidence

just gate go-win   -> PASS 1/1, runner rc 0, 12 s
                      gowin: open id=2 / fill / present / close / OK, no [EXC]
bash tools/inventory-gates.sh --check   -> OK

Beyond the markers, the frame captured at gowin: present was checked against the colour the program painted into its own back-buffer: 46,299 scanout pixels exact 0x3050a0, 96% of the window rect exact. And the gate was deliberately falsified — one marker assert changed to a string the program never prints turned the run red (serial-contains [...]=0, 01: FAIL) before the spec was restored.

Two findings the code records

  1. vi.MmapAnon cannot work from a Go program. It hard-codes addr = 0, and a hintless sys_mmap is refused with EINVAL: the GOOS=virelai runtime's sbrk heap reserves upward from the module end and covers the kernel's default mmap base (process.mmap_next_va = 0x1000_0000), which the issue-claim: GOOS=virelai 0b round 2: argv-flake root cause + ADR 0027 thread/futex slots 73/74 #1214 collision rule rejects. GOWIN passes an explicit page-aligned hint (12 GiB, clear of that heap and of the randomized EL0 stack band) through the same svc #0 gateway user/go/vi/vi_arm64.s implements, reached by //go:linkname — no new slot, no new file, no edit to user/go/vi.
  2. The scanout must be armed before a window can exist at all. driving_award.user_open returns EINVAL while the manager is unarmed, so a run without the display never reaches a window id (observed as gowin: error open -1 on the first cut of the spec). The spec carries --screen/--via-virtio for that reason.

Rollback

Nothing here mutates kernel state, persisted data, or configuration. Close this PR without merging (the claim on #1245 reopens), or git revert 94beb03. Deleting tools/gate/specs/go-win.spec removes the gate from the discovered fleet with no other edit.

Handoff

Card 2's codec is not in this PR; it lives on agent/autocoder/m53-tabcodec (its own claim is #1246). The maintainer adds the M53 row to docs/status.md at landing, and merge closes #1245.

M53 Card 1 (umbrella #1244 is context; it stays open).

tools/go/gowin.go -> GOWIN.ELF, the first Go consumer of the raw ADR 0007
window seam, in the same family as tools/go/hello.go: sys_win_open, a
shared-anonymous back-buffer over sys_mmap, a visible rect filled from that
buffer, sys_win_present, sys_poll_event until CloseRequested (WIN_CLOSE,
kind 8), then sys_win_close and sys_exit. No LIBUI, no webrender, no browser,
no HTTP, no new syscall, kernel untouched. Each of the five serial markers is
printed only after its syscall succeeded, so the marker chain IS the syscall
chain.

Two findings the code records, both observed live rather than assumed:

  * vi.MmapAnon hard-codes addr=0, and a hintless sys_mmap from a Go program
    is refused with EINVAL: the GOOS=virelai runtime's sbrk heap reserves
    upward from the module end and covers the kernel's default mmap base
    (process.mmap_next_va = 0x1000_0000), which the issue-#1214 collision rule
    rejects. GOWIN passes an explicit page-aligned hint (12 GiB, clear of the
    heap and of the randomized EL0 stack band) through the same `svc #0`
    gateway vi_arm64.s implements, reached by //go:linkname.
  * The scanout must be armed before a window can exist at all:
    driving_award.user_open returns EINVAL while the manager is unarmed, so a
    gate run without the display never reaches a window id (observed as
    `gowin: error open -1`).

tools/go/build-go.sh gains the gowin -> GOWIN name mapping and links user/go
into GOPATH as `virelai` (the build-web.sh pattern) so a fixture can import
the shared guest SDK; the five existing fixtures still build.

tools/gate/specs/go-win.spec is a new declarative class-B gate cloned from
go-hello.spec: it stages .build/go/GOWIN.ELF, execs it, holds `dui close 2`
(script2) until the program's own `gowin: present` line arrives, and asserts
the five markers plus serial-absent [EXC] and exited status=139.

Evidence: `just gate go-win` PASS 1/1 (runner rc 0; markers in order
open id=2 / fill / present / close / OK); inventory re-rendered and --check
clean; the gate was falsified by breaking one marker assert and confirmed red
before restoring. Card 2's codec was split out of this branch and lives on
agent/autocoder/m53-tabcodec.

Closes #1245
@drawmeanelephant
drawmeanelephant force-pushed the agent/autocoder/m53-go-first-app branch from 95a4d48 to 94beb03 Compare September 15, 2026 00:36
@drawmeanelephant drawmeanelephant changed the title M53 Cards 1+2: a Go program owns a raw window (GOWIN.ELF) and an independent Go .tabs v2 codec M53 Card 1: GOWIN.ELF — a Go program owns a raw ADR 0007 window (Closes #1245) Sep 15, 2026
@drawmeanelephant
drawmeanelephant merged commit fafe111 into main Sep 15, 2026
9 checks passed
@drawmeanelephant
drawmeanelephant deleted the agent/autocoder/m53-go-first-app branch September 15, 2026 00:48
drawmeanelephant added a commit that referenced this pull request Sep 15, 2026
The recipe listed the five runtime fixtures explicitly, so `just go-toolchain`
produced GOHELLO/GOARGS/GOROUT/GOSTRESS/GOPANIC but not GOWIN — and gate
go-win's setup hook needs that ELF, refusing with the exact build hint when it
is missing. GOWIN.ELF is a fleet member since #1282, so a fresh `just verify-vz`
reported the new gate as a setup failure. Adds tools/go/gowin.go to the
argument list and updates the recipe's fixture/gate enumeration to match.

No codec change: tools/go/tabcodec/** is untouched by this commit. Carried here
because the card that landed GOWIN.ELF could not declare the justfile.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

M53 Card 1: minimal Go window app

1 participant