page under ?mem64=1: GL and the host X server work (B0)

- kernel: MAP_32BIT (x86-64) places an anonymous mapping below the high arena;
- guest GL: the command ring is mapped MAP_32BIT, since the browser host takes its address as
  32 bits (a 64-bit process put it above 4 GiB and every submit failed);
- page: the host X server takes the wasm32 kernel build under mem64 (its own memory is wasm32).

tests/games/src/glx-context passes in Chromium with a 64-bit guest memory (0 failures).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_d2453757b8a84fdbb4ee7c9e093141df
This commit is contained in:
velzieandClaude Opus 5.5 committed 2026-10-07 21:23:35 -04:00
1 parent 02efdd5970
commit d442cc5755
4 files changed
+20 -5

No files matched your search

+4
View File
@@ -32,6 +32,10 @@ pub mod flags {
pub const FIXED_NOREPLACE: u64 = 0x100000;
pub const ANONYMOUS: u64 = 0x20;
pub const NORESERVE: u64 = 0x4000;
/// x86-64's `MAP_32BIT`: below 2 GiB. In an M64 process it keeps an
/// anonymous mapping out of the high arena (the guest GL library's command
/// ring, whose address the browser host takes as 32 bits).
pub const MAP_32BIT: u64 = 0x40;
pub const STACK: u64 = 0x20000;
}
+2 -2
View File
@@ -5190,8 +5190,8 @@ impl Kernel {
// code, so in a 64-bit memory it stays below 4 GiB with the code; the
// loader runs at INTERP_BASE (docs/mem64.md §3).
let from_loader = (gex_abi::INTERP_BASE..gex_abi::STACK_TOP - gex_abi::STACK_SIZE).contains(&self.syscall_pc);
let start = if from_loader {
self.mem.mmap_low(addr, len, prot_bits, flags, "")?
let start = if from_loader || (cfg!(feature = "x86") && flags & mflags::MAP_32BIT != 0) {
self.mem.mmap_low(addr, len, prot_bits, flags & !mflags::MAP_32BIT, "")?
} else {
self.mem.mmap(addr, len, prot_bits, flags, "")?
};
+11 -2
View File
@@ -103,8 +103,17 @@ static int ring_open(void) {
return -1;
}
size_t total = HEADER_BYTES + CMD_CAPACITY + REPLY_CAPACITY;
void *p = mmap(NULL, total, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
/* MAP_32BIT on x86-64: the host takes the ring's address as 32 bits (the
browser's gl_submit), and a process with a 64-bit memory would otherwise
get it above 4 GiB. */
void *p = MAP_FAILED;
#if defined(__x86_64__) && defined(MAP_32BIT)
p = mmap(NULL, total, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
#endif
if (p == MAP_FAILED)
p = mmap(NULL, total, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) {
close(gl_fd);
gl_fd = -1;
+3 -1
View File
@@ -572,7 +572,9 @@ export async function runProgram(
xwaylandUrl: new URL('/gex/xwayland/Xwayland.mjs', location.href).href,
hostwlUrl: new URL('/gex/xwayland/gexhostwl.wasm', location.href).href,
keymapUrl: new URL('/gex/xwayland/gex.xkm', location.href).href,
kernel: { module: kernel.module, memory: kernel.memory },
// The X server's own memory is a wasm32 one, so with `?mem64=1` it takes the
// wasm32 build of the kernel (same kernel memory, other process-memory type).
kernel: { module: m64Infix() ? await WebAssembly.compile(await fetchBytes(`/gex/gex_kernel${archInfix()}.wasm`)) : kernel.module, memory: kernel.memory },
wlChannel,
// A name in the scene arena that no guest pid can collide with: pids
// count up from 1, and this is 'xwl1' as ASCII.