diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 439 |
1 files changed, 395 insertions, 44 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 1a8efd6..5bc387e 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -8375,10 +8375,121 @@ static char *sema_gl_ps_hex; module_param_named(sema_gl_ps_hex, sema_gl_ps_hex, charp, 0644); MODULE_PARM_DESC(sema_gl_ps_hex, "explicit PS program image (SPH+SASS hex, <=256 B) for pixel slots"); +/* + * r1492: deliver the known-good VTG image when the captured upload is + * header-only (page-splice corruption). Default 1; live A/B. + */ +static bool sema_gl_vs_img = true; +module_param_named(sema_gl_vs_img, sema_gl_vs_img, bool, 0644); +MODULE_PARM_DESC(sema_gl_vs_img, + "Deliver the built-in known-good VTG image (SPH+SASS) when the captured VS upload has no SASS body (default 1)"); static u8 svc_gl_prog[GSP_BRIDGE_INLINE_BYTES]; static u32 svc_gl_prog_len; static u8 svc_gl_vs[GSP_BRIDGE_INLINE_BYTES]; /* + * r1492: known-good VTG program image (SPH V4T1 020a0481 + SASS), the + * client's own fixed-function vertex shader recovered from its init-push + * page. r1491 proved the runtime capture of this 1.4-1.5 KB upload can be + * spliced at a page boundary: the delivered bytes were the SPH header + * plus ZERO SASS, so the VS executed no code and the draw stored nothing. + * The captured image must pass svc_gl_img_code_ok(); when it does not, + * this image is delivered at the bind VA instead. A/B via + * sema_gl_vs_img=0 (captured image only) and overridden by sema_gl_vs_hex. + * The bytes are the client's compiled program (no private provenance). + */ +static const u8 svc_gl_vs_img[1408] = { + + 0x81, 0x04, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x73, 0x04, 0xff, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00, + 0x02, 0x7a, 0x08, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x02, 0x7a, 0x0c, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x02, 0x7a, 0x0b, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x02, 0x7a, 0x0d, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x02, 0x7a, 0x0a, 0x00, 0x00, 0xe1, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x23, 0x76, 0x0c, 0x0c, 0x00, 0xec, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x02, 0x7a, 0x0f, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xc6, 0x0f, 0x00, + 0x23, 0x76, 0x0d, 0x0d, 0x00, 0xed, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x20, 0x7a, 0x00, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x1f, 0x04, + 0x20, 0x7a, 0x01, 0x04, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x20, 0x7a, 0x02, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x01, 0x05, 0x00, 0x35, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00, + 0x23, 0x7a, 0x00, 0x06, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x02, 0x05, 0x00, 0x39, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x01, 0x06, 0x00, 0x36, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x20, 0x72, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x02, 0x06, 0x00, 0x3a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x72, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xc8, 0x0f, 0x00, + 0x23, 0x72, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0xca, 0x0f, 0x00, + 0x0b, 0x72, 0x00, 0x05, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0x03, 0x00, 0xd8, 0x0f, 0x00, + 0x08, 0x03, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00, + 0x0b, 0x7a, 0x00, 0xff, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xd0, 0xf1, 0x03, 0x00, 0xe2, 0x0f, 0x00, + 0x20, 0x72, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x1f, 0x08, + 0x20, 0x72, 0x06, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x08, + 0x20, 0x7a, 0x01, 0x04, 0x00, 0x14, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x20, 0x72, 0x07, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x09, 0x78, 0x05, 0x08, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x81, 0x07, 0x00, 0xe2, 0x0f, 0x00, + 0x23, 0x7a, 0x00, 0x06, 0x00, 0x15, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xc6, 0x0f, 0x00, + 0x09, 0x78, 0x08, 0x05, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x81, 0x03, 0x00, 0xe2, 0x0f, 0x00, + 0x23, 0x7a, 0x00, 0x07, 0x00, 0x16, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x20, 0x7a, 0x05, 0x04, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x02, 0x7a, 0x04, 0x00, 0x00, 0xe2, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x09, 0x72, 0x09, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x07, 0x00, 0xe2, 0x0f, 0x00, + 0x23, 0x7a, 0x06, 0x06, 0x00, 0x09, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x21, 0x73, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00, + 0x23, 0x76, 0x0f, 0x0f, 0x00, 0xee, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00, + 0x08, 0x73, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x62, 0x0e, 0x00, + 0x23, 0x7a, 0x0a, 0x07, 0x00, 0x0a, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0xca, 0x0f, 0x00, + 0x09, 0x72, 0x0a, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x07, 0x00, 0xc8, 0x0f, 0x00, + 0x0b, 0x72, 0x00, 0x0a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf3, 0x03, 0x00, 0xe2, 0x0f, 0x00, + 0x20, 0x72, 0x0b, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x2f, 0x00, + 0x20, 0x7a, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xc8, 0x1f, 0x00, + 0x08, 0x73, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00, + 0x20, 0x7a, 0x06, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x20, 0x7a, 0x08, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x20, 0x7a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x05, 0x01, 0x00, 0x21, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x07, 0x01, 0x00, 0x25, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x09, 0x01, 0x00, 0x29, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00, + 0x23, 0x7a, 0x01, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x00, 0x02, 0x00, 0x22, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x04, + 0x08, 0x78, 0x0b, 0x0b, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0x00, + 0x23, 0x7a, 0x0e, 0x02, 0x00, 0x2e, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x01, 0x0a, 0x00, 0x1c, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x08, 0x72, 0x0b, 0x0b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x23, 0x7a, 0x04, 0x02, 0x00, 0x26, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x06, 0x02, 0x00, 0x2a, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00, + 0x23, 0x7a, 0x02, 0x0a, 0x00, 0x1d, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x0a, 0x0a, 0x00, 0x1e, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x07, 0x01, 0x00, 0xe4, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x01, 0x03, 0x00, 0x27, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x04, 0x0b, 0x00, 0x20, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x05, 0x0b, 0x00, 0x21, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00, + 0x23, 0x7a, 0x08, 0x02, 0x00, 0xe5, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x0a, 0x0a, 0x00, 0xe6, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x0b, 0x0b, 0x00, 0x22, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x02, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04, + 0x23, 0x7a, 0x04, 0x04, 0x00, 0xe8, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x02, 0x7a, 0x07, 0x00, 0x00, 0xe7, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x23, 0x7a, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00, + 0x23, 0x7a, 0x0e, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x05, 0x05, 0x00, 0xe9, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x23, 0x7a, 0x06, 0x0b, 0x00, 0xea, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00, + 0x22, 0x73, 0x00, 0xff, 0x00, 0x70, 0x00, 0x00, 0xff, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x0f, 0x00, + 0x22, 0x73, 0x00, 0xff, 0x0e, 0x7c, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x0f, 0x00, + 0x22, 0x73, 0x00, 0xff, 0x04, 0x80, 0x02, 0x00, 0xff, 0x0c, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0x00, + 0x4d, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xea, 0x0f, 0x00, + 0x47, 0x79, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0x03, 0x00, 0xc0, 0x0f, 0x00, +}; + +/* * r1481: shader-image cache filled from any push chunk that starts with a * real SPH magic. The client's init push carries its VS/PS images as raw * continuation chunks (first word 020a0481 / 000a1482) whose method @@ -8434,6 +8545,43 @@ static void svc_gl_prog_apply_param(void) &svc_gl_vs_len, svc_gl_vs_seen); svc_gl_hex_parse(sema_gl_ps_hex, "ps-hex", svc_gl_ps, &svc_gl_ps_len, svc_gl_ps_seen); + if (READ_ONCE(sema_gl_vs_img) && !svc_gl_vs_len) { + memcpy(svc_gl_vs, svc_gl_vs_img, sizeof(svc_gl_vs_img)); + svc_gl_vs_len = (u32)sizeof(svc_gl_vs_img); + } +} + +/* + * r1492: is a captured program image complete enough to deliver? + * + * The client's 0x180/0x1b0 upload runs carry a 128 B SPH followed by SASS. + * The push decoder reads a long entry page by page; when the image payload + * straddles a page whose continuation the ring mapping does not describe, + * the captured bytes are the SPH (in the first page) plus ZERO for the + * SASS tail. r1491 proved that shape on the beef VTG page: the shadow + * receipt read `020a0481 ...` at +0x900 and `code4=00000000` at +0x980, + * while the same page's PS and TESS images had real SASS. Delivering such + * an image overwrites the real program page with a header that has no + * code, so the VS executes NOPs and no vertex reaches the raster. + * + * Gate: SPH magic (SPH type 1=VTG or 2=PS in bits 4:0) and at least one + * nonzero word in the code region [0x80, min(len, 0x200)). A header-only + * image is rejected and the caller falls through to the known-good image + * path (sema_gl_vs_hex / ps_hex or the cached image). + */ +static bool svc_gl_img_code_ok(const u8 *d, u32 n) +{ + u32 w0, i; + + if (!d || n < 0x90u) + return false; + w0 = get_unaligned_le32(d); + if ((w0 & 0x1fu) != 1u && (w0 & 0x1fu) != 2u) + return false; + for (i = 0x80u; i + 4u <= n && i < 0x200u; i += 4u) + if (get_unaligned_le32(d + i)) + return true; + return false; } /* @@ -10135,12 +10283,44 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu, prs[n_recs].data, (u32)sizeof(prs[n_recs].data)); + /* + * r1492: a captured image whose + * SASS body is zero is the + * page-splice corruption, not a + * valid program; reject it so the + * authored image below (the real + * VS/PS bytes) can land instead. + */ + if (got && !svc_gl_img_code_ok( + prs[n_recs].data, + rlen)) { + if (gsp_sema_dbg && + svc_gl_prog_log < 64) { + svc_gl_prog_log++; + pr_info("sema-gl: real-upload REJECTED va=0x%llx len=%u first=%08x code4=%08x (SPH only; captured SASS body zero)\n", + svc_gl.progs[pi], + rlen, + get_unaligned_le32( + prs[n_recs].data), + rlen > 0x80u ? + get_unaligned_le32( + prs[n_recs].data + + 0x80u) : + 0u); + } + got = false; + rlen = 0; + } if (!got && t != 5u && t != 0xffu) { got = svc_grce_dst_sph( 0x020a0481u, 128u, &rlen, prs[n_recs].data, (u32)sizeof(prs[n_recs].data)); + if (got && !svc_gl_img_code_ok( + prs[n_recs].data, + rlen)) + got = false; if (!got && svc_gl_sph_cache_len[1]) { rlen = min_t(u32, @@ -10149,7 +10329,9 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu, memcpy(prs[n_recs].data, svc_gl_sph_cache[1], rlen); - got = true; + got = svc_gl_img_code_ok( + prs[n_recs].data, + rlen); } } if (got) { @@ -10240,12 +10422,37 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu, if (svc_gl.up[uu].len < 128u) continue; if ((svc_gl.up[uu].dst_va & - ~(u64)(SEMA_PAGE_SIZE - 1)) == + ~(u64)(SEMA_PAGE_SIZE - 1)) != (svc_gl.progs[pi] & - ~(u64)(SEMA_PAGE_SIZE - 1))) { - real_up = true; - break; + ~(u64)(SEMA_PAGE_SIZE - 1))) + continue; + /* + * r1492: same page, but a + * header-only payload is the + * page-splice corruption - do not + * let it suppress the authored + * real image. + */ + if (!svc_gl_img_code_ok( + svc_gl.up[uu].data, + svc_gl.up[uu].len)) { + if (gsp_sema_dbg && + svc_gl_prog_log < 64) { + svc_gl_prog_log++; + pr_info("sema-gl: real-upload page va=0x%llx len=%u code4=%08x rejected (authored image used)\n", + svc_gl.up[uu].dst_va, + svc_gl.up[uu].len, + svc_gl.up[uu].len > + 0x80u ? + get_unaligned_le32( + svc_gl.up[uu].data + + 0x80u) : + 0u); + } + continue; } + real_up = true; + break; } if (real_up) { if (gsp_sema_dbg && @@ -15150,16 +15357,84 @@ static u32 svc_gl_cb_hash(const u8 *p, u32 n) return h; } +/* + * r1491: is the position block (c[0x0][0x80..0xbc], the 4x4 matrix the + * captured VS uses to turn the vertex into clip space) usable? A NaN/Inf + * word or an all-zero 16-word block means the source page is not the + * engine-written fixed constant buffer (or the matrix was never filled), + * and the draw would collapse every triangle regardless of the vertex + * fetch. Finite and not all-zero is the minimum credible shape. + */ +static bool svc_gl_cb_matrix_ok(const u8 *buf) +{ + u32 i, nz = 0, normal = 0; + + for (i = 0; i < 16u; i++) { + u32 w = get_unaligned_le32(buf + 0x80u + i * 4u); + u32 exp = (w >> 23) & 0xffu; + + if (exp == 0xffu) + return false; + if (!(w & 0x7fffffffu)) + continue; + nz++; + /* + * r1492: a method-stream page mis-resolved for the CB + * answers with headers/payload words whose "floats" are + * zero/denormal/tiny (0x2001xxxx -> exp 0x40). A real + * transform row has normal-scale components. Requiring four + * normal-magnitude words rejects the method pages that made + * r1492 accept a garbage matrix (`00000053 80000585 + * 20010d2a ... ok=1`). + */ + if (exp >= 0x70u && exp <= 0x8eu) + normal++; + } + return nz != 0u && normal >= 4u; +} + +static void svc_gl_cb_dump_matrix(const u8 *buf, const char *src, u64 pa, + u32 ap, int ssrc) +{ + u32 i, w[16]; + + for (i = 0; i < 16u; i++) + w[i] = get_unaligned_le32(buf + 0x80u + i * 4u); + pr_info("vgsp-sema: sema-gl: cb-matrix src=%s pa=0x%llx ap=%u ssrc=%d m[0x80..0xbc]=%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x ok=%u\n", + src, pa, ap, ssrc, w[0], w[1], w[2], w[3], w[4], w[5], + w[6], w[7], w[8], w[9], w[10], w[11], w[12], w[13], w[14], + w[15], svc_gl_cb_matrix_ok(buf)); + pr_info("vgsp-sema: sema-gl: cb-const src=%s c[0x2a0..0x2a8]=%08x %08x %08x c[0x780..0x7c8]=%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x c[0x820..0x828]=%08x %08x %08x c[0x850..0x858]=%08x %08x %08x c[0x870..0x888]=%08x %08x %08x %08x %08x %08x %08x\n", + src, + get_unaligned_le32(buf + 0x2a0), get_unaligned_le32(buf + 0x2a4), + get_unaligned_le32(buf + 0x2a8), + get_unaligned_le32(buf + 0x780), get_unaligned_le32(buf + 0x784), + get_unaligned_le32(buf + 0x788), get_unaligned_le32(buf + 0x78c), + get_unaligned_le32(buf + 0x790), get_unaligned_le32(buf + 0x794), + get_unaligned_le32(buf + 0x798), get_unaligned_le32(buf + 0x79c), + get_unaligned_le32(buf + 0x7a0), get_unaligned_le32(buf + 0x7a4), + get_unaligned_le32(buf + 0x7a8), get_unaligned_le32(buf + 0x7c0), + get_unaligned_le32(buf + 0x7c4), get_unaligned_le32(buf + 0x7c8), + get_unaligned_le32(buf + 0x820), get_unaligned_le32(buf + 0x824), + get_unaligned_le32(buf + 0x828), + get_unaligned_le32(buf + 0x850), get_unaligned_le32(buf + 0x854), + get_unaligned_le32(buf + 0x858), + get_unaligned_le32(buf + 0x870), get_unaligned_le32(buf + 0x874), + get_unaligned_le32(buf + 0x878), + get_unaligned_le32(buf + 0x880), get_unaligned_le32(buf + 0x884), + get_unaligned_le32(buf + 0x888)); +} + static void svc_gl_cb_copy(struct nv_vgpu_device *vgpu, u32 h_object) { /* Static: 4 KB is too much for the kernel stack; this runs on the * single service thread (same reason as the static arrays in * svc_gl_flush and svc_decode_stream). */ static u8 buf[SEMA_PAGE_SIZE]; - u64 src_va, pa = 0; + u64 src_va, pa = 0, hpa = 0; u32 ap = 0, val, hash; const char *src = "resolve"; - int rc; + int rc, ssrc = 0; if (!sema_gl_cb_copy_to) return; @@ -15176,65 +15451,141 @@ static void svc_gl_cb_copy(struct nv_vgpu_device *vgpu, u32 h_object) return; src_va = (u64)val << 8; } - rc = svc_resolve_va(vgpu, src_va, &pa, &ap); - if (rc) { - /* Fallback 1: the trusted walk svc_gl_flush uses for the - * program page. */ - rc = svc_read_va_trusted(vgpu, src_va, buf, sizeof(buf)); - if (!rc) { - src = "trusted"; + /* + * r1491: the fixed constant buffer is ENGINE-written (the driver + * publishes its base through SET_MME_SHADOW_SCRATCH(FIXED_CONSTANT_ + * BUFFER), then VPC constant methods and the fixed-CB selector make + * the GPU fill it). Its content therefore lives in the page the GR + * engine reads: a guest-RAM GPA (SYS). The emulated BAR1 vidmem + * shadow only holds guest-CPU writes through the aperture, so + * reading a FB-resolved fixed CB there returns unrelated vidmem - + * r1490 read `09037223 00000004`, r1482 oscillated between a float + * row, method words and zeros. Resolve the page the way the engine + * does first: this channel's own VAS, then the GR relocation + * resolver (ledger + VAS walk + verified HPA). Only a SYS answer is + * content-valid; an FB answer falls through to the walk paths, and + * the FB shadow read is the last resort (and marks the matrix + * untrusted). + */ + if (!svc_chanvas_lookup(vgpu, src_va, &pa, &ap)) { + ssrc = 1; + src = "chanvas"; + if (ap == SVC_APERTURE_SYS && + !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf, + sizeof(buf))) goto have; + } + /* + * r1492: walk every registered VAS before the GR ledger. The + * landing table (which gr_reloc_resolve prefers for VAs above + * SVC_VAS_FLOOR) is fed by our own launches and can answer with a + * re-used VA's page; the page tables are the mapping truth. + */ + if (!svc_walk_vaspaces(vgpu, + src_va & ~(u64)(SEMA_PAGE_SIZE - 1), + &pa, &ap)) { + pa += src_va & (SEMA_PAGE_SIZE - 1u); + ssrc = 8; + src = "vaswalk"; + if (ap == SVC_APERTURE_SYS && + !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf, + sizeof(buf))) + goto have; + } + { + struct gsp_sema_gr_reloc r; + + if (!gsp_sema_gr_reloc_resolve(src_va, &r)) { + pa = r.pa; + ap = r.ap; + hpa = r.hpa; + ssrc = 2; + src = (r.ap == SVC_APERTURE_FB) ? "gr-fb" : "gr-sys"; + if (r.ap == SVC_APERTURE_SYS && + !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf, + sizeof(buf))) + goto have; } - /* Fallback 2: the general lookup (adds the vidmem window - * convention). */ - rc = svc_read_va(vgpu, src_va, buf, sizeof(buf)); - if (!rc) { - src = "lookup"; + } + rc = svc_resolve_va(vgpu, src_va, &pa, &ap); + if (!rc && ap == SVC_APERTURE_SYS && + !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf, sizeof(buf))) { + ssrc = 3; + src = "resolve-sys"; + goto have; + } + if (!rc) { + /* An FB resolution is only valid for content the guest CPU + * writes through the aperture; use it but flag it. */ + if (!svc_read_ap(vgpu, pa, ap, buf, sizeof(buf))) { + ssrc = 4; + src = "resolve-fb"; goto have; } - /* - * r1476: the client's fixed-CB VA is a GPU/vidmem VA the - * service cannot walk (resolve -2 even through the trusted - * and general fallbacks). Rather than leave the VS reading - * screen data, author a synthetic identity MVP at the - * position block the VS reads (c[0x0][0x80..0xbc], one - * 4x4 row-major matrix). The vertices then pass through in - * model space; the viewport prelude maps NDC to the RT. This - * is a controlled positive control for the raster path: if - * pixels appear, the constant CONTENT is the only remaining - * unknown; if not, the raster/clip path is still wrong. - */ + } + /* Fallback: the trusted walk svc_gl_flush uses for the program page. */ + if (!svc_read_va_trusted(vgpu, src_va, buf, sizeof(buf))) { + ssrc = 5; + src = "trusted"; + goto have; + } + /* Fallback: the general lookup (adds the vidmem window convention). */ + if (!svc_read_va(vgpu, src_va, buf, sizeof(buf))) { + ssrc = 6; + src = "lookup"; + goto have; + } + /* + * r1476: nothing resolved the client's fixed-CB VA. Rather than + * leave the VS reading screen data, author a synthetic identity MVP + * at the position block the VS reads (c[0x0][0x80..0xbc], one 4x4 + * row-major matrix). The vertices then pass through in model space; + * the viewport prelude maps NDC to the RT. This is a controlled + * positive control for the raster path: if pixels appear, the + * constant CONTENT is the only remaining unknown; if not, the + * raster/clip path is still wrong. + */ + memset(buf, 0, sizeof(buf)); + put_unaligned_le32(0x3f800000u, buf + 0x80); /* m00 */ + put_unaligned_le32(0x3f800000u, buf + 0x94); /* m11 */ + put_unaligned_le32(0x3f800000u, buf + 0xa8); /* m22 */ + put_unaligned_le32(0x3f800000u, buf + 0xbc); /* m33 */ + src = "synthetic-id"; + ssrc = 7; + goto have; +have: + /* + * r1491: a source whose 0x80 block is not a credible matrix would + * still collapse every vertex. Only a SYS (engine-page) read is + * trusted; an FB-shadow read is by construction not the engine's + * page, so author the identity positive control there too. + */ + if ((ssrc == 4 || ssrc == 5 || ssrc == 6 || ssrc == 7) || + !svc_gl_cb_matrix_ok(buf)) { memset(buf, 0, sizeof(buf)); put_unaligned_le32(0x3f800000u, buf + 0x80); /* m00 */ put_unaligned_le32(0x3f800000u, buf + 0x94); /* m11 */ put_unaligned_le32(0x3f800000u, buf + 0xa8); /* m22 */ put_unaligned_le32(0x3f800000u, buf + 0xbc); /* m33 */ src = "synthetic-id"; - goto have; } - if (svc_read_ap(vgpu, pa, ap, buf, sizeof(buf))) { - if (svc_gl_cb_copy_log < 8u) { - svc_gl_cb_copy_log++; - pr_info("vgsp-sema: sema-gl: cb-copy src=0x%llx dst=0x%llx resolve=0 ap=%u read failed\n", - src_va, sema_gl_cb_copy_to, ap); - } - return; - } -have: hash = svc_gl_cb_hash(buf, sizeof(buf)); if (svc_gl_cb_copy_h == h_object && svc_gl_cb_copy_val == val && svc_gl_cb_copy_hash == hash) return; rc = svc_grce_inline_write(vgpu, sema_gl_cb_copy_to, buf, sizeof(buf), h_object); - if (svc_gl_cb_copy_log < 8u) { + if (svc_gl_cb_copy_log < 24u) { u32 w0, w1; memcpy(&w0, buf, 4); memcpy(&w1, buf + 4, 4); svc_gl_cb_copy_log++; - pr_info("vgsp-sema: sema-gl: cb-copy src=0x%llx dst=0x%llx resolve=%d ap=%u first=%08x %08x src=%s write=%d (fixed-CB page -> forced seed page)\n", - src_va, sema_gl_cb_copy_to, 0, ap, w0, w1, src, rc); + pr_info("vgsp-sema: sema-gl: cb-copy src=0x%llx dst=0x%llx pa=0x%llx ap=%u hpa=0x%llx ssrc=%d first=%08x %08x src=%s write=%d (fixed-CB page -> forced seed page)\n", + src_va, sema_gl_cb_copy_to, pa, ap, hpa, ssrc, w0, w1, + src, rc); + if (svc_gl_cb_copy_log <= 4u) + svc_gl_cb_dump_matrix(buf, src, pa, ap, ssrc); } if (!rc) { svc_gl_cb_copy_h = h_object; |
