diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 87 |
1 files changed, 49 insertions, 38 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 9d116ad..a04a3c2 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -2667,45 +2667,28 @@ static void svc_apply_pending(struct nv_vgpu_device *vgpu) static u32 svc_apply_page_data(struct nv_vgpu_device *vgpu, const u8 *buf, u64 pa_page) { - u32 off, applied = 0; - bool any = false; - unsigned long flags; - int ci; - /* - * No live channel: no client can be waiting on a release, so a - * "release" decoded from an arbitrary swept page can only be a false - * positive, and its write lands through whatever translation the VA - * happens to have (observed: 2 applied writes while the guest kernel - * was booting corrupted a task's CPU field and panicked the guest - * scheduler). Only apply swept-page releases while a client exists; - * real releases are carried by the channels' readable pushes then. + * DISABLED: releases decoded from swept pages are false positives that + * write through whatever translation the VA happens to have and corrupt + * live guest memory. Two confirmed incidents: during guest boot (a + * task's CPU field, guest scheduler panic) and while channels were + * valid (PAGE_FLAGS_CHECK_AT_FREE / bad rss-counter, counter-page + * slots polluted with payloads like 0x10000). Real releases are + * applied only from pushes the pump reads through a channel's GPFIFO + * translation, with svc_fake_release / svc_counter_release_apply as + * the channel-anchored fallbacks. This function stays as the single + * place that would re-enable page-content heuristics. */ - spin_lock_irqsave(&svc.chan_lock, flags); - for (ci = 0; ci < SVC_MAX_CHANNELS; ci++) { - if (svc.chan[ci].valid) { - any = true; - break; - } - } - spin_unlock_irqrestore(&svc.chan_lock, flags); - if (!any) - return 0; + (void)vgpu; + (void)buf; + (void)pa_page; + return 0; +} - /* - * Decoded execution: walk the page as a method stream and perform the - * pushed work (PTE memsets, semaphore releases) for pushes that are - * still pending. - * - * This page was reached by sweeping raw guest RAM, so the data is - * arbitrary: only the bounded semaphore-release writes below may be - * attempted. Executing fills/copies decoded from a swept page is what - * made the sweep corrupt live guest kernel memory (65M pages scanned, - * fabricated "pushes" executing memsets); work execution is limited - * to pushes the pump read through a trusted ring translation. - */ - svc_decode_stream(vgpu, buf, SEMA_PAGE_SIZE, pa_page, false, 0, 0, 0, - false); +static u32 __maybe_unused __svc_apply_page_data_disabled(struct nv_vgpu_device *vgpu, + const u8 *buf, u64 pa_page) +{ + u32 off, applied = 0; for (off = 0; off + 16 <= SEMA_PAGE_SIZE; off += 4) { u32 hdr, hi, lo, payload; @@ -4682,6 +4665,8 @@ static int svc_thread(void *arg) pr_info("sema-svc: thread started\n"); while (!kthread_should_stop() && !svc.stop) { + bool pumped = false; + vgpu = NULL; mutex_lock(&nv_vgpu_driver.lock); { @@ -4718,8 +4703,13 @@ static int svc_thread(void *arg) * time it takes the fallback scan to find the push. A doorbell * token means a channel was just scheduled; run everything now. */ - svc.doorbell_pending = false; - svc_pump_channels(vgpu); + { + u64 done_before = svc.gpfifo_entries_done; + + svc.doorbell_pending = false; + svc_pump_channels(vgpu); + pumped = (svc.gpfifo_entries_done != done_before); + } /* * Releases whose target VA was not translatable when the scan @@ -4737,6 +4727,18 @@ static int svc_thread(void *arg) svc_apply_sweep_slice(vgpu); /* + * While the pump is making progress the client is streaming + * pushes and waiting on their releases: loop tightly and skip + * the discovery/sweep passes, which otherwise dominate the pass + * period (the pump cadence is what the client's context init + * deadline sees). Scans resume the first pass without progress. + */ + if (pumped) { + msleep(1); + continue; + } + + /* * Push-buffer base discovery: a chunked walk of guest RAM * finds the pages whose first push names a channel, so a * channel that appears with work already waiting is pinned and @@ -4798,6 +4800,15 @@ void gsp_sema_service_doorbell(u32 token) svc.doorbell_count++; svc.doorbell_pending = true; + /* + * Wake the service thread: a doorbell means a channel just became + * runnable, and the loop's rolling scans can otherwise delay the pump + * by the whole pass period. This is called from the VFIO write path + * (atomic context), where wake_up_process is allowed. + */ + if (svc.task) + wake_up_process(svc.task); + if (svc.doorbell_log < 64) { pr_info("sema-svc: doorbell token=0x%x runlist=%u vector=%u (count=%llu)\n", token, (token >> 16) & 0x7f, token & 0xfff, |
