code wiki / _hdl_build / nx_nv.nx
nx_nv.nx source
↩ module page · 37 lines · 2527 B
1// nx_nv.nx -- the native-Linux NVIDIA OPEN-KERNEL-MODULE device shim (TIER-1 sovereign executor), sibling to
2// nx_dxg (the WSL2 GPU-PV shim). This is the path that ACTUALLY EXECUTES on real silicon -- modeled on tinygrad's
3// ops_nv.py, which submits via /dev/nvidia* + a GPFIFO ring + a usermode doorbell, bypassing the CUDA runtime
4// (and bypassing the proprietary dxg priv-data handshake that walls WSL2). Runs on a native-Linux / rented cloud
5// GPU instance (brick-safe, rule #26).
6//
7// LOCALLY-VERIFIABLE (gated bit-exact here): the GPFIFO entry encoder + the doorbell offset.
8// CLOUD-PENDING (structured, completed against the instance's open-gpu-kernel-modules headers on first run):
9// the full RM-API object tree -- NV_ESC_RM_ALLOC on /dev/nvidiactl for root client -> device -> subdevice ->
10// channel-group -> GPFIFO channel (NV_CHANNELGPFIFO_ALLOCATION_PARAMETERS) -> compute object; NV_ESC_RM_CONTROL
11// for GPFIFO_SCHEDULE + GET_WORK_SUBMIT_TOKEN; NV_ESC_RM_MAP_MEMORY for the usermode doorbell BAR.
12// Pure funcs, no main. license_tier: ORIGINAL
13import "nx_syscalls.nx"
14
15// NVIDIA RM ioctl escapes (NV_IOCTL_MAGIC='F'=0x46): the ioctl = _IOWR(0x46, NV_ESC_*, sizeof(param)).
16// (numbers from the open-gpu-kernel-modules ABI; struct sizes resolved on the cloud instance = TODO_CLOUD)
17const NV_ESC_RM_ALLOC: i64 = 0x2b
18const NV_ESC_RM_CONTROL: i64 = 0x2a
19const NV_ESC_RM_MAP_MEMORY: i64 = 0x4e
20// usermode doorbell: tinygrad writes the channel work-submit token to MMIO byte offset 0x90 (gpu_mmio[0x90/4]).
21const NV_DOORBELL_OFF: i64 = 0x90
22
23func nv_open_ctl() -> i64 { return sys_openat_rd("/dev/nvidiactl" as *u8) }
24func nv_open_dev() -> i64 { return sys_openat_rd("/dev/nvidia0" as *u8) }
25func nv_open_uvm() -> i64 { return sys_openat_rd("/dev/nvidia-uvm" as *u8) }
26
27// GPFIFO entry (real hardware format, per tinygrad ops_nv.py _submit_to_gpfifo):
28// entry = (gpu_va aligned to 4) | (len_dwords << 42) | (1 << 41)
29// = ((gpu_va>>2)<<2) clears the low 2 bits (matches tinygrad's `cmdq_addr//4 << 2`).
30func nv_gpfifo_entry(gpu_va: i64, len_dwords: i64) -> i64 { return ((gpu_va >> 2) << 2) | (len_dwords << 42) | (1 << 41) }
31
32// ring the doorbell: 32-bit write of the channel work-submit token to the mapped usermode MMIO at NV_DOORBELL_OFF.
33func nv_doorbell_ring(mmio_base: i64, token: i64) -> i64 {
34 let b: *u8 = (mmio_base + NV_DOORBELL_OFF) as *u8
35 b[0]=(token&0xff) as u8; b[1]=((token>>8)&0xff) as u8; b[2]=((token>>16)&0xff) as u8; b[3]=((token>>24)&0xff) as u8
36 return 0
37}