summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c89
1 files changed, 58 insertions, 31 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index e972732..ee73027 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -53,6 +53,23 @@
#include "gsp_phys_gpu.h"
#include "gsp_cuda_bridge.h"
+/*
+ * ISSUE-0002 (r75b): bounds for accesses through the emulated vidmem shadow
+ * at vgpu->bars[1].vaddr. The shadow is sized by the mdev type
+ * (nv_vgpu_fb_emul_size: 512M/1G/2G) while vgpu->bars[1].size is the physical
+ * BAR1 aperture exposed to the guest (256M on TU104). Every bounds check that
+ * guards a shadow dereference must use the shadow size: a legitimate guest
+ * vidmem offset above the aperture (the pma scrub memset at 262M in a second/
+ * third CUDA session) was rejected as -EINVAL against the aperture bound and
+ * the client froze in scrubCheckAndWaitForSize. Using the shadow size is also
+ * the safe direction in the inverse case: an aperture larger than the shadow
+ * would otherwise let a check pass past the vzalloc'd buffer.
+ */
+static inline u64 svc_fb_shadow_size(const struct nv_vgpu_device *vgpu)
+{
+ return nv_vgpu_fb_emul_size(vgpu);
+}
+
#define SEMA_MAP_MAX 65536
#define SEMA_MAP_SIZE_BITS 16
#define SEMA_PAGE_SIZE 4096
@@ -874,7 +891,7 @@ static int svc_read_ap(struct nv_vgpu_device *vgpu, u64 addr, u32 aperture,
{
if (aperture == SVC_APERTURE_FB) {
u8 *base = vgpu->bars[1].vaddr;
- size_t size = vgpu->bars[1].size;
+ size_t size = svc_fb_shadow_size(vgpu);
if (!base || addr + len > size)
return -EINVAL;
@@ -889,7 +906,7 @@ static int svc_write_ap(struct nv_vgpu_device *vgpu, u64 addr, u32 aperture,
{
if (aperture == SVC_APERTURE_FB) {
u8 *base = vgpu->bars[1].vaddr;
- size_t size = vgpu->bars[1].size;
+ size_t size = svc_fb_shadow_size(vgpu);
if (!base || addr + len > size)
return -EINVAL;
@@ -1273,7 +1290,7 @@ static int svc_pde_aperture(u32 ap)
static bool svc_ap_ok(struct nv_vgpu_device *vgpu, u64 addr, int ap)
{
if (ap == SVC_APERTURE_FB)
- return vgpu->bars[1].vaddr && addr + 8 <= vgpu->bars[1].size;
+ return vgpu->bars[1].vaddr && addr + 8 <= svc_fb_shadow_size(vgpu);
return addr + 8 <= SEMA_PA_MAX;
}
@@ -1397,10 +1414,20 @@ static int svc_gmmu_walk(struct nv_vgpu_device *vgpu, u64 pdb, u32 entries,
if (big & 1) {
bap = svc_pte_aperture((big >> 1) & 0x3);
if (bap >= 0) {
- *addr = svc_pte_addr(big, bap == SVC_APERTURE_FB) +
+ u64 a = svc_pte_addr(big, bap == SVC_APERTURE_FB) +
(va & ((1ULL << 21) - 1));
- *ap = bap;
- return 0;
+
+ /*
+ * ISSUE-0002 (r75b): validate the 2 MB leaf against
+ * the aperture bounds like every other leaf path; an
+ * unchecked out-of-shadow result must fall through to
+ * the shadow fallback, not reach the copy path.
+ */
+ if (svc_ap_ok(vgpu, a, bap)) {
+ *addr = a;
+ *ap = bap;
+ return 0;
+ }
}
}
bap = svc_pde_aperture((big >> 1) & 0x3);
@@ -1603,7 +1630,7 @@ static void svc_pd_discover(struct nv_vgpu_device *vgpu)
* matters is the first one of the page. */
for (pass = 0; pass < 2 && !svc_pd_found; pass++) {
int ap = pass == 0 ? SVC_APERTURE_SYS : SVC_APERTURE_FB;
- u64 limit = pass == 0 ? SEMA_PA_MAX : vgpu->bars[1].size;
+ u64 limit = pass == 0 ? SEMA_PA_MAX : svc_fb_shadow_size(vgpu);
u8 *fb = (u8 *)vgpu->bars[1].vaddr;
u64 gpa;
@@ -2319,7 +2346,7 @@ static int svc_lookup(struct nv_vgpu_device *vgpu, u64 va, u64 *addr, int *ap)
if (!svc_lookup_trusted(vgpu, va, addr, ap))
return 0;
if (va >= SVC_VIDMEM_VA_BASE &&
- va - SVC_VIDMEM_VA_BASE + 4 <= vgpu->bars[1].size) {
+ va - SVC_VIDMEM_VA_BASE + 4 <= svc_fb_shadow_size(vgpu)) {
*addr = va - SVC_VIDMEM_VA_BASE;
*ap = SVC_APERTURE_FB;
svc_lat_store(va, *addr, *ap);
@@ -3679,7 +3706,7 @@ static int svc_fill(struct nv_vgpu_device *vgpu, u64 addr, u64 value, u32 elem,
if (aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- size_t size = vgpu->bars[1].size;
+ size_t size = svc_fb_shadow_size(vgpu);
if (!base || addr + total > size)
return -EINVAL;
@@ -4147,7 +4174,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
} else if (src_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && src + sizeof(sb) <= vgpu->bars[1].size)
+ if (base && src + sizeof(sb) <= svc_fb_shadow_size(vgpu))
memcpy(sb, base + src, sizeof(sb));
} else {
svc_read(vgpu, src, sb, sizeof(sb));
@@ -4157,7 +4184,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
} else if (dst_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && dst + sizeof(db) <= vgpu->bars[1].size)
+ if (base && dst + sizeof(db) <= svc_fb_shadow_size(vgpu))
memcpy(db, base + dst, sizeof(db));
} else {
svc_read(vgpu, dst, db, sizeof(db));
@@ -4259,7 +4286,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (src_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && src + 8 <= vgpu->bars[1].size)
+ if (base && src + 8 <= svc_fb_shadow_size(vgpu))
memcpy(sb, base + src, 8);
} else {
svc_read(vgpu, src, sb, 8);
@@ -4267,7 +4294,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (dst_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && dst + 8 <= vgpu->bars[1].size)
+ if (base && dst + 8 <= svc_fb_shadow_size(vgpu))
memcpy(db, base + dst, 8);
} else {
svc_read(vgpu, dst, db, 8);
@@ -4319,7 +4346,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (src_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && src + n <= vgpu->bars[1].size)
+ if (base && src + n <= svc_fb_shadow_size(vgpu))
memcpy(peek, base + src, n);
} else {
svc_read(vgpu, src, peek, n);
@@ -4361,7 +4388,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (aper == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (!base || pa + chunk > vgpu->bars[1].size)
+ if (!base || pa + chunk > svc_fb_shadow_size(vgpu))
return -EINVAL;
memcpy(bounce, base + pa, chunk);
} else if (svc_read(vgpu, pa, bounce, chunk)) {
@@ -4369,7 +4396,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
}
} else if (src_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- size_t size = vgpu->bars[1].size;
+ size_t size = svc_fb_shadow_size(vgpu);
if (!base || src + o + chunk > size)
return -EINVAL;
@@ -4391,7 +4418,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (aper == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (!base || pa + chunk > vgpu->bars[1].size)
+ if (!base || pa + chunk > svc_fb_shadow_size(vgpu))
return -EINVAL;
memcpy(base + pa, bounce, chunk);
} else if (svc_write(vgpu, pa, bounce, chunk)) {
@@ -4399,7 +4426,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
}
} else if (dst_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- size_t size = vgpu->bars[1].size;
+ size_t size = svc_fb_shadow_size(vgpu);
if (!base || dst + o + chunk > size)
return -EINVAL;
@@ -4425,7 +4452,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
} else if (dst_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && dst + sizeof(da) <= vgpu->bars[1].size)
+ if (base && dst + sizeof(da) <= svc_fb_shadow_size(vgpu))
memcpy(da, base + dst, sizeof(da));
} else {
svc_read(vgpu, dst, da, sizeof(da));
@@ -4443,7 +4470,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (dst_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && dst + 8 <= vgpu->bars[1].size)
+ if (base && dst + 8 <= svc_fb_shadow_size(vgpu))
memcpy(da, base + dst, 8);
} else {
svc_read(vgpu, dst, da, 8);
@@ -4460,7 +4487,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total,
if (dst_aperture == CE_APERTURE_VID) {
u8 *base = vgpu->bars[1].vaddr;
- if (base && dst + n <= vgpu->bars[1].size)
+ if (base && dst + n <= svc_fb_shadow_size(vgpu))
memcpy(da, base + dst, n);
} else {
svc_read(vgpu, dst, da, n);
@@ -4530,7 +4557,7 @@ static int svc_grce_inline_write(struct nv_vgpu_device *vgpu, u64 dst_va,
if (ap == SVC_APERTURE_FB) {
u8 *base = vgpu->bars[1].vaddr;
- if (!base || pa + bytes > vgpu->bars[1].size)
+ if (!base || pa + bytes > svc_fb_shadow_size(vgpu))
return -EINVAL;
memcpy(base + pa, data, bytes);
} else {
@@ -8791,9 +8818,9 @@ static void svc_gr_content_discover(struct nv_vgpu_device *vgpu)
* entry0 must sit at the pinned page's offset 0 for the page-granular
* pin to be correct.
*/
- if (vgpu->bars[1].vaddr && vgpu->bars[1].size) {
+ if (vgpu->bars[1].vaddr && svc_fb_shadow_size(vgpu)) {
const u8 *fb = (const u8 *)vgpu->bars[1].vaddr;
- u64 lim = min_t(u64, vgpu->bars[1].size,
+ u64 lim = min_t(u64, svc_fb_shadow_size(vgpu),
SVC_GR_CONTENT_FB_LIMIT);
u64 off;
@@ -9274,9 +9301,9 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu,
* entry0-shaped word (1 MB aligned push VA, sane length). The
* client's ring allocation offset varies per boot; the scan
* names the real location for the fix. */
- if (gsp_sema_dbg && vgpu->bars[1].vaddr && vgpu->bars[1].size &&
+ if (gsp_sema_dbg && vgpu->bars[1].vaddr && svc_fb_shadow_size(vgpu) &&
!svc_fbs_scan_done) {
- u64 lim = min_t(u64, vgpu->bars[1].size, 0x20000000ULL);
+ u64 lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x20000000ULL);
u64 off;
int hits = 0;
@@ -10501,8 +10528,8 @@ static int svc_fwd_operand_hpa(struct nv_vgpu_device *vgpu, u8 kind,
u8 *base = vgpu ? vgpu->bars[1].vaddr : NULL;
struct page *pg;
- if (!base || page > vgpu->bars[1].size ||
- (u64)page_off + bytes > vgpu->bars[1].size - page)
+ if (!base || page > svc_fb_shadow_size(vgpu) ||
+ (u64)page_off + bytes > svc_fb_shadow_size(vgpu) - page)
return -ERANGE;
pg = vmalloc_to_page(base + page);
if (!pg)
@@ -12858,7 +12885,7 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
pr_info("sema-userd-sweep: h=0x%x e0=0x%x e1=0x%x\n",
ch->h_object, e0, e1);
}
- for (off = 0x80000; off + 8 <= vgpu->bars[1].size && off < 0x200000;
+ for (off = 0x80000; off + 8 <= svc_fb_shadow_size(vgpu) && off < 0x200000;
off += 0x1000) {
u32 w0, w1;
@@ -14927,7 +14954,7 @@ int gsp_sema_service_dump_vidmem(u64 addr, u64 len)
return -ENODEV;
base = vgpu->bars[1].vaddr;
- if (!base || addr + len > vgpu->bars[1].size)
+ if (!base || addr + len > svc_fb_shadow_size(vgpu))
return -EINVAL;
pr_info("sema-vidmem: dump addr=0x%llx len=%llu\n",
@@ -14961,7 +14988,7 @@ int gsp_sema_service_find_vidmem(u64 pattern, u64 max_hits)
return -ENODEV;
base = vgpu->bars[1].vaddr;
- size = vgpu->bars[1].size;
+ size = svc_fb_shadow_size(vgpu);
if (!base)
return -EINVAL;
if (!max_hits)