summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index fa0fe65..ac1849f 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3872,6 +3872,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
bool unreadable =
svc_read_va_trusted(vgpu, va,
pb, len) != 0;
+ bool injected = false;
+ bool allow_ops = (ch->engine_type != 0);
/*
* A resolved buffer that does not start
@@ -3879,12 +3881,28 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
* (content-scanned map; observed firmware
* and kernel data pages). Handle it like
* an unreadable push so the content rescue
- * can find the real page.
+ * can find the real page. Exception: a
+ * host-injected translation is verified
+ * truth, and real CE release pushes start
+ * with an INC_METHOD whose address is not
+ * zero (observed 0x200381c0, addr 0x700):
+ * decode those release-only instead of
+ * discarding them, so the client's
+ * tracking-semaphore releases still apply.
*/
- if (!unreadable &&
- !svc_method_stream_plausible(pb, len)) {
- svc.false_trans++;
- unreadable = true;
+ if (!unreadable) {
+ u64 ipa;
+ int iap;
+
+ injected = (svc_ipin_lookup(va, &ipa,
+ &iap) == 0);
+ if (!svc_method_stream_plausible(pb, len)) {
+ svc.false_trans++;
+ if (injected)
+ allow_ops = false;
+ else
+ unreadable = true;
+ }
}
if (!unreadable) {
@@ -3902,7 +3920,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc_decode_stream(vgpu, pb,
len, 0,
- ch->engine_type != 0,
+ allow_ops,
ch->h_object,
ch->engine_type,
va);