summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_rm_emulation.c197
-rw-r--r--kernel/gsp_sema_service.c21
2 files changed, 205 insertions, 13 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 49758b4..b8a3e37 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -3159,11 +3159,22 @@ static void gsp_rm_handle_rm_alloc(struct gsp_emu_context *ctx,
gsp_rm_register_channel(ctx, ho, params, params_size);
/*
- * NV01_EVENT (allocated with class 0x79 in the guest ABI; params are
- * NV0005_ALLOC_PARAMETERS {hParentClient, hSrcResource, hClass,
- * notifyIndex, data}). The driver allocates one per channel and waits
- * for the GPU to post the event before it considers submitted work
- * complete - remember them so completed work can be signalled back.
+ * NV01_EVENT (params are NV0005_ALLOC_PARAMETERS {hParentClient,
+ * hSrcResource, hClass, notifyIndex, data}). The driver allocates one
+ * per channel and waits for the GPU to post the event before it
+ * considers submitted work complete - remember them so completed work
+ * can be signalled back.
+ *
+ * r682: the guest ABI uses THREE event classes and only the
+ * NV01_EVENT_OS_EVENT (0x79) shape was registered: libcuda's channel
+ * events arrive as 0x79, but the modern nvkms/Vulkan path allocates
+ * NV01_EVENT_KERNEL_CALLBACK_EX (0x7E, nvos.h) - observed live as
+ * `GSP_RM_ALLOC class=0x7e paramsSize=24 hParent=<subdevice>
+ * hObject=0xcaf00003` from the second RM client while its main
+ * thread sat in the vkCreateDevice wait loop (readiness word in a
+ * /dev/nvidiactl notification page, never signalled). Register 0x78
+ * (KERNEL_CALLBACK) and 0x7E alongside 0x79 so the completion
+ * wake-ups reach those events too.
*
* The table is append+retire: FREE retires records (valid=false) but
* never shrinks events_n, so long-lived boots with many client
@@ -3176,7 +3187,8 @@ static void gsp_rm_handle_rm_alloc(struct gsp_emu_context *ctx,
* first retired slot for a new registration, and log loudly when the
* table is genuinely full of live entries.
*/
- if (class_id == 0x79 && params_size >= 24) {
+ if ((class_id == 0x79 || class_id == 0x7e || class_id == 0x78) &&
+ params_size >= 24) {
u32 h_src = 0, notify_index = 0, hclass = 0;
u64 data64 = 0;
int hc_off = -1, i;
@@ -3194,16 +3206,17 @@ static void gsp_rm_handle_rm_alloc(struct gsp_emu_context *ctx,
rm->events_n, ho);
else {
/*
- * Locate hClass (0x79) inside the params instead of
- * trusting a fixed offset: NV0005_ALLOC_PARAMETERS is
- * {hParentClient, hSrcResource, hClass, notifyIndex,
- * data}, with hSrcResource immediately before hClass.
+ * Locate hClass (0x78/0x79/0x7e) inside the params
+ * instead of trusting a fixed offset:
+ * NV0005_ALLOC_PARAMETERS is {hParentClient,
+ * hSrcResource, hClass, notifyIndex, data}, with
+ * hSrcResource immediately before hClass.
*/
for (i = 0; i + 4 <= (int)params_size; i += 4) {
u32 v;
memcpy(&v, params + i, 4);
- if (v == 0x79) {
+ if (v == 0x79 || v == 0x7e || v == 0x78) {
hc_off = i;
break;
}
@@ -3440,6 +3453,60 @@ MODULE_PARM_DESC(gsp_rm_binapi07_fwd,
"Forward only the guest GL core's BINAPI 0x20810107 query to the live GSP session (default 0; diagnostic/experiment)");
/*
+ * session 75: reply words for the client-pending control 0x2080a097 (the
+ * libnvidia-eglcore engine-readiness poll). Runtime-tunable so one boot can
+ * sweep reply variants: the client reads +0x204, +0x488 and +0x48c back
+ * (file offsets 0xecd45f..0xecd475) before its engine loop re-issues the
+ * control. Defaults: flag=1 (the request sets it to 0), the other words 0.
+ */
+static uint gsp_rm_a097_flag = 1;
+module_param_named(wall2_a097_flag, gsp_rm_a097_flag, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_flag, "0x2080a097 reply word at params+0x204 (default 1)");
+static uint gsp_rm_a097_v488;
+module_param_named(wall2_a097_v488, gsp_rm_a097_v488, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_v488, "0x2080a097 reply word at params+0x488 (default 0)");
+static uint gsp_rm_a097_v48c;
+module_param_named(wall2_a097_v48c, gsp_rm_a097_v48c, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_v48c, "0x2080a097 reply word at params+0x48c (default 0)");
+
+/*
+ * session 76: the 0x2080a097 reply's RECORD area (params+4..+0x23). The
+ * real host RM handler overwrites up to four {u32, u32} mode pairs there
+ * (per-mode engine status + a x1000 clock/percent value); the client
+ * (count=1) copies back the first 16 bytes into its per-engine query
+ * buffer, and the second word of the first pair is consumed as the
+ * "engine progress" word (libnvidia-eglcore d5e3e0: *(inner+4) ->
+ * session+0xe104, compared against per-boot config thresholds).
+ * Each word defaults to 0xffffffff = leave the echoed request word
+ * untouched; any other value replaces it, so one boot can sweep the
+ * record matrix without rebuilding.
+ */
+static uint gsp_rm_a097_count = ~0u;
+module_param_named(wall2_a097_count, gsp_rm_a097_count, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_count, "0x2080a097 reply count word at params+0 (0xffffffff = echo)");
+static uint gsp_rm_a097_rec0 = ~0u, gsp_rm_a097_rec1 = ~0u;
+static uint gsp_rm_a097_rec2 = ~0u, gsp_rm_a097_rec3 = ~0u;
+static uint gsp_rm_a097_rec4 = ~0u, gsp_rm_a097_rec5 = ~0u;
+static uint gsp_rm_a097_rec6 = ~0u, gsp_rm_a097_rec7 = ~0u;
+module_param_named(wall2_a097_rec0, gsp_rm_a097_rec0, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec0, "0x2080a097 reply word at params+0x4 (0xffffffff = echo)");
+module_param_named(wall2_a097_rec1, gsp_rm_a097_rec1, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec1, "0x2080a097 reply word at params+0x8 (0xffffffff = echo)");
+module_param_named(wall2_a097_rec2, gsp_rm_a097_rec2, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec2, "0x2080a097 reply word at params+0xc (0xffffffff = echo)");
+module_param_named(wall2_a097_rec3, gsp_rm_a097_rec3, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec3, "0x2080a097 reply word at params+0x10 (0xffffffff = echo)");
+module_param_named(wall2_a097_rec4, gsp_rm_a097_rec4, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec4, "0x2080a097 reply word at params+0x14 (0xffffffff = echo)");
+module_param_named(wall2_a097_rec5, gsp_rm_a097_rec5, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec5, "0x2080a097 reply word at params+0x18 (0xffffffff = echo)");
+module_param_named(wall2_a097_rec6, gsp_rm_a097_rec6, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec6, "0x2080a097 reply word at params+0x1c (0xffffffff = echo)");
+module_param_named(wall2_a097_rec7, gsp_rm_a097_rec7, uint, 0644);
+MODULE_PARM_DESC(wall2_a097_rec7, "0x2080a097 reply word at params+0x20 (0xffffffff = echo)");
+
+
+/*
* The live session's oracle client/object for the 0x20810107 experiment,
* created on demand; 0 until the first query builds it. One device per module
* load, so file-statics are enough; reset by unload.
@@ -4215,6 +4282,72 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
break;
}
+ case 0x2080a097: { /* client-pending engine-context query (session 75)
+ *
+ * libnvidia-eglcore issues this via NVOS54 and then
+ * POLLS the reply's params words: the request sets
+ * +0x204 = 0, and the caller re-issues the whole
+ * control every ~1.8 s while its readiness check
+ * stays negative (observed: 32-36 polls against the
+ * generic all-zero reply, then the client gives up
+ * and vkCreateDevice returns -4). The params are an
+ * in/out record block: u32 count at +0, then count
+ * 16-byte records, then +0x204, and the client reads
+ * back +0, +0x204, +0x488 and +0x48c after the call
+ * (libnvidia-eglcore.so.570.144 file offsets
+ * 0xecd45f..0xecd475). The readiness wait itself
+ * lives in the client's engine loop
+ * (0xd6ef40..0xd6f0ab polling byte +0x1b038 of the
+ * engine object, which a91ea0 recomputes from many
+ * state fields), so the reply words below are
+ * runtime-tunable for a single-cycle sweep without
+ * rebuilding: the wall2_a097_* module parameters.
+ *
+ * Reply: verbatim echo (the request records are the
+ * client's own query data) with the tunable words
+ * applied. Defaults keep the completion-style flag. */
+ u8 *rp = reply + GSP_RM_CTRL_HDR_SIZE;
+ const u8 *pp = req_data + GSP_RM_CTRL_HDR_SIZE;
+
+ if (req.paramsSize >= 0x490 &&
+ req.paramsSize + GSP_RM_CTRL_HDR_SIZE <=
+ GSPRM_MAX_SINGLE_ELEM_DATA) {
+ u32 count = 0, flag;
+ static const u32 *const recp[8] = {
+ &gsp_rm_a097_rec0, &gsp_rm_a097_rec1,
+ &gsp_rm_a097_rec2, &gsp_rm_a097_rec3,
+ &gsp_rm_a097_rec4, &gsp_rm_a097_rec5,
+ &gsp_rm_a097_rec6, &gsp_rm_a097_rec7,
+ };
+ int i;
+
+ memcpy(rp, pp, req.paramsSize);
+ memcpy(&count, pp, 4);
+ memcpy(&flag, pp + 0x204, 4);
+ if (gsp_rm_a097_count != ~0u)
+ *(u32 *)(rp + 0) = gsp_rm_a097_count;
+ for (i = 0; i < 8; i++) {
+ if (*recp[i] != ~0u)
+ *(u32 *)(rp + 4 + i * 4) = *recp[i];
+ }
+ *(u32 *)(rp + 0x204) = gsp_rm_a097_flag;
+ *(u32 *)(rp + 0x488) = gsp_rm_a097_v488;
+ *(u32 *)(rp + 0x48c) = gsp_rm_a097_v48c;
+ if (gsp_sema_dbg)
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: ctrl 0x2080a097: echoed %u bytes (count=%u, req flag=%u) -> flag=%u v488=0x%x v48c=0x%x",
+ req.paramsSize, count, flag,
+ gsp_rm_a097_flag, gsp_rm_a097_v488,
+ gsp_rm_a097_v48c);
+ out_status = 0;
+ out_params_size = req.paramsSize;
+ } else {
+ out_status = 0;
+ out_params_size = 0;
+ }
+ break;
+ }
+
default:
/* Unknown control command - return success with zeroed params.
* Do NOT echo the request: pure queries pass uninitialized
@@ -4656,6 +4789,23 @@ static void gsp_rm_handle_element(struct gsp_emu_context *ctx, const u8 *elem)
* For vGPU, we just acknowledge success. */
nv_vgpu_info(ctx->vgpu, "vgsp-rm: RPC UPDATE_BAR_PDE(%u) seq=%u len=%u -> SUCCESS",
function, sequence, hdr->length);
+ {
+ const u8 *pl = (const u8 *)hdr + sizeof(*hdr);
+ u32 n = min_t(u32, hdr->length, 64);
+ char dump[256];
+ int o = 0;
+ u32 i;
+
+ for (i = 0; i < n; i += 4) {
+ u32 v = 0;
+
+ memcpy(&v, pl + i, 4);
+ o += snprintf(dump + o, sizeof(dump) - o,
+ "%08x ", v);
+ }
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: bar-pde payload: %s", dump);
+ }
if (gsp_rm_send(ctx, function, sequence, 0, NULL, 0))
nv_vgpu_err(ctx->vgpu, "vgsp-rm: UPDATE_BAR_PDE reply send failed");
else
@@ -4684,6 +4834,31 @@ static void gsp_rm_handle_element(struct gsp_emu_context *ctx, const u8 *elem)
nv_vgpu_info(ctx->vgpu, "vgsp-rm: RPC %s(%u) seq=%u len=%u -> generic SUCCESS reply (unknown #%llu)",
gsp_rm_rpc_name(function), function,
sequence, hdr->length, rm->unknown_rpcs);
+ /*
+ * Bounded payload dump for the first unknown RPCs: the vGPU
+ * guest maps its client VA spaces through some RPC; the
+ * mapping data (va pages / PAs / memdesc handles) must be
+ * visible here to be captured. Never echo it back (pure
+ * queries would eat their own stack garbage).
+ */
+ if (rm->unknown_rpcs <= 96 && hdr->length) {
+ const u8 *pl = (const u8 *)hdr + sizeof(*hdr);
+ u32 n = min_t(u32, hdr->length, 64);
+ char dump[256];
+ int o = 0;
+ u32 i;
+
+ for (i = 0; i < n; i += 4) {
+ u32 v = 0;
+
+ memcpy(&v, pl + i, 4);
+ o += snprintf(dump + o, sizeof(dump) - o,
+ "%08x ", v);
+ }
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: unknown fn=%u seq=%u len=%u payload: %s",
+ function, sequence, hdr->length, dump);
+ }
if (gsp_rm_send(ctx, function, sequence, 0, NULL, 0))
nv_vgpu_err(ctx->vgpu, "vgsp-rm: reply send failed fn=%u", function);
else
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index b6fa436..993e507 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -88,6 +88,20 @@ static inline u64 svc_fb_shadow_size(const struct nv_vgpu_device *vgpu)
#define SEMA_VA_LO 0x100000000ULL
#define SEMA_VA_HI 0x2000000000ULL
+/*
+ * session 79: the GR/GL ucode init releases target the RM's LOW aperture
+ * (the same 0x4000000-0x4ffffff VA family as the push/ring windows): the
+ * live GL init push carries `2005c017 04923060 ... 02000001` (0x5c-form,
+ * va=0x4923060, payload 1, RELEASE) and `200426c0 00000000 04b19b10
+ * 00000001 10000000` (REPORT_SEM group, va=0x4b19b10, payload 1,
+ * RELEASE) - both rejected by the sysmem-only range check, so the GR
+ * completion never applied and the NvOgl engine-init wait spun forever.
+ * Accept the low aperture for release decode (the pushes are only
+ * decoded from trusted ring reads, so the false-positive risk the
+ * sysmem bound guarded against does not apply here).
+ */
+#define SVC_LOW_REL_VA_LO 0x4000000ULL
+
/* Canonical kernel virtual address range (x86_64). */
#define KVA_LO 0xffff800000000000ULL
#define KVA_HI 0xffffc00000000000ULL
@@ -10760,7 +10774,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if ((op == HOST_SEM_OP_RELEASE ||
op == HOST_SEM_OP_REDUCTION) && payload &&
- va >= SEMA_VA_LO && va < SEMA_VA_HI) {
+ (va >= SEMA_VA_LO || va >= SVC_LOW_REL_VA_LO) &&
+ va < SEMA_VA_HI) {
if (page_pa)
svc_mark_hot(page_pa);
svc.pushes_seen++;
@@ -10953,7 +10968,9 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
break;
va = ((u64)st.rs_upper << 32) |
st.rs_lower;
- if (va < SEMA_VA_LO || va >= SEMA_VA_HI)
+ if ((va < SEMA_VA_LO &&
+ va < SVC_LOW_REL_VA_LO) ||
+ va >= SEMA_VA_HI)
break;
if (page_pa)
svc_mark_hot(page_pa);