From patchwork Fri Feb 8 23:13:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Glisse X-Patchwork-Id: 2118871 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id DF390DFE75 for ; Fri, 8 Feb 2013 23:14:07 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5DCE8E60F1 for ; Fri, 8 Feb 2013 15:14:07 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-ve0-f179.google.com (mail-ve0-f179.google.com [209.85.128.179]) by gabe.freedesktop.org (Postfix) with ESMTP id C3C46E5C0E for ; Fri, 8 Feb 2013 15:13:55 -0800 (PST) Received: by mail-ve0-f179.google.com with SMTP id da11so3744331veb.38 for ; Fri, 08 Feb 2013 15:13:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer; bh=8LXg5yIPeqx4QX6zxvv6ztvdG4WzDJ8xGINTySgoGXc=; b=neIxlGE6OI5t51EjjZGfei9S1XIfNluHqyy94cfa2lthZBUQe8TYuFJPUiWmuL5lrT Sr+EtH5oFEXvHtdFxFecgDcIGA+2iDihj7EWhY0VF5W8sYv0jYpgp4phnA7OQh1zcjI9 0F1cuYBpnYFCdyIg23Za35+avyU2yRfOCP5R3ApHhrkWkzkzgOYbZ79jUSpmwzwZe+8L 5Ye1NAO1KafiEW944dxrgAuQQrLxetAKesV0hA8o7+zmfNp8wEK8rx+0jE9IZtkSce4B 4ckjyg+Fm6Kfa8q3Sf9pvUeWIjlYeapbmYhhVq5MYPX9MpXp7NFS7DJd94Vq2BxxiTtU VgPg== X-Received: by 10.52.21.146 with SMTP id v18mr7819162vde.79.1360365235231; Fri, 08 Feb 2013 15:13:55 -0800 (PST) Received: from homer.localdomain (c-66-31-46-242.hsd1.ma.comcast.net. [66.31.46.242]) by mx.google.com with ESMTPS id cl9sm46416816vdb.3.2013.02.08.15.13.54 (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 08 Feb 2013 15:13:54 -0800 (PST) From: j.glisse@gmail.com To: dri-devel@lists.freedesktop.org Subject: [PATCH] drm/radeon: copy userspace cmd to local copy before processing it v3 Date: Fri, 8 Feb 2013 18:13:50 -0500 Message-Id: <1360365230-19922-1-git-send-email-j.glisse@gmail.com> X-Mailer: git-send-email 1.7.11.7 Cc: Jerome Glisse X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org From: Jerome Glisse 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 Reviewed-by: Alex Deucher --- 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;