summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 08:08:41 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 08:08:41 -0400
commita42e596308dc05e4b691ce219e27297872f7ccff (patch)
tree58fbc413e1654b0dde08d0ce4699d69d9684bf4b
parent968cd2dca6c463efb44dd04ad92f23eda81da33a (diff)
downloadopen-iov-a42e596308dc05e4b691ce219e27297872f7ccff.tar.gz
open-iov-a42e596308dc05e4b691ce219e27297872f7ccff.zip
docs: ANALYSIS-egl-engine-selection - the EGL 3D-engine wall's failing chain (shipped-binary evidence)
Records the eglcore->glsi chain that rejects the engine candidate (0xee00001 out of the glsi engine-init), the ruled-out hypotheses (RM controls answer NV_OK; the engine passes the walk's own filters; stable under gdb no-ASLR) and the exact breakpoints/offsets for the next trace.
-rw-r--r--userspace/cuda/570.144/docs/ANALYSIS-egl-engine-selection.md115
1 files changed, 115 insertions, 0 deletions
diff --git a/userspace/cuda/570.144/docs/ANALYSIS-egl-engine-selection.md b/userspace/cuda/570.144/docs/ANALYSIS-egl-engine-selection.md
new file mode 100644
index 0000000..9c7ed67
--- /dev/null
+++ b/userspace/cuda/570.144/docs/ANALYSIS-egl-engine-selection.md
@@ -0,0 +1,115 @@
+# ANALYSIS - EGL 3D-engine selection wall (570.144 guest userspace)
+
+Status: OPEN (2026-10-23). The EGL-device path initialises (devices enumerate,
+`eglInitialize` succeeds, `vendor=NVIDIA`), but `eglMakeCurrent` fails with
+`EGL_BAD_ALLOC (0x3003)` because the per-device EGL-core client creator
+returns NULL after a lower-layer engine-init call fails.
+
+This document records the *shipped-binary* evidence only (disassembly +
+live gdb traces). Method: run the probe under gdb with ASLR disabled
+(gdb's default) so library offsets are stable, set breakpoints at the
+recorded offsets, and read the arguments/returns.
+
+## 1. The failing chain (libnvidia-eglcore.so.570.144)
+
+```
+eglMakeCurrent
+ -> NvGlEglApiInit family: per-device EGL-core client creator (+0xa246f0)
+ -> +0xa06ed0 (device/engine selection wrapper)
+ -> +0x9fe790 (engine-list walk)
+ list head: *( *(device + 0x28738) + 8 )
+ filters per engine: engine[0x59] & 0x40
+ engine[0x70] == 0
+ per-engine callback: *0x70( *(*(engine+0x28738)+0x10) )
+ -> +0xa22000 (callback)
+ rbx = *(reqs + 0xa0) (device object)
+ mode = *(reqs + 0x20)
+ mode 6 -> +0xa09830
+ mode 7 -> +0xa0a4d0
+ else -> +0x9fdfd0(device, engine, obj, reqs)
+ NULL -> EGL_BAD_ALLOC
+```
+
+`+0x9fdfd0` ends in the rejection site:
+
+```
+9fe146: rax = *(r14 + 0x10) ; r14 = *(engine + 0x28738)
+9fe14d: rdi = *(rbx + 0x20) ; rbx = *(reqs + 0xa0) (device object)
+9fe151: call *0x30(rax) ; vtable slot 0x30
+9fe154: test eax,eax
+9fe156: je 9fe170 ; 0 == continue (success)
+9fe158: free(tmp); return 0 ; non-zero == reject
+```
+
+## 2. The rejecting method (libnvidia-glsi.so.570.144)
+
+The vtable at `*(*(engine+0x28738)+0x10)` is a *glsi* device-engine vtable;
+its slot 0x30 resolves (live gdb: vtable `0x7ffff71ddfe0`, method
+`+0xa29440` in eglcore terms = glsi `+0x5f480` base-adjusted) to the glsi
+engine-init entry:
+
+```
+glsi +0x5f480(device, reqs):
+ 5f4c0: fd = *(*(*(dev+0x108)+0x58)) ; int fd (nvidia device)
+ 5f4c8: rsi = *(dev+0x118)
+ 5f4dc: call +0x1aba0(fd, rsi, reqs) ; FIRST call
+ 5f52e: call +0x1af20(...) ; second call
+```
+
+Live trace (probe `egl_frame` under gdb, breakpoint at the callback's call
+site): the **first** glsi call returns `0xee00001`; the caller propagates it
+and the engine is rejected. `0xee00001` is a glsi-internal status produced by
+two sites (`glsi +0x31f84`, `+0x33910`) that set flag bit `0x20` in the
+device's `+0xb84` word and return "busy"-style; the engine-init state machine
+(`glsi +0x301b0` and callees `+0x2fbe0` -> `+0x29760` -> `+0x32110`/`+0x2dc70`)
+is what fails.
+
+## 3. What is ruled out
+
+* **Not an RM-control error.** During the failing probe the emulated GSP
+ answers every `GSP_RM_CONTROL` with `status=0x0` (including the
+ `0x20810107` BINAPI query that was previously suspected; that one is a red
+ herring - a real class-0x2081 object on the live session answers
+ `NV_OK`/`{0,0}` exactly like the emulation).
+* **Not the engine-list shape alone.** The single candidate engine passes the
+ walk's own filters (`flag59 & 0x40` set, `f70 == 0`), so the list contains
+ a usable engine; the failure is inside the per-engine init.
+* **Not ASLR-dependent.** All offsets above are stable under gdb
+ (`set disable-randomization on`).
+
+## 4. Next steps (for the successor)
+
+1. Trace `glsi +0x301b0`'s internal calls (returns of `+0x3a6f0`,
+ `+0x2ac10`, `+0x2fbe0`, `+0x29760`, `+0x32110`, `+0x2dc70`) to find the
+ first non-zero return; that call is the true failing layer.
+2. Compare the glsi device-engine state with the same probe on a physical
+ Turing GPU (the host's own 570 driver runs the identical userspace; a
+ host-side `egl_frame` run with the real GPU succeeds, so a differential
+ dump of the engine records / the `+0xb84` flags word will show what the
+ emulated device is missing).
+3. The engine records glsi consumes come from the kernel driver's device
+ data (engine table + class list). The CUDA path builds the analogous
+ records from `GET_ENGINES_V2`; the CUDA engine list on this guest is
+ known to be complete for GR + CE (see the private analysis area). The
+ glsi path may require an entry (e.g. a specific engine kind or a caps
+ bit) that the emulated device does not report.
+
+## 5. Reproduction
+
+```
+# in the guest (570.144 stock driver):
+gcc -O2 -o /tmp/egl_frame /tmp/egl_frame.c -lEGL -lGLESv2 # tools/guest-diag/egl_frame.c
+timeout 90 /tmp/egl_frame # EGL_CURRENT_FAIL err=0x3003
+
+# under gdb (offsets stable, ASLR disabled):
+gdb -q -batch -x egl-gdb11.txt ./egl_frame # catches the vtable call site
+```
+
+Breakpoints used (no-ASLR addresses with eglcore base 0x7ffff5200000,
+glsi base 0x7ffff7e2a000):
+
+| address | meaning |
+|---|---|
+| `0x7ffff5bfe151` | eglcore rejection call `*0x30(vtable)` |
+| `0x7ffff7e89480` | glsi engine-init entry (+0x5f480) |
+| `0x7ffff7e894e1` | after glsi's first inner call (returns 0xee00001) |