summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c106
-rw-r--r--kernel/gsp_phys_booter.h9
2 files changed, 103 insertions, 12 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 989c91f..60b57f2 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -1873,6 +1873,7 @@ static struct gsp_phys_boot_stage {
bool rmcall_gr_exec_ok; /* a real GR submission proved out */
u32 rmcall_gr_submit_epoch; /* per-submission mapper epoch */
u32 rmcall_gr_pt_used; /* Tier-1 window pool slots used */
+ u32 rmcall_guest_pt_win_mask; /* Tier-2 scratch windows installed */
struct gsp_phys_boot_chunk rmcall_gr_pt[GSP_PHYS_RMCALL_GR_PT_PAGES];
struct gsp_phys_boot_chunk rmcall_gr_shadow; /* Tier-2 pages */
struct {
@@ -2501,6 +2502,7 @@ static void gsp_phys_rmcall_reset(void)
boot_stage.rmcall_gr_exec_ok = false;
boot_stage.rmcall_gr_submit_epoch = 0;
boot_stage.rmcall_gr_pt_used = 0;
+ boot_stage.rmcall_guest_pt_win_mask = 0;
memset(boot_stage.rmcall_gr_pt, 0, sizeof(boot_stage.rmcall_gr_pt));
memset(&boot_stage.rmcall_gr_shadow, 0,
sizeof(boot_stage.rmcall_gr_shadow));
@@ -13693,6 +13695,68 @@ static int gsp_phys_rmcall_gr_map_va_locked(void __iomem *bar0, u64 guest_va,
return 0;
}
+static void __iomem *gsp_phys_gr_scratch_bar0;
+
+/*
+ * Tier-2 spine: install the guest scratch PT pool's 2 MiB VA window through
+ * the server walker (DMA_UPDATE_PDE_2) the first time a shadow line in that
+ * pool page is consumed. On the shared-management VAS the client PD0 entries
+ * built by pdb_build are not preserved by the server's root migration, so
+ * without this install the shadow VAs (rmcall_va_guest_pt + page<<21 + ...)
+ * have no PTE chain in the engine's table view and every Tier-2 leg (param,
+ * program, release, pointer/indirect pages the QMD was rewritten to) is
+ * unreachable: the QMD can never execute even though the ring entry is
+ * fetched. The control shape matches the Tier-1 installer; the PT page is the
+ * pool chunk itself, whose PTEs gr_map_shadow(_contig)_locked writes. On an
+ * externally-owned VAS the client PDB spine is preserved, so the install is
+ * skipped there. Called with gsp_phys_rm_lock held.
+ */
+static int gsp_phys_rmcall_gr_scratch_win_install_locked(u32 page)
+{
+ struct gsp_phys_rmcall_update_pde2_params p;
+ struct gsp_phys_boot_chunk *pt;
+ u32 rpc_result = 0, status = 0, pde_index;
+ int ret;
+
+ if (page >= GSP_PHYS_RMCALL_GUEST_PT_PAGES)
+ return -EINVAL;
+ if (!gsp_phys_rmcall_vas_shared_value())
+ return 0;
+ if (boot_stage.rmcall_guest_pt_win_mask & BIT(page))
+ return 0;
+ pt = &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GUEST_PT0 + page];
+ if (!pt->pages)
+ return -EIO;
+ if (!boot_stage.rmcall_va_guest_pt)
+ return -EIO;
+ pde_index = (u32)((boot_stage.rmcall_va_guest_pt >> 21) + page);
+ memset(&p, 0, sizeof(p));
+ p.pde_index = cpu_to_le32(pde_index);
+ p.flags = cpu_to_le32(GSP_PHYS_RMCALL_PDE2_FLAG_FLUSH);
+ p.pt[0].phys_addr = cpu_to_le64((u64)gsp_phys_chunk_page_dma(pt, 0));
+ p.pt[0].aperture = cpu_to_le32(GSP_PHYS_RMCALL_PDE2_APERTURE_SYS_COH);
+ p.pt[1].aperture = cpu_to_le32(GSP_PHYS_RMCALL_PDE2_APERTURE_INVALID);
+ p.h_va_space = cpu_to_le32(boot_stage.rmcall_vas);
+ p.pde_buffer = 0;
+ p.sub_device_id = 0;
+ ret = gsp_phys_rmcall_control(gsp_phys_gr_scratch_bar0,
+ boot_stage.rmcall_device,
+ GSP_PHYS_RMCALL_CTRL_DMA_UPDATE_PDE_2,
+ &p, sizeof(p), sizeof(p), &p, sizeof(p),
+ &rpc_result, &status, "GR forward scratch PDE_UPDATE");
+ if (ret) {
+ pr_err("vgsp-gr: scratch PDE install refused pdeIndex=%u (VA 0x%llx) status=0x%x rpc_result=0x%x ret=%d; Tier-2 shadow legs stay unreachable in the engine's table view\n",
+ pde_index, (u64)pde_index << 21, status, rpc_result,
+ ret);
+ return ret;
+ }
+ boot_stage.rmcall_guest_pt_win_mask |= BIT(page);
+ pr_info("vgsp-gr: scratch window installed pdeIndex=%u (VA 0x%llx) ptPa=0x%llx status=0x%x (Tier-2 shadow legs now reachable through the server walker)\n",
+ pde_index, (u64)pde_index << 21,
+ (u64)gsp_phys_chunk_page_dma(pt, 0), status);
+ return 0;
+}
+
/*
* Tier-2 map: consume one never-reused 128 B fetch line from the guest
* scratch PT pool (PTE0 only) for a ladder-owned shadow page and return the
@@ -13726,6 +13790,9 @@ static int gsp_phys_rmcall_gr_map_shadow_locked(u32 slot, u64 hpa,
return -ENOSPC;
page = line / GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE;
line_in_page = line % GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE;
+ ret = gsp_phys_rmcall_gr_scratch_win_install_locked(page);
+ if (ret)
+ return ret;
pt = &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GUEST_PT0 + page];
if (!pt->pages)
return -EIO;
@@ -13756,6 +13823,7 @@ static int gsp_phys_rmcall_gr_map_shadow_contig_locked(u32 line, u32 pte,
struct gsp_phys_boot_chunk *pt;
u32 page, line_in_page;
u8 *pt_va;
+ int ret;
if (pte >= GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES)
return -EINVAL;
@@ -13764,6 +13832,9 @@ static int gsp_phys_rmcall_gr_map_shadow_contig_locked(u32 line, u32 pte,
return -ENOSPC;
page = line / GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE;
line_in_page = line % GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE;
+ ret = gsp_phys_rmcall_gr_scratch_win_install_locked(page);
+ if (ret)
+ return ret;
pt = &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GUEST_PT0 + page];
if (!pt->pages)
return -EIO;
@@ -13851,6 +13922,7 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
ret = -EAGAIN;
goto out;
}
+ gsp_phys_gr_scratch_bar0 = bar0;
sem_va = gsp_phys_chunk_page_va(sem, 0);
if (!sem_va || !gsp_phys_chunk_page_va(pb, 0)) {
gsp_phys_gr_refused++;
@@ -14223,9 +14295,11 @@ gr_page_unmapped:
*/
if (qmd_dst_mem) {
memcpy(qmd_dst_mem, qmd, GSP_PHYS_GR_QMD_WORDS * 4);
+ put_unaligned_le32(GSP_PHYS_GR_QMD_SENTINEL, qmd_dst_mem);
wmb();
- pr_info("vgsp-gr: QMD prewritten to dest 0x%llx (%u words)\n",
- qmd_dst, GSP_PHYS_GR_QMD_WORDS);
+ pr_info("vgsp-gr: QMD prewritten to dest 0x%llx (%u words, w0 sentinel=0x%08x)\n",
+ qmd_dst, GSP_PHYS_GR_QMD_WORDS,
+ GSP_PHYS_GR_QMD_SENTINEL);
}
words = gsp_phys_rmcall_build_gr_launch(methods, req, qmd,
@@ -14309,22 +14383,30 @@ gr_page_unmapped:
u32 q0 = 0, q1 = 0, q23 = 0, q24 = 0, q25 = 0;
u32 relw = 0;
- if (req->qmd_hpa) {
- u8 *qp = (u8 *)__va(req->qmd_hpa);
-
- q0 = get_unaligned_le32(qp);
- q1 = get_unaligned_le32(qp + 4);
- q23 = get_unaligned_le32(qp + 92);
- q24 = get_unaligned_le32(qp + 96);
- q25 = get_unaligned_le32(qp + 100);
+ {
+ u8 *qp = qmd_dst_mem ? qmd_dst_mem :
+ (req->qmd_hpa ?
+ (u8 *)__va(req->qmd_hpa) :
+ NULL);
+
+ if (qp) {
+ q0 = get_unaligned_le32(qp);
+ q1 = get_unaligned_le32(qp + 4);
+ q23 = get_unaligned_le32(qp + 92);
+ q24 = get_unaligned_le32(qp + 96);
+ q25 = get_unaligned_le32(qp + 100);
+ }
}
if (qmd_rel_hpa)
relw = READ_ONCE(
*(u32 *)((u8 *)__va(qmd_rel_hpa) +
qmd_rel_off));
- pr_info("vgsp-gr: post-mortem gpget=%u->%u qmd_page w0=%08x w1=%08x w23..25=%08x %08x %08x relw=%08x\n",
+ pr_info("vgsp-gr: post-mortem gpget=%u->%u qmd_page w0=%08x w1=%08x w23..25=%08x %08x %08x relw=%08x iq2m=%s\n",
sub.gpget, gpget_post, q0, q1, q23, q24,
- q25, relw);
+ q25, relw,
+ q0 == GSP_PHYS_GR_QMD_SENTINEL ?
+ "not-run (sentinel intact)" :
+ "ran (page overwritten)");
}
poll = w1;
ret = -ETIMEDOUT;
diff --git a/kernel/gsp_phys_booter.h b/kernel/gsp_phys_booter.h
index 9a0331f..67d5d5c 100644
--- a/kernel/gsp_phys_booter.h
+++ b/kernel/gsp_phys_booter.h
@@ -335,6 +335,15 @@ void gsp_phys_backend_relay_counters(u64 *requested, u64 *ok, u64 *verify_fail,
#define GSP_PHYS_GR_MAX_INLINE 8u
#define GSP_PHYS_GR_INLINE_BYTES 64u
#define GSP_PHYS_GR_QMD_WORDS 64u
+/*
+ * IQ2M sentinel: written to the inline-QMD destination's word 0 after the
+ * prewrite. If the engine processes the inline window, the copy overwrites
+ * the page (word 0 -> the inline value, 0) and the post-mortem sees the page
+ * changed; if the sentinel survives, the engine stalled before the inline
+ * window and the page was never touched. Distinguishes "IQ2M never ran" from
+ * "QMD deposited but not executed" without a server-side capture.
+ */
+#define GSP_PHYS_GR_QMD_SENTINEL 0xdeadbeefu
#define GSP_PHYS_GR_QMD_WORD_NONE 0xffffffffu
#define GSP_PHYS_GR_RAW_WORDS 256u