summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c99
-rw-r--r--kernel/gsp_rm_emulation.c36
-rw-r--r--kernel/gsp_rm_emulation.h4
3 files changed, 139 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 4125192..b2375a2 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -25303,6 +25303,91 @@ static const struct file_operations gsp_phys_guest_gpa_fops = {
};
/*
+ * gsp-phys-shared-bit0 (write-only, mode 0200): development-harness assist
+ * for the NVIDIA X driver's per-client shared-data slot.
+ *
+ * Every direct GLX client receives a shared memory page from the X driver
+ * (nvidia_drv.so creates a memfd and passes it over a unix socket) whose
+ * first words are {u32 zero, u32 cookie, u32 state, u32 zero, u32 hClient,
+ * u32 hObject}; glcore's device init reads the state word and skips its own
+ * class-c46f channel creation while bit 0 of it is set. In this emulated
+ * environment the X driver publishes state=3 (bits 0+1) and direct clients
+ * therefore never allocate a channel and never render. The value is written
+ * by the X driver before the fd reaches the client, so it cannot be
+ * corrected from the client side.
+ *
+ * Input: "0x<hex GPA>" (4 KB aligned) naming the guest page that carries the
+ * slot. The GPA must fall inside a range registered through
+ * gsp-phys-guest-ram; it is translated with gsp_phys_gpa_to_hpa_vgpu()
+ * (first open mdev) and the state word is cleared of bit 0 through the
+ * kernel direct map (the translator validates pfn_valid, so __va() is a
+ * valid kernel mapping for the shmem-backed guest RAM). As a sanity guard
+ * the write is only performed when the page's +0x10 word looks like an RM
+ * client handle (0xc1d0xxxx / 0xc1e0xxxx) or the token carries a "force"
+ * suffix. Old and new values are always logged.
+ *
+ * This is a diagnostic aid for the development VM, matching the spirit of
+ * the existing guest-GPA pin; it is not part of the product behaviour.
+ */
+static ssize_t gsp_phys_shared_bit0_write(struct file *file,
+ const char __user *ubuf, size_t len,
+ loff_t *ppos)
+{
+ char buf[48];
+ u64 gpa, hpa = 0;
+ u32 *word;
+ u32 h1032;
+ bool force = false;
+ int ret;
+
+ if (len == 0 || len >= sizeof(buf))
+ return -EINVAL;
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ {
+ char *p = strim(buf);
+ char *tok = strsep(&p, " \t");
+
+ if (p && strstr(p, "force"))
+ force = true;
+ if (kstrtoull(tok, 0, &gpa) || !PAGE_ALIGNED(gpa)) {
+ pr_info("vgsp-boot: gsp-phys-shared-bit0: write ignored: expected \"0x<hex GPA>\" (4 KB aligned, optional 'force')\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = gsp_phys_gpa_to_hpa_vgpu(NULL, gpa, &hpa);
+ if (ret) {
+ pr_err("vgsp-boot: gsp-phys-shared-bit0: GPA 0x%llx translation failed (%d: no open mdev / GPA not inside a gsp-phys-guest-ram range / not RAM)\n",
+ gpa, ret);
+ return -ENOENT;
+ }
+
+ word = (u32 *)__va(hpa + 8);
+ h1032 = *(u32 *)__va(hpa + 0x10);
+ if (!force && (h1032 >> 16) != 0xc1d0 && (h1032 >> 16) != 0xc1e0) {
+ pr_info("vgsp-boot: gsp-phys-shared-bit0: gpa=0x%llx word=0x%x but +0x10=0x%x does not look like an RM client handle; refusing (append 'force' to override)\n",
+ gpa, *word, h1032);
+ return -EINVAL;
+ }
+
+ pr_info("vgsp-boot: gsp-phys-shared-bit0: gpa=0x%llx hpa=0x%llx hClient=0x%x word=0x%x -> 0x%x\n",
+ gpa, hpa, h1032, *word, *word & ~1u);
+ *word &= ~1u;
+ return len;
+}
+
+static const struct file_operations gsp_phys_shared_bit0_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = gsp_phys_shared_bit0_write,
+ .llseek = no_llseek,
+};
+
+
+/*
* gsp-phys-guest-ram (write-only, mode 0200): configure a guest RAM backing
* file that gsp_phys_gpa_to_hpa_vgpu() translates through (QEMU
* memory-backend-file,...,share=yes). One write is
@@ -25787,6 +25872,20 @@ int gsp_phys_boot_debugfs_init(void)
err);
return (int)err;
}
+ file = debugfs_create_file("gsp-phys-shared-bit0", 0200,
+ gsp_phys_debugfs_root, NULL,
+ &gsp_phys_shared_bit0_fops);
+ if (IS_ERR_OR_NULL(file)) {
+ long err = IS_ERR(file) ? PTR_ERR(file) : -ENODEV;
+
+ /*
+ * The shared-slot bit0 assist is optional; the other
+ * triggers and the state snapshot stay registered.
+ */
+ pr_warn("vgsp-boot: debugfs file gsp-phys-shared-bit0 creation failed: %ld (other triggers and state snapshot stay available)\n",
+ err);
+ return (int)err;
+ }
file = debugfs_create_file("gsp-phys-guest-ram", 0200,
gsp_phys_debugfs_root, NULL,
&gsp_phys_guest_ram_fops);
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 653ff1d..2f63bcd 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -4412,6 +4412,42 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
break;
}
+ case 0x20800afe: { /* NV2080_CTRL_CMD_INTERNAL_INIT_USER_SHARED_DATA
+ *
+ * The guest kernel driver hands the GSP-RM the physical
+ * address of the RUSD (RM user shared data) page it
+ * allocated; on real hardware the GSP registers the
+ * memdesc and keeps the page's sequence-guarded fields
+ * (clocks, BAR1, utilisation, ...) populated, and 0
+ * de-initialises it. Nothing here performs that upkeep,
+ * and consumers treat a zeroed sequence word as "data
+ * invalid" and skip the fields, so the correct emulated
+ * behaviour is to acknowledge the registration, echo the
+ * request (the caller may read the address back) and log
+ * the address once so the page can be correlated with
+ * guest RAM during diagnosis. */
+ u8 *rp = reply + GSP_RM_CTRL_HDR_SIZE;
+ const u8 *pp = req_data + GSP_RM_CTRL_HDR_SIZE;
+
+ if (req.paramsSize >= 8) {
+ u64 phys_addr;
+
+ memcpy(&phys_addr, pp, 8);
+ memcpy(rp, pp, req.paramsSize);
+ rm->rusd_phys_addr = phys_addr;
+ rm->rusd_init_seen = true;
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: INIT_USER_SHARED_DATA physAddr=0x%llx (RUSD registered; fields left at sequence 0 = 'data invalid', consumers skip)",
+ phys_addr);
+ out_status = 0;
+ out_params_size = req.paramsSize;
+ } else {
+ out_status = 0;
+ out_params_size = 0;
+ }
+ break;
+ }
+
case 0x2080a097: { /* client-pending engine-context query (session 75)
*
* libnvidia-eglcore issues this via NVOS54 and then
diff --git a/kernel/gsp_rm_emulation.h b/kernel/gsp_rm_emulation.h
index a4b1afd..c0eecf8 100644
--- a/kernel/gsp_rm_emulation.h
+++ b/kernel/gsp_rm_emulation.h
@@ -184,6 +184,10 @@ struct gsp_rm_emu {
u64 ctrl_fwd_fallback; /* forward attempt used emulation */
u64 ctrl_fwd_timeout; /* fallbacks caused by a backend timeout */
+ /* NV2080_CTRL_CMD_INTERNAL_INIT_USER_SHARED_DATA bookkeeping */
+ u64 rusd_phys_addr; /* last registered RUSD phys address */
+ bool rusd_init_seen; /* a registration was acknowledged */
+
/*
* NV01_EVENT objects (class 0x5, allocated via class 0x79 in the
* guest ABI). Each carries {hSrcResource, notifyIndex, data}; the