summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 19:04:05 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 19:04:05 -0400
commit6b686f70d8ff3e6340e8307c95847cd1eed4f2ae (patch)
tree71cf22aff298900e4073427534eab4ce93a6ef84 /kernel
parent256c5308423befddc20bdf7e59a663f3f1b683ae (diff)
downloadopen-iov-6b686f70d8ff3e6340e8307c95847cd1eed4f2ae.tar.gz
open-iov-6b686f70d8ff3e6340e8307c95847cd1eed4f2ae.zip
kernel: Fix FIFO table fortify_panic + GSP boot-state reset on queue death + ISO fbRegion
- gsp_rm_handle_fifo_device_table: read baseIndex from the queue element buffer (req_data + hdr), not past the local 24-byte header struct - FORTIFY proved the old memcpy always overflows -> fortify_panic killed gsp_emu_0 mid RmInitNvDevice (guest timed out on fn 76). - gsp_emu_clear_boot_state: clear WPR2/RISCV/mailboxes/stage tracker and reset GSP-RM queue state. Turing guests produce no observable BAR0 writes on unload, so the next probe's _kgspBootGspRm failed with 'unexpected WPR2 already up'. Trigger on ENGINE reset and on detected queue death (insane writePtr jump / garbage element signature). - GspStaticConfigInfo fbRegion[0].supportISO=1: memmgrCalcReservedFbSpace asserts some region supports ISO 'even with no display'; without it kdispStateInitLocked couldn't allocate clientChannelTable. - .gitignore: scripts/git-push-vgpu.sh (local per-machine helper)
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_emulation.c30
-rw-r--r--kernel/gsp_emulation.h5
-rw-r--r--kernel/gsp_rm_emulation.c40
3 files changed, 64 insertions, 11 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c
index 3b6f6e5..5522bf3 100644
--- a/kernel/gsp_emulation.c
+++ b/kernel/gsp_emulation.c
@@ -138,6 +138,32 @@ enum gsp_emu_boot_stage {
};
/*
+ * gsp_emu_clear_boot_state - return the emulated GSP to a cold state.
+ *
+ * On real hardware, driver unload tears down WPR2 (Booter Unload) so the
+ * next probe's _kgspBootGspRm WPR2-up check passes. Turing guests produce
+ * no observable BAR0 writes on unload, so callers must trigger this on
+ * indirect death signals (ENGINE reset, GSP-RM queue going stale).
+ * Clears WPR2, RISCV active status and the falcon stage tracker, and
+ * drops the parsed GSP-RM queue state.
+ */
+void gsp_emu_clear_boot_state(struct gsp_emu_context *ctx, const char *reason)
+{
+ nv_vgpu_info(ctx->vgpu, "GSP-BOOT: clearing boot state (%s)", reason);
+
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_WPR2_ADDR_LO, 0);
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_WPR2_ADDR_HI, 0);
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_RISCV_STATUS, 0);
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_MAILBOX0, 0);
+ gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_MAILBOX1, 0);
+
+ ctx->boot_stage = GSP_BOOT_STAGE_IDLE;
+ ctx->flcn_kick_count = 0;
+
+ gsp_rm_emu_reset(ctx);
+}
+
+/*
* gsp_emu_poll_boot - drive the guest's physical GSP boot to completion.
*
* The guest driver kicks falcon ucodes (FWSEC for FRTS, then Booter Load for
@@ -155,12 +181,10 @@ static void gsp_emu_poll_boot(struct gsp_emu_context *ctx)
/* 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);
+ gsp_emu_clear_boot_state(ctx, "ENGINE reset");
return;
}
diff --git a/kernel/gsp_emulation.h b/kernel/gsp_emulation.h
index 668d567..fe4186e 100644
--- a/kernel/gsp_emulation.h
+++ b/kernel/gsp_emulation.h
@@ -44,6 +44,7 @@
#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_GSP_MAILBOX1 0x110044
#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
@@ -121,6 +122,10 @@ static inline u32 gsp_emu_shadow_read32(struct gsp_emu_context *ctx, u32 offset)
int gsp_emu_init(struct nv_vgpu_device *vgpu);
void gsp_emu_cleanup(struct nv_vgpu_device *vgpu);
+
+/* Clear emulated GSP boot state (WPR2/RISCV/stages/RM queues) on
+ * ENGINE reset or detected GSP death (stale msgq). */
+void gsp_emu_clear_boot_state(struct gsp_emu_context *ctx, const char *reason);
int gsp_emu_process_rpc(struct gsp_emu_context *ctx);
void gsp_emu_inject_completion_interrupt(struct gsp_emu_context *ctx, u32 seq_id);
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index e152e5c..1ed63ab 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -526,7 +526,12 @@ static void gsp_rm_build_static_info(u8 *buf)
val64 = 0; memcpy(&region->reserved, &val64, 8);
val32 = 0; memcpy(&region->performance, &val32, 4);
region->supportCompressed = 0;
- region->supportISO = 0;
+ /* memmgrCalcReservedFbSpace asserts that SOME region supports
+ * ISO "even if we have no display" - without it the reserved
+ * space split fails and kdisp can't allocate its channel
+ * table. A single ISO-capable region satisfies fast/slow/iso
+ * assignment. */
+ region->supportISO = 1;
region->bProtected = 0;
memset(region->blackList, 0, sizeof(region->blackList));
}
@@ -670,6 +675,7 @@ struct gsp_rm_control_req {
static void gsp_rm_handle_fifo_device_table(struct gsp_emu_context *ctx,
u32 sequence,
struct gsp_rm_control_req *req,
+ const u8 *req_params,
u32 *out_status,
u8 *out_params, u32 *out_params_size)
{
@@ -678,8 +684,14 @@ static void gsp_rm_handle_fifo_device_table(struct gsp_emu_context *ctx,
fifo_params = (struct tu104_fifo_get_device_info_params *)out_params;
base = 0;
- if (req->paramsSize >= 4)
- memcpy(&base, (u8 *)(req + 1), 4);
+ /* baseIndex is the first field of the request params, which live in
+ * the queue element buffer (NOT after the local header struct!). Only
+ * readable when the whole request fits in the first element. */
+ if (req->paramsSize >= 4 &&
+ req->paramsSize + GSP_RM_CTRL_HDR_SIZE <= GSPRM_MAX_SINGLE_ELEM_DATA)
+ memcpy(&base, req_params, 4);
+ if (base >= TU104_FIFO_TABLE_MAX_DEVICES)
+ base = 0;
/* How many entries to return in this page */
count = TU104_ENGINE_TABLE_SIZE - base;
@@ -847,6 +859,7 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
switch (req.cmd) {
case TU104_CTRL_FIFO_GET_DEVICE_INFO_TABLE:
gsp_rm_handle_fifo_device_table(ctx, sequence, &req,
+ req_data + GSP_RM_CTRL_HDR_SIZE,
&out_status,
reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
break;
@@ -975,9 +988,15 @@ static void gsp_rm_poll_commands(struct gsp_emu_context *ctx)
if (tx.writePtr < rm->cmd_read ||
(tx.writePtr - rm->cmd_read) > rm->cmd_msgcount) {
- nv_vgpu_warn(ctx->vgpu, "GSPRM: cmd writePtr jumped %u -> %u, resyncing",
+ /* The writePtr is monotonic for the life of a boot. A backward
+ * or insane jump means the queue buffer was torn down - the
+ * guest driver unloaded (or crashed) without an observable
+ * GSP shutdown. Declare the emulated GSP dead: clear WPR2 /
+ * RISCV / boot stages so the next probe's WPR2-up check
+ * passes and it re-boots from scratch. */
+ nv_vgpu_warn(ctx->vgpu, "GSPRM: cmd writePtr jumped %u -> %u, GSP boot declared dead",
rm->cmd_read, tx.writePtr);
- rm->cmd_read = tx.writePtr;
+ gsp_emu_clear_boot_state(ctx, "stale GSP-RM queue");
return;
}
@@ -1003,12 +1022,17 @@ static void gsp_rm_poll_commands(struct gsp_emu_context *ctx)
if (signature != GSPRM_RPC_SIGNATURE || elem_count == 0 ||
elem_count > rm->cmd_msgcount) {
- nv_vgpu_warn(ctx->vgpu, "GSPRM: bad element idx=%u sig=0x%x elemCount=%u fn=%u, skipping",
+ /* The driver always writes a valid element BEFORE
+ * bumping writePtr. An advanced writePtr with garbage
+ * content means the queue buffer is stale (freed and
+ * reused by the guest after unload/crash) - declare
+ * the emulated GSP dead so the next probe re-boots. */
+ nv_vgpu_warn(ctx->vgpu, "GSPRM: garbage element idx=%u sig=0x%x elemCount=%u fn=%u, GSP boot declared dead",
rm->cmd_read, signature, elem_count,
hdr->function);
- rm->cmd_read++;
kfree(elem);
- continue;
+ gsp_emu_clear_boot_state(ctx, "garbage GSP-RM queue");
+ return;
}
gsp_rm_handle_element(ctx, elem);