Message ID | 1360365230-19922-1-git-send-email-j.glisse@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Feb 8, 2013 at 6:13 PM, <j.glisse@gmail.com> wrote: > From: Jerome Glisse <jglisse@redhat.com> > > In some rare case were packet is big enough to go over page boundary > we might not have copied yet the userspace data into the local copy > resulting in kernel reading garbage data. > > Without this patch kernel might submit unprocessed/unrelocated cmd > to the GPU which might lead to GPU lockup. > > v2: Make sure we do copy all the page and don't forget some when > the packet count dw is bigger than 1 page > v3: Rebase patch against Linus master > > Signed-off-by: Jerome Glisse <jglisse@redhat.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> > --- > drivers/gpu/drm/radeon/evergreen_cs.c | 35 ++++++++++++++++++++++++++++++++++- > drivers/gpu/drm/radeon/r600_cs.c | 19 ++++++++++++++++++- > 2 files changed, 52 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c > index 7a44566..51ad74a 100644 > --- a/drivers/gpu/drm/radeon/evergreen_cs.c > +++ b/drivers/gpu/drm/radeon/evergreen_cs.c > @@ -1021,7 +1021,7 @@ static int evergreen_cs_packet_parse(struct radeon_cs_parser *p, > unsigned idx) > { > struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; > - uint32_t header; > + uint32_t header, i, npages; > > if (idx >= ib_chunk->length_dw) { > DRM_ERROR("Can not parse packet at %d after CS end %d !\n", > @@ -1052,6 +1052,11 @@ static int evergreen_cs_packet_parse(struct radeon_cs_parser *p, > pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); > return -EINVAL; > } > + /* make sure we copied packet fully from userspace */ > + npages = ((idx + pkt->count + 1) >> 10) - (idx >> 10); > + for (i = 1; i <= npages; i++) { > + radeon_get_ib_value(p, (idx & 0xfffffc00) + i * 0x400); > + } > return 0; > } > > @@ -2909,12 +2914,16 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > return -EINVAL; > } > if (tiled) { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 6); > dst_offset = ib[idx+1]; > dst_offset <<= 8; > > ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); > p->idx += count + 7; > } else { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 2); > dst_offset = ib[idx+1]; > dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; > > @@ -2945,6 +2954,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > switch (misc) { > case 0: > /* L2T, frame to fields */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 9); > if (idx_value & (1 << 31)) { > DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); > return -EINVAL; > @@ -2983,6 +2994,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 1: > /* L2T, T2L partial */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 11); > if (p->family < CHIP_CAYMAN) { > DRM_ERROR("L2T, T2L Partial is cayman only !\n"); > return -EINVAL; > @@ -3005,6 +3018,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 3: > /* L2T, broadcast */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 9); > if (idx_value & (1 << 31)) { > DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); > return -EINVAL; > @@ -3043,6 +3058,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 4: > /* L2T, T2L */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 8); > /* detile bit */ > if (idx_value & (1 << 31)) { > /* tiled src, linear dst */ > @@ -3079,6 +3096,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 5: > /* T2T partial */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 12); > if (p->family < CHIP_CAYMAN) { > DRM_ERROR("L2T, T2L Partial is cayman only !\n"); > return -EINVAL; > @@ -3089,6 +3108,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 7: > /* L2T, broadcast */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 9); > if (idx_value & (1 << 31)) { > DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); > return -EINVAL; > @@ -3132,6 +3153,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > } else { > switch (misc) { > case 0: > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 8); > /* detile bit */ > if (idx_value & (1 << 31)) { > /* tiled src, linear dst */ > @@ -3176,6 +3199,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > switch (misc) { > case 0: > /* L2L, byte */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 4); > src_offset = ib[idx+2]; > src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; > dst_offset = ib[idx+1]; > @@ -3198,6 +3223,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 1: > /* L2L, partial */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 8); > if (p->family < CHIP_CAYMAN) { > DRM_ERROR("L2L Partial is cayman only !\n"); > return -EINVAL; > @@ -3211,6 +3238,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > break; > case 4: > /* L2L, dw, broadcast */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 6); > r = r600_dma_cs_next_reloc(p, &dst2_reloc); > if (r) { > DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n"); > @@ -3251,6 +3280,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > } > } else { > /* L2L, dw */ > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 4); > src_offset = ib[idx+2]; > src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; > dst_offset = ib[idx+1]; > @@ -3274,6 +3305,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) > } > break; > case DMA_PACKET_CONSTANT_FILL: > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 3); > r = r600_dma_cs_next_reloc(p, &dst_reloc); > if (r) { > DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); > diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c > index 69ec24a..d36f9e6 100644 > --- a/drivers/gpu/drm/radeon/r600_cs.c > +++ b/drivers/gpu/drm/radeon/r600_cs.c > @@ -796,7 +796,7 @@ static int r600_cs_packet_parse(struct radeon_cs_parser *p, > unsigned idx) > { > struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; > - uint32_t header; > + uint32_t header, i, npages; > > if (idx >= ib_chunk->length_dw) { > DRM_ERROR("Can not parse packet at %d after CS end %d !\n", > @@ -827,6 +827,11 @@ static int r600_cs_packet_parse(struct radeon_cs_parser *p, > pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); > return -EINVAL; > } > + /* make sure we copied packet fully from userspace */ > + npages = ((idx + pkt->count + 1) >> 10) - (idx >> 10); > + for (i = 1; i <= npages; i++) { > + radeon_get_ib_value(p, (idx & 0xfffffc00) + i * 0x400); > + } > return 0; > } > > @@ -2623,12 +2628,16 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) > return -EINVAL; > } > if (tiled) { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 4); > dst_offset = ib[idx+1]; > dst_offset <<= 8; > > ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); > p->idx += count + 5; > } else { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 2); > dst_offset = ib[idx+1]; > dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; > > @@ -2654,6 +2663,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) > return -EINVAL; > } > if (tiled) { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 6); > idx_value = radeon_get_ib_value(p, idx + 2); > /* detile bit */ > if (idx_value & (1 << 31)) { > @@ -2680,6 +2691,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) > p->idx += 7; > } else { > if (p->family >= CHIP_RV770) { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 4); > src_offset = ib[idx+2]; > src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; > dst_offset = ib[idx+1]; > @@ -2691,6 +2704,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) > ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; > p->idx += 5; > } else { > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 3); > src_offset = ib[idx+2]; > src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; > dst_offset = ib[idx+1]; > @@ -2715,6 +2730,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) > } > break; > case DMA_PACKET_CONSTANT_FILL: > + /* make sure we copied packet fully from userspace */ > + radeon_get_ib_value(p, idx + 3); > if (p->family < CHIP_RV770) { > DRM_ERROR("Constant Fill is 7xx only !\n"); > return -EINVAL; > -- > 1.7.11.7 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 7a44566..51ad74a 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -1021,7 +1021,7 @@ static int evergreen_cs_packet_parse(struct radeon_cs_parser *p, unsigned idx) { struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; - uint32_t header; + uint32_t header, i, npages; if (idx >= ib_chunk->length_dw) { DRM_ERROR("Can not parse packet at %d after CS end %d !\n", @@ -1052,6 +1052,11 @@ static int evergreen_cs_packet_parse(struct radeon_cs_parser *p, pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); return -EINVAL; } + /* make sure we copied packet fully from userspace */ + npages = ((idx + pkt->count + 1) >> 10) - (idx >> 10); + for (i = 1; i <= npages; i++) { + radeon_get_ib_value(p, (idx & 0xfffffc00) + i * 0x400); + } return 0; } @@ -2909,12 +2914,16 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) return -EINVAL; } if (tiled) { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 6); dst_offset = ib[idx+1]; dst_offset <<= 8; ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); p->idx += count + 7; } else { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 2); dst_offset = ib[idx+1]; dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; @@ -2945,6 +2954,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) switch (misc) { case 0: /* L2T, frame to fields */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 9); if (idx_value & (1 << 31)) { DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); return -EINVAL; @@ -2983,6 +2994,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 1: /* L2T, T2L partial */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 11); if (p->family < CHIP_CAYMAN) { DRM_ERROR("L2T, T2L Partial is cayman only !\n"); return -EINVAL; @@ -3005,6 +3018,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 3: /* L2T, broadcast */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 9); if (idx_value & (1 << 31)) { DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); return -EINVAL; @@ -3043,6 +3058,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 4: /* L2T, T2L */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 8); /* detile bit */ if (idx_value & (1 << 31)) { /* tiled src, linear dst */ @@ -3079,6 +3096,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 5: /* T2T partial */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 12); if (p->family < CHIP_CAYMAN) { DRM_ERROR("L2T, T2L Partial is cayman only !\n"); return -EINVAL; @@ -3089,6 +3108,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 7: /* L2T, broadcast */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 9); if (idx_value & (1 << 31)) { DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); return -EINVAL; @@ -3132,6 +3153,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) } else { switch (misc) { case 0: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 8); /* detile bit */ if (idx_value & (1 << 31)) { /* tiled src, linear dst */ @@ -3176,6 +3199,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) switch (misc) { case 0: /* L2L, byte */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; dst_offset = ib[idx+1]; @@ -3198,6 +3223,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 1: /* L2L, partial */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 8); if (p->family < CHIP_CAYMAN) { DRM_ERROR("L2L Partial is cayman only !\n"); return -EINVAL; @@ -3211,6 +3238,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; case 4: /* L2L, dw, broadcast */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 6); r = r600_dma_cs_next_reloc(p, &dst2_reloc); if (r) { DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n"); @@ -3251,6 +3280,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) } } else { /* L2L, dw */ + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; dst_offset = ib[idx+1]; @@ -3274,6 +3305,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) } break; case DMA_PACKET_CONSTANT_FILL: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 3); r = r600_dma_cs_next_reloc(p, &dst_reloc); if (r) { DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 69ec24a..d36f9e6 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -796,7 +796,7 @@ static int r600_cs_packet_parse(struct radeon_cs_parser *p, unsigned idx) { struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; - uint32_t header; + uint32_t header, i, npages; if (idx >= ib_chunk->length_dw) { DRM_ERROR("Can not parse packet at %d after CS end %d !\n", @@ -827,6 +827,11 @@ static int r600_cs_packet_parse(struct radeon_cs_parser *p, pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); return -EINVAL; } + /* make sure we copied packet fully from userspace */ + npages = ((idx + pkt->count + 1) >> 10) - (idx >> 10); + for (i = 1; i <= npages; i++) { + radeon_get_ib_value(p, (idx & 0xfffffc00) + i * 0x400); + } return 0; } @@ -2623,12 +2628,16 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) return -EINVAL; } if (tiled) { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); dst_offset = ib[idx+1]; dst_offset <<= 8; ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); p->idx += count + 5; } else { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 2); dst_offset = ib[idx+1]; dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; @@ -2654,6 +2663,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) return -EINVAL; } if (tiled) { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 6); idx_value = radeon_get_ib_value(p, idx + 2); /* detile bit */ if (idx_value & (1 << 31)) { @@ -2680,6 +2691,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) p->idx += 7; } else { if (p->family >= CHIP_RV770) { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; dst_offset = ib[idx+1]; @@ -2691,6 +2704,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; p->idx += 5; } else { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 3); src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; dst_offset = ib[idx+1]; @@ -2715,6 +2730,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) } break; case DMA_PACKET_CONSTANT_FILL: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 3); if (p->family < CHIP_RV770) { DRM_ERROR("Constant Fill is 7xx only !\n"); return -EINVAL;