summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c109
1 files changed, 98 insertions, 11 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 8756d83..c8e224b 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -25725,14 +25725,41 @@ gsp_phys_gr_m91_fault_cap(const struct gsp_phys_gr_submit *req,
* (gsp_sema_gr_reloc_resolve: pins/map/walks before the ledger, the
* guest-walk-first counterpart of the fill's ledger-first order). Only a
* different, plausibly-code page is adopted (mode ALT; the engine-visible
- * copy is taken from it); anything else leaves the QMD pair at the guest
- * VA (mode GUEST_VA, the ptr_guest behaviour for this pair). One
- * rate-limited CODESRC-SUSPECT line per detection.
+ * copy is taken from it).
+ *
+ * r1625 (the c361-c368 wedge): mode GUEST_VA used to leave the QMD pair at
+ * the guest VA, which is above every engine-PDB window - the GPCCLIENT_GCC
+ * I-fetch then raised FAULT_PDE and parked the FIFO permanently (the
+ * WEDGE-REARM TSG probe cannot revive a dead PBDMA). With
+ * gsp_phys_gr_codesrc_reloc (default 1) the refused page is instead
+ * relocated to the engine-mapped window-0 shadow and the QMD pair is
+ * rewritten there. The source page is copied when it is only empty (so any
+ * content elsewhere in the page is preserved and inline records still land
+ * on top); PTE/module pages are never republished. The program entry
+ * (original QMD offset preserved) is then overwritten with the client's own
+ * known-good SPH+SASS image for the bound stage (gsp_sema_gl_prog_img) -
+ * a raw EXIT stub would fail the engine's SPH validation - truncated at a
+ * 128-bit instruction boundary with a terminal EXIT appended. If the shadow
+ * mapping cannot be installed the launch is refused (the existing unmapped-
+ * page path), so a QMD whose program pointer is not engine-mapped is never
+ * published. One rate-limited CODESRC-SUSPECT line per detection, plus a
+ * CODESRC-RELOC line for each relocation.
*/
#define GSP_PHYS_GR_CODESRC_OK 0
#define GSP_PHYS_GR_CODESRC_ALT 1
#define GSP_PHYS_GR_CODESRC_GUEST_VA 2
+/*
+ * r1625: terminal 16 B sm_75 SASS (MOV R1, c[0x0][0x0]; EXIT), taken from
+ * the first two instructions of a compiled sm_75 kernel's .text. Appended
+ * after a truncated relocation image so control can never run into the
+ * zero-filled tail of the shadow page.
+ */
+static const u8 gsp_phys_gr_codesrc_exit[16] = {
+ 0x02, 0x7a, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+};
+
static bool
gsp_phys_gr_codesrc_chunk_has(const struct gsp_phys_boot_chunk *c, u64 hpa)
{
@@ -25816,7 +25843,8 @@ static bool gsp_phys_gr_codesrc_empty(const u8 *p, u32 off)
static noinline int
gsp_phys_gr_code_src(const struct gsp_phys_gr_submit *req,
- const struct gsp_phys_gr_page *pg, u64 *alt_hpa)
+ const struct gsp_phys_gr_page *pg, u64 *alt_hpa,
+ const char **why_out, bool *unsafe_out)
{
u64 page = pg->guest_va & ~(u64)(GSP_PHYS_PAGE_SIZE - 1);
u32 off = (u32)(req->qmd[48] & (GSP_PHYS_PAGE_SIZE - 1));
@@ -25826,6 +25854,10 @@ gsp_phys_gr_code_src(const struct gsp_phys_gr_submit *req,
int mode = GSP_PHYS_GR_CODESRC_GUEST_VA;
*alt_hpa = 0;
+ if (why_out)
+ *why_out = NULL;
+ if (unsafe_out)
+ *unsafe_out = false;
if (off > GSP_PHYS_PAGE_SIZE - 16u)
off = GSP_PHYS_PAGE_SIZE - 16u; /* keep 16 B in-page */
if (gsp_phys_gr_codesrc_empty(p, off))
@@ -25836,6 +25868,14 @@ gsp_phys_gr_code_src(const struct gsp_phys_gr_submit *req,
why = "module-pt-page";
if (!why)
return GSP_PHYS_GR_CODESRC_OK;
+ if (why_out)
+ *why_out = why;
+ /* The page content must not be republished as code: PTE/filler
+ * bytes would execute as SASS. Empty is safe to copy (all zero)
+ * but is republished with a known-good image at the entry. */
+ if (unsafe_out && why &&
+ (!strcmp(why, "pte-page") || !strcmp(why, "module-pt-page")))
+ *unsafe_out = true;
/*
* Alternative resolution order; only a different page that itself
* passes the content checks is adopted.
@@ -29208,16 +29248,63 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
* CODESRC: the program page (qmd_word 48) is the page
* the engine's I-fetch reads; screen its source
* before publishing it. A refused source is either
- * replaced by the alternative resolver's page or the
- * pair is left at the guest VA (no copy, no rewrite,
- * no mapping - the page is fully withdrawn from the
- * submission).
+ * replaced by the alternative resolver's page or
+ * (r1625) relocated to this shadow with the client's
+ * known-good stage image at the entry, so the QMD
+ * pair is rewritten to an engine-mapped VA. Leaving
+ * it at the guest VA makes the I-fetch fault (PDE)
+ * and parks the FIFO; that legacy withdrawal is now
+ * gated behind gsp_phys_gr_codesrc_reloc=0.
*/
if (pg->hpa && pg->qmd_word == 48u) {
u64 alt_hpa = 0;
- int cs = gsp_phys_gr_code_src(req, pg, &alt_hpa);
-
- if (cs == GSP_PHYS_GR_CODESRC_GUEST_VA) {
+ const char *why = NULL;
+ bool unsafe = false;
+ int cs = gsp_phys_gr_code_src(req, pg,
+ &alt_hpa, &why,
+ &unsafe);
+
+ if (cs == GSP_PHYS_GR_CODESRC_GUEST_VA &&
+ gsp_phys_gr_codesrc_reloc_value()) {
+ u32 po = qmd[48] &
+ (GSP_PHYS_PAGE_SIZE - 1);
+ const u8 *img = NULL;
+ u32 imlen = 0, cp = 0, fit;
+
+ if (po > GSP_PHYS_PAGE_SIZE - 16u)
+ po = GSP_PHYS_PAGE_SIZE - 16u;
+ if (!unsafe)
+ memcpy(sh_page,
+ (u8 *)__va(pg->hpa),
+ GSP_PHYS_PAGE_SIZE);
+ img = gsp_sema_gl_prog_img(
+ pg->guest_va, &imlen);
+ fit = GSP_PHYS_PAGE_SIZE - po;
+ if (imlen > fit)
+ fit = fit >
+ sizeof(gsp_phys_gr_codesrc_exit) ?
+ fit -
+ sizeof(gsp_phys_gr_codesrc_exit) :
+ 0u;
+ if (img && imlen) {
+ cp = imlen < fit ? imlen : fit;
+ memcpy(sh_page + po, img, cp);
+ }
+ if (cp < imlen || !img || !imlen)
+ memcpy(sh_page + po + cp,
+ gsp_phys_gr_codesrc_exit,
+ sizeof(gsp_phys_gr_codesrc_exit));
+ copied++;
+ pr_info_ratelimited("vgsp-gr: CODESRC-RELOC va=0x%llx pa=0x%llx why=%s src=%s img_len=%u cp=%u off=0x%x trunc=%u h=0x%x push=0x%llx (engine copy + QMD pair rewrite)\n",
+ pg->guest_va & ~(u64)(GSP_PHYS_PAGE_SIZE - 1),
+ pg->hpa, why ? why : "none",
+ unsafe ? "stub-only" :
+ img ? "image" : "exit",
+ imlen, cp, po,
+ cp < imlen ? 1u : 0u,
+ req->h_object,
+ req->push_va);
+ } else if (cs == GSP_PHYS_GR_CODESRC_GUEST_VA) {
code_keep_guest = true;
mapped = true;
} else {