port(romdata): POSIX fixed-address ROM map (mmap) for the Linux build

The cart-base map at 0x10000000 (so absolute ROM-asset symbols are live host
pointers) was Windows-only; the #else branch was a stub that logged
"not implemented" and fell to the degraded heap-copy path.

- Factor the post-map work (memcpy + pcmodels/pccg sidecar load + D55 RLE
  header fixup) into romdataFinishCartMap(), shared by both paths.
- POSIX #else: anonymous mmap at CART_BASE with MAP_FIXED_NOREPLACE where
  available; on any failure munmap + fall through to the identical heap copy.
- romdataDestroy() munmaps on POSIX (length tracked in mappedLen).

Verified on Windows: builds 242/242, -level_09 boots crash-free (identical
behaviour with/without the refactor). Linux compile + runtime verification
owed — see docs/dev/LINUX-PORT.md. No behaviour change on Windows.
This commit is contained in:
James Dansereau committed 2026-09-02 21:15:01 -04:00
1 parent 702dee61fc
commit b01c7fa89c
2 files changed
+168 -44

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
# Linux port — status & gap analysis
Session M-38 (2026-09-02). Goal-2 on the roadmap (after the Windows alpha /
release artifact). This is a scoping + first-patch pass; **nothing here has run
on a Linux machine yet.**
## Method
Read `build-pc.sh`, `CMakeLists.txt`, `docs/building.md`, and grepped
`port/src`, `port/fast3d`, `port/include` for Windows-only headers / Win32 APIs
/ unguarded `_WIN32` branches. A local Qwen `triage` pass seeded the hunt; every
claim below was re-checked against the real files (the 27B was wrong on two of
three headline items — see "Ruled out").
## What is already Linux-ready (verified by reading)
- **`port/include/platform.h`** — sets `PLATFORM_LINUX` / `PLATFORM_MACOS` /
`PLATFORM_WINDOWS` cleanly.
- **`CMakeLists.txt`** — `find_package(SDL2 REQUIRED)`, `find_package(ZLIB
REQUIRED)`, and `else()` branches already present for the non-Windows case:
`GL_LIBRARY = GL` (l.291), `EXTRA_LIBRARIES = stdc++ m dl pthread` (l.304),
`elseif(UNIX)` platform block (l.86). `WIN32_EXECUTABLE` and the MinGW zlib
fallback are correctly `if(WIN32)` / `if(MINGW)` guarded.
- **`build-pc.sh`** — already documents the Linux apt deps
(`cmake libsdl2-dev zlib1g-dev libgl1-mesa-dev`) and is a plain bash script,
no MSYS-isms in the executable body.
- **`port/src/system.c`** — `sysSleep()` has a `nanosleep()` `#else` branch
(l.76-82); `<windows.h>` is `PLATFORM_WINDOWS`-guarded.
- **`port/src/libultra.c`** — the OS-thread kernel has a real pthreads branch
next to the Win32 `_beginthreadex` one.
- **`port/src/crash.c`** — `MessageBoxW` / `SetThreadPriority` / `__debugbreak`
all `_WIN32`-guarded, with `PLATFORM_LINUX` counterparts.
- **`port/src/video.c`** — `GE_MKDIR` has both `_mkdir` and `mkdir(p,0777)`.
- No `__declspec`, `#pragma comment`, or hardcoded `\`-path / drive-letter
usage anywhere in `port/`.
## Ruled out (Qwen triage false positives)
- ~~`system.c:75` `Sleep()` has no POSIX branch~~ — it does (`nanosleep`).
- ~~CMake needs `else()` branches for zlib/pthread on Linux~~ — already there.
## The one real code gap — FIXED this session (verification owed)
**`port/src/romdata.c`** — the fixed-address cart map (`0x10000000`, so absolute
ROM-asset symbols are live host pointers) had a **Windows-only** implementation
(`VirtualAlloc`); the `#else` branch was a stub that logged "not implemented on
this platform" and fell straight to the heap-copy fallback. In heap-copy mode
anything that dereferences a cart address *directly* (not via
`romdataGetRom()` / the PI shims) reads wrong memory — so Linux would run, if at
all, in the same degraded mode Windows only hits when `VirtualAlloc` loses the
address race.
**Change (M-38):**
- Factored the post-map work (memcpy + `pcmodelsLoadSidecars` +
`pccgLoadSidecars` + D55 RLE-header fixup) into `romdataFinishCartMap()`,
shared by both paths so they cannot drift.
- POSIX `#else` now does an anonymous `mmap((void*)CART_BASE, len,
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED_NOREPLACE, -1, 0)`.
`MAP_FIXED_NOREPLACE` (Linux 4.17+) fails rather than clobbering an existing
mapping; where the macro is absent the plain hint is advisory and the
`at == CART_BASE` check catches a relocated result. On any failure it
`munmap`s and falls through to the identical heap-copy path as before.
- `romdataDestroy()` `munmap`s on POSIX (tracked length in `mappedLen`).
**Owed verification (needs a Linux box):**
1. Compiles under GCC on Linux (`<sys/mman.h>` resolves; no decomp-include-path
shadowing surprise).
2. `mmap` actually lands at `0x10000000` on a stock ASLR Linux — `0x10000000`
(256 MB) is low but usually free; if the kernel routinely refuses it,
consider linking the binary no-PIE or reserving the range via a linker
script so the loader keeps it clear.
3. `-level_09` boots crash-free with the mapped path taken (check the log says
"mapped at 0x10000000 (cart base)", not "using heap copy").
4. Whether the heap-copy fallback is actually survivable on Linux if step 2
fails — audit for direct `0x1xxxxxxx` derefs outside the PI shims.
## Remaining Linux work after the romdata patch lands
| # | Item | Size | Note |
|---|------|------|------|
| 1 | Run the Ubuntu **`validate`** CI job → upgrade it to a real **compile** job | S | `.github/workflows/ci.yml` already configures on Ubuntu; flipping it to `cmake --build` surfaces the real GCC-strictness gaps cheaply |
| 2 | First actual Linux runtime bring-up (`-level_09`) | M | expect a short tail of unguarded calls / struct-layout asserts GCC-on-Linux vs MinGW |
| 3 | `docs/building.md` — promote Linux from "untested" to "supported" once 1+2 pass | S | |
| 4 | SDL2 / GL context creation on X11 + Wayland | M | fast3d is GL 3.3 core; PD port runs on Linux so the path is known-good |
| 5 | Package: an AppImage or tarball equivalent of `bundle-win.sh` | M | reuse `prepare-assets.py` verbatim — it is already OS-agnostic |
## Recommended next step
Land the romdata patch behind CI (item 1) — turn the Ubuntu `validate` job into
a compile job in the same PR so the "does it build on Linux" question is
answered by the bots, then do the runtime bring-up on a real machine.