From c8249854284c3e8181587b96e3c5b4177d705e0c Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 21 Sep 2026 14:10:43 -0400 Subject: kernel: Present physical TU104 to guest + emulate GSP boot (FWSEC/Booter) + VBIOS serving Guest driver probe fixes (unmodified 570.144 open driver on physical path): - kernel/main.c: add show_description to the mdev driver. Userspace mdev management tools parse 'framebuffer=M' from every mdev type's description sysfs file before creating an mdev; the missing file made such tools fail to create the vGPU. Also fix create_mdev.sh for the real type dir name pci-nvidia-vgpu-* (mdev core names dirs dev_driver_string(parent)-; the parent registers before nvidia.ko binds so dev_driver_string == 'pci'). - kernel/bar_emulation.c: seed BAR0 shadow so guest sees a REAL, PHYSICAL, non-virtual TU104 (user directive: no PV/VF vGPU paths, unmodified driver): * PMC_BOOT_0/1/42 = physical TU104 values captured from host hardware (0x164000a1 / 0x0 / 0x164a1000). Without these, halmgrGetHalForGpu() fails and probe aborts with 'does not include the required GSP'. * Serve a valid VBIOS at the PROM window (BAR0+0x300000) loaded from /lib/firmware/tu104_vbios.bin (dump of host TU104 ROM). Guest's kgspExtractVbiosFromRom_TU102 needs it for the mandatory FWSEC ucode (kgspGetFrtsSize is hardwired to 1MB on Turing). * Pre-set GSP secure-boot (GFW) completion state: PGC6 PLM (0x118128)=1, GFW_BOOT progress (0x118234)=0xFF, GSP falcon CPUCTL HALTED (0x110100). The driver's post-FLR GFW wait only *waits* (never kicks), so the pre-set state satisfies it immediately. - kernel/gsp_emulation.c/h: physical GSP boot emulation. * Falcon boot-watch: poll GSP falcon/PGC6/WPR2/scratch registers and log changes (guest BAR0 is mmap-based, otherwise invisible to host). * gsp_emu_poll_boot: STARTCPU auto-complete state machine. Guest kicks FWSEC then Booter Load via GSP falcon CPUCTL; detect each kick and complete the stage (HALTED + FRTS err NONE + WPR2 + mailbox + RISCV-active) so the guest believes its ucodes ran. Diagnosis that led here (documented in Handoff-vGPU-IO.md): - Open nvidia.ko can never be an SR-IOV VF vGPU guest: os_is_grid_supported() is a stub returning FALSE in the open build (disassembled). PV path also rejected per user directive. Only the physical path with a fully emulated local GSP boot remains. --- kernel/gsp_emulation.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) (limited to 'kernel/gsp_emulation.c') diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c index bfd8be7..81c319f 100644 --- a/kernel/gsp_emulation.c +++ b/kernel/gsp_emulation.c @@ -65,6 +65,173 @@ static inline void gsp_emu_copy_response_to_shared(struct gsp_emu_context *ctx, memcpy(ctx->shared_mem_virt + 0x80, rsp, sizeof(*rsp)); } +/* ============================================================ + * GSP Falcon Boot-Watch (observability for physical GSP boot) + * ============================================================ */ + +/* + * The guest's physical GSP boot (FWSEC -> Booter -> RISCV) pokes the GSP + * falcon block via the mmap'd shadow, which the host cannot trap. Poll these + * BAR0 offsets and log changes so the boot sequence is visible in host dmesg. + */ +static const struct { + u32 offset; + const char *name; +} gsp_emu_falcon_watch[GSP_EMU_FALCON_WATCH_COUNT] = { + { 0x110040, "GSP_MAILBOX0" }, + { 0x110044, "GSP_MAILBOX1" }, + { 0x110080, "GSP_FALCON_OS" }, + { 0x110100, "GSP_CPUCTL" }, + { 0x110180, "GSP_IMEMC" }, + { 0x110184, "GSP_IMEMD" }, + { 0x1101c0, "GSP_DMEMC" }, + { 0x1101c4, "GSP_DMEMD" }, + { 0x1103c0, "GSP_ENGINE" }, + { 0x110c04, "GSP_QUEUE_HEAD1" }, + { 0x110c08, "GSP_QUEUE_TAIL0" }, + { 0x110c0c, "GSP_QUEUE_TAIL1" }, + { 0x118128, "PGC6_PLM_GFW" }, + { 0x118234, "PGC6_GFW_BOOT" }, + { 0x1fa824, "WPR2_ADDR_LO" }, + { 0x1fa828, "WPR2_ADDR_HI" }, + { 0x001438, "VBIOS_SCRATCH_0E" }, +}; + +static void gsp_emu_poll_falcon_watch(struct gsp_emu_context *ctx) +{ + int i; + + for (i = 0; i < GSP_EMU_FALCON_WATCH_COUNT; i++) { + u32 val = readl(ctx->bar0_vaddr + gsp_emu_falcon_watch[i].offset); + + if (!ctx->falcon_watch_valid) { + ctx->falcon_watch_last[i] = val; + continue; + } + + if (val != ctx->falcon_watch_last[i]) { + nv_vgpu_info(ctx->vgpu, "FALCON %s (0x%x): 0x%08x -> 0x%08x", + gsp_emu_falcon_watch[i].name, + gsp_emu_falcon_watch[i].offset, + ctx->falcon_watch_last[i], val); + ctx->falcon_watch_last[i] = val; + } + } + ctx->falcon_watch_valid = true; +} + +/* ============================================================ + * 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 + +enum gsp_emu_boot_stage { + GSP_BOOT_STAGE_IDLE = 0, /* waiting for first kick (FWSEC) */ + GSP_BOOT_STAGE_FWSEC_DONE, /* FWSEC FRTS completed */ + 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. + * + * The guest driver kicks falcon ucodes (FWSEC for FRTS, then Booter Load for + * GSP-RM) by writing STARTCPU to the GSP falcon CPUCTL, then polls for HALTED + * plus stage-specific result registers. The auto-boot waits (GFW) are already + * satisfied by the state pre-set in nv_vgpu_bar_emul_init. Here we watch for + * STARTCPU kicks and complete each stage so the guest believes its falcon + * ucodes ran successfully. + */ +static void gsp_emu_poll_boot(struct gsp_emu_context *ctx) +{ + u32 cpuctl = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_GSP_CPUCTL); + u32 engine = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_GSP_ENGINE); + + /* 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"); + 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). + */ + 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_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; + 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); + gsp_emu_shadow_write32(ctx, GSP_EMU_REG_RISCV_STATUS, 0x1); + gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_CPUCTL, + GSP_EMU_CPUCTL_HALTED); + ctx->boot_stage = GSP_BOOT_STAGE_BOOTER_DONE; + nv_vgpu_info(ctx->vgpu, "GSP-BOOT: Booter kick completed, " + "RISCV active"); + break; + + default: + /* Later kicks (e.g. resume/unload): just complete them */ + 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; + } +} + /* ============================================================ * RPC Processing * ============================================================ */ @@ -276,6 +443,12 @@ static int gsp_emu_thread_fn(void *data) /* Read doorbell */ doorbell_val = gsp_emu_read_doorbell(ctx); + /* Watch GSP falcon boot registers (physical GSP boot tracing) */ + gsp_emu_poll_falcon_watch(ctx); + + /* Drive the guest's physical GSP boot to completion */ + gsp_emu_poll_boot(ctx); + if (doorbell_val != 0) { /* ACK doorbell immediately */ gsp_emu_write_doorbell(ctx, 0); -- cgit v1.2.3