From c3a295efd1b1132bbaa5d422cd05b3fa8e89a8bf Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 21 Sep 2026 13:06:51 -0400 Subject: kernel: Fix GSP emulation shadow binding, eventfd wiring, RPC livelocks + docs suite + repo reorg CRITICAL FIXES (guest driver bring-up): - gsp_emulation.c: emulation engine bound to the WRONG BAR0 - it polled the host physical BAR0 (bars[0].vaddr ioremap) for the doorbell and read RPCs from a local dma_alloc_wc buffer, while the guest writes land in the vzalloc'd bar0_shadow. The RPC path could never work; PBA writes even corrupted the host GPU's physical BAR0+0x3000. gsp_emu_init now binds exclusively to bar0_shadow (doorbell/mailbox/PBA aliases; shared_mem_dma==0 marks the alias so cleanup never dma_free's it). - main.c SET_IRQS: DATA_EVENTFD eventfds were DISCARDED ('TODO' + kfree) - the guest never received MSI-X completions. Full wiring now: eventfd_ctx_fdget per vector, fd -1 clears, dev_close releases refs. gsp_emu_inject_completion_interrupt looks up vgpu->irqs[0].trigger LIVE (init-time copy was permanently NULL since QEMU wires after gsp_emu_init). - gsp_rpc_client.c: BAR_TRAP/MIGRATE in emulation mode called gsp_rpc_submit_raw which rings the SAME doorbell the thread polls - self-triggered RPC livelock + multi-second stalls. Now fail fast with -ENOTSUPP + pr_warn_ratelimited (guest BAR access is direct MMIO). MORE FIXES: - main.c: nv_vgpu_config_write returned SIZE_MAX (while(count--) wrap) and was dead code while the VFIO write handler did unfiltered byte copies (guest could rewrite vendor ID/BARs). Return fixed; VFIO write handler now routes through the per-register filter. - kernel/Makefile: M=$(PWD) used the env var which is stale when invoked via the top-level make (pointed at repo root -> kbuild silently built NOTHING; explains every 'stale .ko' incident). Now M=$(CURDIR). - Warnings sweep: header prototypes for mdev/type functions, format casts in gsp_comm.c DRY-RUN logs, unused variable. ROBUSTNESS (harness/tooling): - vgpu_vm.py: run had no timeout (start could block forever); guest_shell recv could block forever on a wedged guest. Both now bounded; guest_shell pre-flights guest-ping and reports wedge diagnostics. - stack_manager.sh: qemu/qemu-debug now launch via the vgpu_vm.py harness (workflow rule: never raw QEMU). REPO REORGANIZATION: - driver/ (legacy guest-side gsp-vgpu.ko) moved to legacy-driver-guest/ (reference only, not built; README explains). 3 legacy un-buildable test files moved to legacy-driver-guest/kernel-tests/. Top-level Makefile cleaned of the dead DRIVER_DIR reference. DOCUMENTATION SUITE (new): - docs/GSP_EMULATION_ARCHITECTURE.md - emulator deep-dive: shadow BAR0 model, doorbell protocol, dispatch table, MSI-X path, lifecycle, memory- model caveats - docs/DEBUGGING.md - QEMU GDB stub workflow, serial console, QMP NMI, failure taxonomy, full bring-up validation checklist, EPT-livelock case study, version-matrix discipline - docs/ONBOARDING.md - repo tour, coding standards (incl. virt_to_phys / dma_addr_t / get-put rules), first build & test - docs/VERSION_UPGRADE.md - end-to-end new-driver-version procedure (firmware fetch, Ghidra analysis, configs, signatures, validation) - docs/PERFORMANCE.md - bare-metal A/B methodology + targets - README.md doc index; STATE.md refreshed; DEVELOPMENT_WORKFLOW.md corrected (load order: open-iov-vfio BEFORE nvidia; stock-driver blacklist note) --- docs/VERSION_UPGRADE.md | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 docs/VERSION_UPGRADE.md (limited to 'docs/VERSION_UPGRADE.md') diff --git a/docs/VERSION_UPGRADE.md b/docs/VERSION_UPGRADE.md new file mode 100644 index 0000000..94c7d68 --- /dev/null +++ b/docs/VERSION_UPGRADE.md @@ -0,0 +1,137 @@ +# Open-IOV Version Upgrade Guide + +> How to support a new NVIDIA driver version (e.g. moving from 570.144 to a +> 610-series release) end-to-end: firmware acquisition → reverse engineering → +> config → host driver → guest validation. The goal is that a version bump is +> **configuration + analysis**, not a rewrite. + +--- + +## 0. Version discipline (read first) + +Four components must stay in lock-step; a mismatch between any two produces +failures that are indistinguishable from emulation bugs: + +``` +guest nvidia driver == host OpenRM nvidia.ko == host GSP firmware == emulation target (decompiled GSP) +``` + +Today that anchor is **570.144** everywhere. When you bump one, you bump all +four. Verify with `docs/DEBUGGING.md` §7 before any deep debugging. + +--- + +## 1. Acquire the new firmware + matching OpenRM tag + +1. Download the Linux x86_64 runfile for the target version: + `https://us.download.nvidia.com/XFree86/Linux-x86_64//NVIDIA-Linux-x86_64-.run` + (the `tesla/` path 404s for consumer releases). +2. Extract the GSP firmware (`gsp_tu10x.bin` / arch-specific) — or fetch the + versioned blob from `linux-firmware.git`: + `nvidia//gsp_tu10x.bin`. +3. Extract the `.fwimage` section (host boot image) and record the MD5: + ```bash + objcopy --only-section=.fwimage gsp_tu10x.bin gsp-.fwimage.bin + md5sum gsp-.fwimage.bin + ``` +4. Note the matching OpenRM tag at + `github.com/NVIDIA/open-gpu-kernel-modules` (e.g. `570.144`). + +## 2. Lay down versioned directories (never overwrite a working version) + +``` +firmware/-GSP// # e.g. firmware/61X-GSP/610.XX/ + gsp-.fwimage.bin + decompiled/ # ghidra output lands here +config/versions/.yaml # e.g. config/versions/610.yaml +``` + +Copy the analysis scripts from the previous version dir +(`firmware/57X-GSP/570.144/*.py`) into the new one — they are script-relative. + +## 3. Reverse-engineer the new firmware (Ghidra headless) + +```bash +cd tools/ghidra +python3 analyze_fwimage.py \ + ../../firmware/-GSP//gsp-.fwimage.bin \ + /tmp/ghidra_project_ "gsp_" +cd ../../firmware/-GSP/ +python3 analyze_firmware.py gsp-.fwimage.bin +``` + +What to extract (compare against `wiki/Address-Reference.md` for 570.144W): + +| Artifact | Why it matters | +|----------|----------------| +| Primary RPC dispatcher + jump table | RPC types/subcommands may shift | +| BAR trap / WPR handlers | BAR emulation behavior | +| Entry/boot sequence | GSP boot RPC ordering the guest driver expects | +| Migration tables | migration protocol (if enabled) | +| RPC message layouts | struct changes break the emulator silently | +| Version string/signature | runtime firmware matching | + +Sanity checks: still RV64IMAC? still the same 12 top-level RPC types? new +subcommands? Confidential-computing/TEE additions? + +## 4. Produce the version config + +Update `config/versions/.yaml` with: +- `version.name/major/minor` and `firmware.gsp_version` +- discovered dispatcher/handler addresses (if tracked in yaml) +- `features` toggles per what the firmware actually has +- `symbols` (the nvidia.ko vGPU VFIO interface — verify against the new + OpenRM tag; renamed exports break the nvidia build) + +## 5. Update the runtime signature database + +`kernel/firmware_analyzer.c` matches firmware by CRC32/SHA256 + patterns. +Add the new entry to `known_signatures[]` (version string, hashes, discovered +addresses). This is what lets one `open-iov-vfio.ko` serve multiple firmware +versions safely. + +## 6. Rebuild host + guest against the new anchor + +1. Point `patches/nvidia/` at the new OpenRM tag (rebase our delta; verify + `modinfo nvidia.ko | grep depends` still shows `open-iov-vfio`). +2. `./scripts/stack_manager.sh build-all` (kernel → nvidia → userspace). +3. Install the new host firmware to `/lib/firmware/` + (`stack_manager.sh install-firmware`). +4. **Guest**: install the *matching* stock driver in the VM (runfile for the + exact version), replacing the old one. Keep the guest able to boot without + nvidia auto-loading during the swap (temporarily move dkms-built modules + aside — see `docs/DEBUGGING.md`). + +## 7. Validate (same checklist every version) + +Run the full bring-up checklist in `docs/DEBUGGING.md` §5: +module load → mdev → VM boot → guest probe → `nvidia-smi` → teardown +regression → unit test. Then the workload tests (CUDA vectorAdd, graphics). +Only after the checklist is green do performance comparisons +(`docs/PERFORMANCE.md`). + +## 8. Rollback plan + +Keep the previous version's directory + config untouched. Rollback = +`git checkout` the repo tag/commit for the old anchor + reinstall the old +guest driver. Because versions live in parallel directories, the working +setup is never destroyed by a forward attempt. + +## 9. Multi-version testing matrix (target state) + +For each supported anchor version × each supported GPU family +(`config/hardware/*.yaml`), the CI matrix should run the §7 checklist. When +adding a version, extend the matrix rather than replacing the old column — +regressions across versions are the cheapest bugs to catch. + +## 10. Common pitfalls (learned the hard way) + +- **Runfile version drift**: Ubuntu's `nvidia-driver-XXX-open` metapackages + can resolve to a *newer* major (570-open pulled 580). Always check the + candidate version before installing; prefer the exact-version runfile. +- **GSP firmware filename**: guest driver requests `nvidia//gsp_tu10x.bin`; + a wrong-version firmware file = probe failure that looks like an emulation bug. +- **Kernel text addresses differ per build**: re-derive Ghidra addresses per + firmware; never carry 570.144 addresses into a 610 config. +- **Symbol renames across OpenRM tags**: `nvidia_vgpu_vfio_*` renames break + the nvidia build with `Unknown symbol` — check `kernel-open` diffs. -- cgit v1.2.3