summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_rm_emulation.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 357997c..fb0f31d 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -788,13 +788,27 @@ 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;
+ /*
+ * r579 THE EVENT-DROP ROOT CAUSE: NV0005_ALLOC_PARAMETERS.notifyIndex
+ * is OVERLOADED (cl0005.h): INDEX=bits[15:0], SUBDEVICE=bits[23:16],
+ * FLAGS=bits[31:24]. The registration word (e.g. 0x3c00000c) must not
+ * be posted verbatim: the guest's _kgspRpcPostEvent hands the payload
+ * notifyIndex straight to gpuNotifySubDeviceEvent_IMPL, which indexes
+ * its notifier array by it - posting 0x3c00000c produced a wild
+ * pointer (base + 0x3c00000c*4 + 0x1508) and a kernel Oops
+ * ("BUG: unable to handle page fault ... gpuNotifySubDeviceEvent_IMPL
+ * +0x21f", RAX=0x3c00000c) on every dispatched event, which is why
+ * nv_post_event never fired and clients waiting on event wakes
+ * wedged. Post the INDEX field only.
+ */
+ u32 notify_index = rm->events[i].notify_index & 0xffffu;
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 + 8, &notify_index, 4);
memcpy(payload + 12, &rm->events[i].data, 4);
/* info16@16, status@20, eventDataSize@24 = 0 */
if (gsp_rm_ev_nlist)