summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 20:01:53 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 20:01:53 -0400
commitccdc1240d5df9777503a05b247109b6136d03313 (patch)
tree74f1ea2bede53a4d7c863ede4f861bc611a038ba /kernel/gsp_rm_emulation.c
parent1c596b4b30e7ecc2f525ae47b52a73b8d4de816d (diff)
downloadopen-iov-ccdc1240d5df9777503a05b247109b6136d03313.tar.gz
open-iov-ccdc1240d5df9777503a05b247109b6136d03313.zip
vgsp-sema r577: never let a foreign release VA claim a CE channel's tracking slot; event-record A/B knobs; GR-DEC dump deepened
r575 starved-release wedge (live): an unreadable UVM CE entry's rescued stale page decoded a release to a foreign VA (0x12006c004, pay=60); the rescue paths adopted it as the channel's tracking slot (last_rel_va) and every later recovery release targeted it, while the client's real pool (0x121000000) stopped at 25 - the client spun in uvm_tracker_wait for 34 (exact-slot poke delivered it and the client completed green). For CE channels only a pool-shaped release target (0x121000000..0x122000000) may become last_rel_va; a foreign rescued release is refused (witnessed, bounded) and the pool step is delivered through the exact-slot fallback / deferred-release machinery instead. The fake's read-before-write keeps the delivery monotonic even when a legit push carries multiple releases. Also: gsp_rm_ev_{seq,nlist,cl} runtime knobs for the guest-RM event drop A/B (the r576 experiment: guest consumes every POST_EVENT record and never enters nv_post_event), and the GR-DEC launch dump now covers 256 data pages (the mail VADD fill carries n_data=969). New: tools/cuda-ab/evhold.cu - deterministic CUDA event holder/wait probe (context + cudaEventSynchronize + a hold window) for the event experiments.
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
-rw-r--r--kernel/gsp_rm_emulation.c80
1 files changed, 53 insertions, 27 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index d381c65..f44c01b 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -754,6 +754,46 @@ static void gsp_rm_evlog_post(struct nv_vgpu_device *vgpu,
}
/*
+ * r577 experiment knobs (runtime-writable; default 0 = legacy behaviour).
+ * The r576 live experiment showed the guest consumes our POST_EVENT records
+ * (rmstate cursors match) yet never enters nv_post_event (clean single-probe
+ * window, forced rmpost rounds -> entries-written 0): the guest RM drops
+ * them somewhere between the status-queue read and osNotifyEvent. These
+ * knobs let one boot A/B the record contents without rebuilding:
+ * gsp_rm_ev_seq - when nonzero, event records carry the status-queue
+ * sequence as the RPC-level sequence (legacy: 0)
+ * gsp_rm_ev_nlist - when nonzero, bNotifyList (payload byte 28) is set,
+ * selecting the driver's notifier-list dispatch path
+ * gsp_rm_ev_cl - when nonzero, overrides the payload hClient (e.g. to
+ * the kernel RM client) for the CliGetEventInfo lookup
+ */
+unsigned gsp_rm_ev_seq;
+unsigned gsp_rm_ev_nlist;
+unsigned gsp_rm_ev_cl;
+
+static void gsp_rm_fill_ev_payload(const struct gsp_rm_emu *rm, u32 i,
+ u8 *payload)
+{
+ u32 h_client = rm->events[i].h_client;
+
+ memset(payload, 0, 32);
+ if (gsp_rm_ev_cl)
+ h_client = gsp_rm_ev_cl;
+ memcpy(payload + 0, &h_client, 4);
+ memcpy(payload + 4, &rm->events[i].h_event, 4);
+ memcpy(payload + 8, &rm->events[i].notify_index, 4);
+ memcpy(payload + 12, &rm->events[i].data, 4);
+ /* info16@16, status@20, eventDataSize@24 = 0 */
+ if (gsp_rm_ev_nlist)
+ payload[28] = 1; /* bNotifyList */
+}
+
+static u32 gsp_rm_ev_sequence(const struct gsp_rm_emu *rm)
+{
+ return gsp_rm_ev_seq ? rm->stat_seq : 0;
+}
+
+/*
* Post the GPU event that tells the guest's CPU-side RM a channel's
* submitted work is complete. A real GPU raises an interrupt, the host GSP
* turns it into an NV_VGPU_MSG_EVENT_POST_EVENT record for the client's
@@ -785,17 +825,13 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
if (!rm->events[i].valid || rm->events[i].h_src != h_src)
continue;
- memset(payload, 0, sizeof(payload));
- memcpy(payload + 0, &rm->events[i].h_client, 4);
- memcpy(payload + 4, &rm->events[i].h_event, 4);
- memcpy(payload + 8, &rm->events[i].notify_index, 4);
- memcpy(payload + 12, &rm->events[i].data, 4);
- /* info16@16, status@20, eventDataSize@24, bNotifyList@28 = 0 */
+ gsp_rm_fill_ev_payload(rm, i, payload);
{
int rc = gsp_rm_send_flags(ctx,
GSPRM_RPC_EVENT_POST_EVENT,
- 0, 0, payload,
- sizeof(payload), true);
+ gsp_rm_ev_sequence(rm), 0,
+ payload, sizeof(payload),
+ true);
gsp_rm_evlog_post(vgpu, rm, i, "chan", rc);
if (rc)
@@ -815,15 +851,12 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
for (i = 0; i < rm->events_n; i++) {
if (!rm->events[i].valid)
continue;
- memset(payload, 0, sizeof(payload));
- memcpy(payload + 0, &rm->events[i].h_client, 4);
- memcpy(payload + 4, &rm->events[i].h_event, 4);
- memcpy(payload + 8, &rm->events[i].notify_index, 4);
- memcpy(payload + 12, &rm->events[i].data, 4);
+ gsp_rm_fill_ev_payload(rm, i, payload);
{
int rc = gsp_rm_send_flags(ctx,
GSPRM_RPC_EVENT_POST_EVENT,
- 0, 0, payload,
+ gsp_rm_ev_sequence(rm),
+ 0, payload,
sizeof(payload),
true);
@@ -861,14 +894,10 @@ static int gsp_rm_post_event_idx(struct gsp_emu_context *ctx, u32 idx)
if (idx >= rm->events_n || !rm->events[idx].valid)
return -EINVAL;
- memset(payload, 0, sizeof(payload));
- memcpy(payload + 0, &rm->events[idx].h_client, 4);
- memcpy(payload + 4, &rm->events[idx].h_event, 4);
- memcpy(payload + 8, &rm->events[idx].notify_index, 4);
- memcpy(payload + 12, &rm->events[idx].data, 4);
+ gsp_rm_fill_ev_payload(rm, idx, payload);
- rc = gsp_rm_send(ctx, GSPRM_RPC_EVENT_POST_EVENT, 0, 0,
- payload, sizeof(payload));
+ rc = gsp_rm_send(ctx, GSPRM_RPC_EVENT_POST_EVENT,
+ gsp_rm_ev_sequence(rm), 0, payload, sizeof(payload));
if (!rc)
rm->events[idx].last_post = jiffies;
return rc;
@@ -946,14 +975,11 @@ int gsp_rm_post_all_events(struct nv_vgpu_device *vgpu)
continue;
}
- memset(payload, 0, sizeof(payload));
- memcpy(payload + 0, &rm->events[i].h_client, 4);
- memcpy(payload + 4, &rm->events[i].h_event, 4);
- memcpy(payload + 8, &rm->events[i].notify_index, 4);
- memcpy(payload + 12, &rm->events[i].data, 4);
+ gsp_rm_fill_ev_payload(rm, i, payload);
{
int rc = gsp_rm_send(ctx, GSPRM_RPC_EVENT_POST_EVENT,
- 0, 0, payload, sizeof(payload));
+ gsp_rm_ev_sequence(rm), 0,
+ payload, sizeof(payload));
gsp_rm_evlog_post(vgpu, rm, i, "all", rc);
if (rc)