[PATCH] drm/radeon: copy userspace cmd to local copy before processing it v3
Alex Deucher
alexdeucher at gmail.com
Fri Feb 8 15:15:10 PST 2013
On Fri, Feb 8, 2013 at 6:13 PM, <j.glisse at gmail.com> wrote:
> From: Jerome Glisse <jglisse at 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 at redhat.com>
Reviewed-by: Alex Deucher <alexander.deucher at 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list