summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_emulation.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 18:01:55 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 18:01:55 -0400
commit6aadb593750736f239fd54a0ccef4b3834c08fc4 (patch)
tree5b3d39d82a09cdfd3ca8022cd9c0f83040f23229 /kernel/gsp_emulation.c
parentc8249854284c3e8181587b96e3c5b4177d705e0c (diff)
downloadopen-iov-6aadb593750736f239fd54a0ccef4b3834c08fc4.tar.gz
open-iov-6aadb593750736f239fd54a0ccef4b3834c08fc4.zip
kernel: GSP-RM msgq emulation + TU104 hardware tables (GET_GSP_STATIC_INFO, GSP_RM_CONTROL)
Implements the GSP-RM reply content layer for the msgq RPC channel: - kernel/gsp_rm_emulation.c/h: GSP-RM msgq emulation engine - Queue chain discovery (libos args → RMARGS → GSP_ARGUMENTS_CACHED) - Status queue link + GSP_INIT_DONE emission - Command queue polling + RPC dispatch - SET_GUEST_SYSTEM_INFO version negotiation (VGX 41.12) - GET_GSP_STATIC_INFO(65) with 1656-byte GspStaticConfigInfo - GSP_RM_CONTROL(76) sub-command dispatch: - FIFO_GET_DEVICE_INFO_TABLE (0x20801112) - INTERNAL_INTR_GET_KERNEL_TABLE (0x20800a5c) - GPU_GET_CONSTRUCTED_FALCON_INFO (0x208001b0) - INTERNAL_GET_DEVICE_INFO_TABLE (0x20800a40) - kernel/gsp_rm_tu104.h: TU104 hardware tables - 12-entry FIFO engine table (GR0, CE0-4, NVDEC0-1, NVENC0, SEC2, NVJPG, SW) - 8-entry interrupt table (from intr_phys_tu102.c) - 1-entry constructed falcon table (FBFLCN) - 11-entry internal device info table - GspStaticConfigInfo layout (1656 bytes, ABI-verified offsets) - Data from NVIDIA driver material (ext-tree) + hwref/turing/tu104 - tools/rmq/: Userspace RM API client (oracle for ground-truth tables) KNOWN ISSUE: gsp_rm_send crashes (fortify_panic) on multi-element messages when reply data exceeds one 4096-byte queue element. Affects cmd 0x20800a41 (paramsSize=8204). Multi-element splitting is the next fix.
Diffstat (limited to 'kernel/gsp_emulation.c')
-rw-r--r--kernel/gsp_emulation.c135
1 files changed, 73 insertions, 62 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c
index 81c319f..f96e521 100644
--- a/kernel/gsp_emulation.c
+++ b/kernel/gsp_emulation.c
@@ -21,6 +21,7 @@
#include "nvidia-vgpu-vfio.h"
#include "gsp_emulation.h"
+#include "gsp_rm_emulation.h"
#include "gsp_rpc_client.h"
#include "bar_emulation.h"
#include "irq.h"
@@ -95,6 +96,9 @@ static const struct {
{ 0x1fa824, "WPR2_ADDR_LO" },
{ 0x1fa828, "WPR2_ADDR_HI" },
{ 0x001438, "VBIOS_SCRATCH_0E" },
+ { 0x840040, "SEC2_MAILBOX0" },
+ { 0x840100, "SEC2_CPUCTL" },
+ { 0x8403c0, "SEC2_ENGINE" },
};
static void gsp_emu_poll_falcon_watch(struct gsp_emu_context *ctx)
@@ -124,19 +128,8 @@ static void gsp_emu_poll_falcon_watch(struct gsp_emu_context *ctx)
* Physical GSP Boot Emulation (FWSEC / Booter falcon auto-complete)
* ============================================================ */
-/* BAR0 shadow offsets used by the guest's physical GSP boot */
-#define GSP_EMU_REG_GSP_CPUCTL 0x110100 /* bit1 STARTCPU, bit4 HALTED */
-#define GSP_EMU_REG_GSP_ENGINE 0x1103c0 /* bit0 RESET */
-#define GSP_EMU_REG_GSP_MAILBOX0 0x110040
-#define GSP_EMU_REG_VBIOS_SCRATCH_0E 0x001438 /* FRTS err code (0=NONE) */
-#define GSP_EMU_REG_WPR2_ADDR_LO 0x1fa824
-#define GSP_EMU_REG_WPR2_ADDR_HI 0x1fa828
-#define GSP_EMU_REG_RISCV_STATUS 0x110240 /* bit0 ACTIVE (NV_PRISCV_RISCV
- CORE_SWITCH_RISCV_STATUS at
- GSP riscv base 0x110000) */
-
-#define GSP_EMU_CPUCTL_STARTCPU 0x2
-#define GSP_EMU_CPUCTL_HALTED 0x10
+/* Register offsets + CPUCTL bits live in gsp_emulation.h (shared with
+ * gsp_rm_emulation.c), as are gsp_emu_shadow_read32/write32. */
enum gsp_emu_boot_stage {
GSP_BOOT_STAGE_IDLE = 0, /* waiting for first kick (FWSEC) */
@@ -144,17 +137,6 @@ enum gsp_emu_boot_stage {
GSP_BOOT_STAGE_BOOTER_DONE, /* Booter Load completed */
};
-static inline void gsp_emu_shadow_write32(struct gsp_emu_context *ctx,
- u32 offset, u32 val)
-{
- writel(val, ctx->bar0_vaddr + offset);
-}
-
-static inline u32 gsp_emu_shadow_read32(struct gsp_emu_context *ctx, u32 offset)
-{
- return readl(ctx->bar0_vaddr + offset);
-}
-
/*
* gsp_emu_poll_boot - drive the guest's physical GSP boot to completion.
*
@@ -167,69 +149,74 @@ static inline u32 gsp_emu_shadow_read32(struct gsp_emu_context *ctx, u32 offset)
*/
static void gsp_emu_poll_boot(struct gsp_emu_context *ctx)
{
- u32 cpuctl = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_GSP_CPUCTL);
+ u32 gsp_cpuctl = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_GSP_CPUCTL);
+ u32 sec2_cpuctl = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_SEC2_CPUCTL);
u32 engine = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_GSP_ENGINE);
- /* ENGINE reset asserted -> falcon rebooted, restart stage tracking */
+ /* GSP ENGINE reset asserted -> falcon rebooted, restart stage tracking */
if ((engine & 0x1) && ctx->boot_stage != GSP_BOOT_STAGE_IDLE) {
ctx->boot_stage = GSP_BOOT_STAGE_IDLE;
ctx->flcn_kick_count = 0;
nv_vgpu_info(ctx->vgpu, "GSP-BOOT: falcon reset, back to IDLE");
+ /* The guest is rebooting the GSP (new probe or unload): the
+ * GSP-RM queue state is stale, reset it too. */
+ gsp_rm_emu_reset(ctx);
return;
}
- /* Nothing to do unless the guest kicked the falcon */
- if (!(cpuctl & GSP_EMU_CPUCTL_STARTCPU))
- return;
-
- ctx->flcn_kick_count++;
-
- switch (ctx->boot_stage) {
- case GSP_BOOT_STAGE_IDLE:
- /*
- * First kick after reset: FWSEC (FRTS setup). Complete it:
- * - CPUCTL: clear STARTCPU, set HALTED
- * - VBIOS_SCRATCH[0x0E] FRTS_ERR_CODE = NONE (0)
- * - WPR2_ADDR_HI != 0, WPR2_ADDR_LO = frtsOffset >> 0xc
- * frtsOffset is learned from the driver's own error message if
- * our value mismatches (deterministic for fixed FB + fw image).
- */
+ /*
+ * FWSEC kick on the GSP falcon (FRTS setup). Complete it:
+ * - CPUCTL: clear STARTCPU, set HALTED
+ * - VBIOS_SCRATCH[0x0E] FRTS_ERR_CODE = NONE (0)
+ * - WPR2_ADDR_HI != 0, WPR2_ADDR_LO = frtsOffset >> 0xc (in _VAL bits31:4)
+ */
+ if ((gsp_cpuctl & GSP_EMU_CPUCTL_STARTCPU) &&
+ ctx->boot_stage == GSP_BOOT_STAGE_IDLE) {
gsp_emu_shadow_write32(ctx, GSP_EMU_REG_VBIOS_SCRATCH_0E, 0);
- gsp_emu_shadow_write32(ctx, GSP_EMU_REG_WPR2_ADDR_HI, 0x1);
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_WPR2_ADDR_HI, 0x100000);
gsp_emu_shadow_write32(ctx, GSP_EMU_REG_WPR2_ADDR_LO,
ctx->wpr2_addr_lo);
gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_CPUCTL,
GSP_EMU_CPUCTL_HALTED);
ctx->boot_stage = GSP_BOOT_STAGE_FWSEC_DONE;
+ ctx->flcn_kick_count++;
nv_vgpu_info(ctx->vgpu, "GSP-BOOT: FWSEC kick completed "
"(WPR2_LO=0x%x)", ctx->wpr2_addr_lo);
- break;
-
- case GSP_BOOT_STAGE_FWSEC_DONE:
- /*
- * Second kick: Booter Load (loads/authenticates GSP-RM image,
- * starts the RISCV). Complete it:
- * - CPUCTL: clear STARTCPU, set HALTED
- * - MAILBOX0 = 0 (booter success status)
- * - RISCV_STATUS = ACTIVE (kflcnIsRiscvActive passes)
- */
- gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_MAILBOX0, 0);
+ return;
+ }
+
+ /*
+ * Booter Load kick on the SEC2 falcon (loads/authenticates the GSP-RM
+ * image and starts the GSP RISCV). Complete it:
+ * - SEC2 CPUCTL: clear STARTCPU, set HALTED
+ * - SEC2 MAILBOX0 = 0 (booter error code, 0 = success)
+ * - GSP RISCV_STATUS = ACTIVE (Booter started the RISCV;
+ * kflcnIsRiscvActive passes)
+ */
+ if ((sec2_cpuctl & GSP_EMU_CPUCTL_STARTCPU) &&
+ ctx->boot_stage == GSP_BOOT_STAGE_FWSEC_DONE) {
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_SEC2_MAILBOX0, 0);
gsp_emu_shadow_write32(ctx, GSP_EMU_REG_RISCV_STATUS, 0x1);
- gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_CPUCTL,
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_SEC2_CPUCTL,
GSP_EMU_CPUCTL_HALTED);
ctx->boot_stage = GSP_BOOT_STAGE_BOOTER_DONE;
+ ctx->flcn_kick_count++;
nv_vgpu_info(ctx->vgpu, "GSP-BOOT: Booter kick completed, "
"RISCV active");
- break;
+ /* The driver has programmed the libos init args address into
+ * GSP MAILBOX0/1 by now; parse the queue chain, link the
+ * status queue and emit GSP_INIT_DONE. */
+ gsp_rm_emu_on_booter_done(ctx);
+ return;
+ }
- default:
- /* Later kicks (e.g. resume/unload): just complete them */
+ /* Any other STARTCPU kick (resume/unload/etc.): just complete it */
+ if (gsp_cpuctl & GSP_EMU_CPUCTL_STARTCPU)
gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_CPUCTL,
GSP_EMU_CPUCTL_HALTED);
- nv_vgpu_info(ctx->vgpu, "GSP-BOOT: extra kick #%u completed",
- ctx->flcn_kick_count);
- break;
- }
+ if (sec2_cpuctl & GSP_EMU_CPUCTL_STARTCPU)
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_SEC2_CPUCTL,
+ GSP_EMU_CPUCTL_HALTED);
}
/* ============================================================
@@ -449,6 +436,9 @@ static int gsp_emu_thread_fn(void *data)
/* Drive the guest's physical GSP boot to completion */
gsp_emu_poll_boot(ctx);
+ /* GSP-RM msgq emulation (physical path: sysmem cmd/status queues) */
+ gsp_rm_emu_poll(ctx);
+
if (doorbell_val != 0) {
/* ACK doorbell immediately */
gsp_emu_write_doorbell(ctx, 0);
@@ -518,6 +508,17 @@ int gsp_emu_init(struct nv_vgpu_device *vgpu)
init_completion(&ctx->thread_stopped);
spin_lock_init(&ctx->lock);
+ /* Physical GSP boot emulation state. wpr2_addr_lo matches what the
+ * guest driver expects WPR2_ADDR_LO to read after FWSEC FRTS:
+ * frtsOffset = fbSize - reservedFromEnd. With fbSize = 256MB
+ * (LOCAL_MEMORY_RANGE) and the 570.144 image's 2MB reservation,
+ * frtsOffset = 0x10000000 - 0x200000 = 0xfe00000; the register's
+ * _VAL field (bits31:4) must equal frtsOffset >> 12 = 0xfe00, so the
+ * raw register value is 0xfe000. */
+ ctx->boot_stage = 0; /* GSP_BOOT_STAGE_IDLE */
+ ctx->flcn_kick_count = 0;
+ ctx->wpr2_addr_lo = 0x000fe000;
+
/* The guest's BAR0 is the emulation shadow (vzalloc'd by
* nv_vgpu_bar_emul_init, mapped to the guest via VFIO mmap) - NOT the
* host physical BAR0 (vgpu->bars[0].vaddr, which belongs to the real GPU
@@ -556,6 +557,13 @@ int gsp_emu_init(struct nv_vgpu_device *vgpu)
/* Enable emulation mode in RPC client */
gsp_rpc_emulation_set(true);
+ /* Initialize GSP-RM msgq emulation (physical path) */
+ ret = gsp_rm_emu_init(vgpu, ctx);
+ if (ret) {
+ nv_vgpu_err(vgpu, "Failed to init GSP-RM emulation: %d", ret);
+ goto err_fini_client;
+ }
+
/* NOTE: MSI-X eventfd triggers are NOT copied here - QEMU wires them
* via VFIO_DEVICE_SET_IRQS later, so gsp_emu_inject_completion_interrupt
* looks them up live from vgpu->irqs[]. */
@@ -605,6 +613,9 @@ void gsp_emu_cleanup(struct nv_vgpu_device *vgpu)
}
ctx->running = false;
+ /* Teardown GSP-RM msgq emulation */
+ gsp_rm_emu_fini(ctx);
+
/* Disable emulation mode */
gsp_rpc_emulation_set(false);