drm: fix a LOR issue on FreeBSD for savage driver

Correct a LOR issue on FreeBSD by allocating temporary space and doing a single
DRM_COPY_FROM_USER rather than DRM_VERIFYAREA_READ followed by tons of
DRM_COPY_FROM_USER_UNCHECKED. I don't like the look of the temporary space
allocation, but I like the simplification in the rest of the file. Tested
with glxgears, tuxracer, and q3 on a savage4.

From: Eric Anholt <anholt@freebsd.org>
Signed-off-by: Dave Airlie <airlied@linux.ie>

authored by Dave Airlie and committed by Dave Airlie 3528af1b 952d751a

+171 -176
+7 -16
drivers/char/drm/savage_drv.h
··· 1 - /* savage_drv.h -- Private header for the savage driver 2 - * 1 + /* savage_drv.h -- Private header for the savage driver */ 2 + /* 3 3 * Copyright 2004 Felix Kuehling 4 4 * All Rights Reserved. 5 5 * ··· 192 192 /* Err, there is a macro wait_event in include/linux/wait.h. 193 193 * Avoid unwanted macro expansion. */ 194 194 void (*emit_clip_rect) (struct drm_savage_private * dev_priv, 195 - drm_clip_rect_t * pbox); 195 + const drm_clip_rect_t * pbox); 196 196 void (*dma_flush) (struct drm_savage_private * dev_priv); 197 197 } drm_savage_private_t; 198 198 ··· 217 217 218 218 /* state functions */ 219 219 extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, 220 - drm_clip_rect_t * pbox); 220 + const drm_clip_rect_t * pbox); 221 221 extern void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, 222 - drm_clip_rect_t * pbox); 222 + const drm_clip_rect_t * pbox); 223 223 224 224 #define SAVAGE_FB_SIZE_S3 0x01000000 /* 16MB */ 225 225 #define SAVAGE_FB_SIZE_S4 0x02000000 /* 32MB */ ··· 502 502 503 503 #define BCI_WRITE( val ) *bci_ptr++ = (uint32_t)(val) 504 504 505 - #define BCI_COPY_FROM_USER(src,n) do { \ 506 - unsigned int i; \ 507 - for (i = 0; i < n; ++i) { \ 508 - uint32_t val; \ 509 - DRM_GET_USER_UNCHECKED(val, &((uint32_t*)(src))[i]); \ 510 - BCI_WRITE(val); \ 511 - } \ 512 - } while(0) 513 - 514 505 /* 515 506 * command DMA support 516 507 */ ··· 527 536 528 537 #define DMA_WRITE( val ) *dma_ptr++ = (uint32_t)(val) 529 538 530 - #define DMA_COPY_FROM_USER(src,n) do { \ 531 - DRM_COPY_FROM_USER_UNCHECKED(dma_ptr, (src), (n)*4); \ 539 + #define DMA_COPY(src, n) do { \ 540 + memcpy(dma_ptr, (src), (n)*4); \ 532 541 dma_ptr += n; \ 533 542 } while(0) 534 543
+164 -160
drivers/char/drm/savage_state.c
··· 27 27 #include "savage_drv.h" 28 28 29 29 void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, 30 - drm_clip_rect_t * pbox) 30 + const drm_clip_rect_t * pbox) 31 31 { 32 32 uint32_t scstart = dev_priv->state.s3d.new_scstart; 33 33 uint32_t scend = dev_priv->state.s3d.new_scend; ··· 53 53 } 54 54 55 55 void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, 56 - drm_clip_rect_t * pbox) 56 + const drm_clip_rect_t * pbox) 57 57 { 58 58 uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0; 59 59 uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1; ··· 115 115 116 116 #define SAVE_STATE(reg,where) \ 117 117 if(start <= reg && start+count > reg) \ 118 - DRM_GET_USER_UNCHECKED(dev_priv->state.where, &regs[reg-start]) 118 + dev_priv->state.where = regs[reg - start] 119 119 #define SAVE_STATE_MASK(reg,where,mask) do { \ 120 120 if(start <= reg && start+count > reg) { \ 121 121 uint32_t tmp; \ 122 - DRM_GET_USER_UNCHECKED(tmp, &regs[reg-start]); \ 122 + tmp = regs[reg - start]; \ 123 123 dev_priv->state.where = (tmp & (mask)) | \ 124 124 (dev_priv->state.where & ~(mask)); \ 125 125 } \ 126 126 } while (0) 127 + 127 128 static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, 128 129 unsigned int start, unsigned int count, 129 - const uint32_t __user * regs) 130 + const uint32_t *regs) 130 131 { 131 132 if (start < SAVAGE_TEXPALADDR_S3D || 132 133 start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { ··· 149 148 SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr); 150 149 if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK) 151 150 return savage_verify_texaddr(dev_priv, 0, 152 - dev_priv->state.s3d. 153 - texaddr); 151 + dev_priv->state.s3d.texaddr); 154 152 } 155 153 156 154 return 0; ··· 157 157 158 158 static int savage_verify_state_s4(drm_savage_private_t * dev_priv, 159 159 unsigned int start, unsigned int count, 160 - const uint32_t __user * regs) 160 + const uint32_t *regs) 161 161 { 162 162 int ret = 0; 163 163 ··· 174 174 ~SAVAGE_SCISSOR_MASK_S4); 175 175 176 176 /* if any texture regs were changed ... */ 177 - if (start <= SAVAGE_TEXDESCR_S4 && start + count > SAVAGE_TEXPALADDR_S4) { 177 + if (start <= SAVAGE_TEXDESCR_S4 && 178 + start + count > SAVAGE_TEXPALADDR_S4) { 178 179 /* ... check texture state */ 179 180 SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr); 180 181 SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0); 181 182 SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1); 182 183 if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK) 183 - ret |= 184 - savage_verify_texaddr(dev_priv, 0, 185 - dev_priv->state.s4.texaddr0); 184 + ret |= savage_verify_texaddr(dev_priv, 0, 185 + dev_priv->state.s4.texaddr0); 186 186 if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK) 187 - ret |= 188 - savage_verify_texaddr(dev_priv, 1, 189 - dev_priv->state.s4.texaddr1); 187 + ret |= savage_verify_texaddr(dev_priv, 1, 188 + dev_priv->state.s4.texaddr1); 190 189 } 191 190 192 191 return ret; ··· 196 197 197 198 static int savage_dispatch_state(drm_savage_private_t * dev_priv, 198 199 const drm_savage_cmd_header_t * cmd_header, 199 - const uint32_t __user * regs) 200 + const uint32_t *regs) 200 201 { 201 202 unsigned int count = cmd_header->state.count; 202 203 unsigned int start = cmd_header->state.start; ··· 207 208 208 209 if (!count) 209 210 return 0; 210 - 211 - if (DRM_VERIFYAREA_READ(regs, count * 4)) 212 - return DRM_ERR(EFAULT); 213 211 214 212 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 215 213 ret = savage_verify_state_s3d(dev_priv, start, count, regs); ··· 232 236 /* scissor regs are emitted in savage_dispatch_draw */ 233 237 if (start < SAVAGE_DRAWCTRL0_S4) { 234 238 if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) 235 - count2 = 236 - count - (SAVAGE_DRAWCTRL1_S4 + 1 - start); 239 + count2 = count - 240 + (SAVAGE_DRAWCTRL1_S4 + 1 - start); 237 241 if (start + count > SAVAGE_DRAWCTRL0_S4) 238 242 count = SAVAGE_DRAWCTRL0_S4 - start; 239 243 } else if (start <= SAVAGE_DRAWCTRL1_S4) { ··· 259 263 while (count > 0) { 260 264 unsigned int n = count < 255 ? count : 255; 261 265 DMA_SET_REGISTERS(start, n); 262 - DMA_COPY_FROM_USER(regs, n); 266 + DMA_COPY(regs, n); 263 267 count -= n; 264 268 start += n; 265 269 regs += n; ··· 417 421 418 422 static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, 419 423 const drm_savage_cmd_header_t * cmd_header, 420 - const uint32_t __user * vtxbuf, 421 - unsigned int vb_size, unsigned int vb_stride) 424 + const uint32_t *vtxbuf, unsigned int vb_size, 425 + unsigned int vb_stride) 422 426 { 423 427 unsigned char reorder = 0; 424 428 unsigned int prim = cmd_header->prim.prim; ··· 503 507 504 508 for (i = start; i < start + count; ++i) { 505 509 unsigned int j = i + reorder[i % 3]; 506 - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * j], 507 - vtx_size); 510 + DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 508 511 } 509 512 510 513 DMA_COMMIT(); ··· 512 517 DMA_DRAW_PRIMITIVE(count, prim, skip); 513 518 514 519 if (vb_stride == vtx_size) { 515 - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * start], 516 - vtx_size * count); 520 + DMA_COPY(&vtxbuf[vb_stride * start], 521 + vtx_size * count); 517 522 } else { 518 523 for (i = start; i < start + count; ++i) { 519 - DMA_COPY_FROM_USER(&vtxbuf 520 - [vb_stride * i], 521 - vtx_size); 524 + DMA_COPY(&vtxbuf [vb_stride * i], 525 + vtx_size); 522 526 } 523 527 } 524 528 ··· 535 541 536 542 static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, 537 543 const drm_savage_cmd_header_t * cmd_header, 538 - const uint16_t __user * usr_idx, 544 + const uint16_t *idx, 539 545 const drm_buf_t * dmabuf) 540 546 { 541 547 unsigned char reorder = 0; ··· 622 628 while (n != 0) { 623 629 /* Can emit up to 255 indices (85 triangles) at once. */ 624 630 unsigned int count = n > 255 ? 255 : n; 625 - /* Is it ok to allocate 510 bytes on the stack in an ioctl? */ 626 - uint16_t idx[255]; 627 631 628 - /* Copy and check indices */ 629 - DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count * 2); 632 + /* check indices */ 630 633 for (i = 0; i < count; ++i) { 631 634 if (idx[i] > dmabuf->total / 32) { 632 635 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", ··· 643 652 644 653 for (i = 1; i + 1 < count; i += 2) 645 654 BCI_WRITE(idx[i + reorder[i % 3]] | 646 - (idx[i + 1 + reorder[(i + 1) % 3]] << 647 - 16)); 655 + (idx[i + 1 + 656 + reorder[(i + 1) % 3]] << 16)); 648 657 if (i < count) 649 658 BCI_WRITE(idx[i + reorder[i % 3]]); 650 659 } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { ··· 665 674 BCI_WRITE(idx[i]); 666 675 } 667 676 668 - usr_idx += count; 677 + idx += count; 669 678 n -= count; 670 679 671 680 prim |= BCI_CMD_DRAW_CONT; ··· 676 685 677 686 static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, 678 687 const drm_savage_cmd_header_t * cmd_header, 679 - const uint16_t __user * usr_idx, 680 - const uint32_t __user * vtxbuf, 688 + const uint16_t *idx, 689 + const uint32_t *vtxbuf, 681 690 unsigned int vb_size, unsigned int vb_stride) 682 691 { 683 692 unsigned char reorder = 0; ··· 742 751 while (n != 0) { 743 752 /* Can emit up to 255 vertices (85 triangles) at once. */ 744 753 unsigned int count = n > 255 ? 255 : n; 745 - /* Is it ok to allocate 510 bytes on the stack in an ioctl? */ 746 - uint16_t idx[255]; 747 - 748 - /* Copy and check indices */ 749 - DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count * 2); 754 + 755 + /* Check indices */ 750 756 for (i = 0; i < count; ++i) { 751 757 if (idx[i] > vb_size / (vb_stride * 4)) { 752 758 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", ··· 763 775 764 776 for (i = 0; i < count; ++i) { 765 777 unsigned int j = idx[i + reorder[i % 3]]; 766 - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * j], 767 - vtx_size); 778 + DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 768 779 } 769 780 770 781 DMA_COMMIT(); ··· 773 786 774 787 for (i = 0; i < count; ++i) { 775 788 unsigned int j = idx[i]; 776 - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * j], 777 - vtx_size); 789 + DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 778 790 } 779 791 780 792 DMA_COMMIT(); 781 793 } 782 794 783 - usr_idx += count; 795 + idx += count; 784 796 n -= count; 785 797 786 798 prim |= BCI_CMD_DRAW_CONT; ··· 790 804 791 805 static int savage_dispatch_clear(drm_savage_private_t * dev_priv, 792 806 const drm_savage_cmd_header_t * cmd_header, 793 - const drm_savage_cmd_header_t __user * data, 807 + const drm_savage_cmd_header_t *data, 794 808 unsigned int nbox, 795 - const drm_clip_rect_t __user * usr_boxes) 809 + const drm_clip_rect_t *boxes) 796 810 { 797 - unsigned int flags = cmd_header->clear0.flags, mask, value; 811 + unsigned int flags = cmd_header->clear0.flags; 798 812 unsigned int clear_cmd; 799 813 unsigned int i, nbufs; 800 814 DMA_LOCALS; 801 815 802 816 if (nbox == 0) 803 817 return 0; 804 - 805 - DRM_GET_USER_UNCHECKED(mask, &data->clear1.mask); 806 - DRM_GET_USER_UNCHECKED(value, &data->clear1.value); 807 818 808 819 clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 809 820 BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW; ··· 811 828 if (nbufs == 0) 812 829 return 0; 813 830 814 - if (mask != 0xffffffff) { 831 + if (data->clear1.mask != 0xffffffff) { 815 832 /* set mask */ 816 833 BEGIN_DMA(2); 817 834 DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 818 - DMA_WRITE(mask); 835 + DMA_WRITE(data->clear1.mask); 819 836 DMA_COMMIT(); 820 837 } 821 838 for (i = 0; i < nbox; ++i) { 822 - drm_clip_rect_t box; 823 839 unsigned int x, y, w, h; 824 840 unsigned int buf; 825 - DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box)); 826 - x = box.x1, y = box.y1; 827 - w = box.x2 - box.x1; 828 - h = box.y2 - box.y1; 841 + x = boxes[i].x1, y = boxes[i].y1; 842 + w = boxes[i].x2 - boxes[i].x1; 843 + h = boxes[i].y2 - boxes[i].y1; 829 844 BEGIN_DMA(nbufs * 6); 830 845 for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) { 831 846 if (!(flags & buf)) ··· 843 862 DMA_WRITE(dev_priv->depth_bd); 844 863 break; 845 864 } 846 - DMA_WRITE(value); 865 + DMA_WRITE(data->clear1.value); 847 866 DMA_WRITE(BCI_X_Y(x, y)); 848 867 DMA_WRITE(BCI_W_H(w, h)); 849 868 } 850 869 DMA_COMMIT(); 851 870 } 852 - if (mask != 0xffffffff) { 871 + if (data->clear1.mask != 0xffffffff) { 853 872 /* reset mask */ 854 873 BEGIN_DMA(2); 855 874 DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); ··· 861 880 } 862 881 863 882 static int savage_dispatch_swap(drm_savage_private_t * dev_priv, 864 - unsigned int nbox, 865 - const drm_clip_rect_t __user * usr_boxes) 883 + unsigned int nbox, const drm_clip_rect_t *boxes) 866 884 { 867 885 unsigned int swap_cmd; 868 886 unsigned int i; ··· 875 895 BCI_CMD_SET_ROP(swap_cmd, 0xCC); 876 896 877 897 for (i = 0; i < nbox; ++i) { 878 - drm_clip_rect_t box; 879 - DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box)); 880 - 881 898 BEGIN_DMA(6); 882 899 DMA_WRITE(swap_cmd); 883 900 DMA_WRITE(dev_priv->back_offset); 884 901 DMA_WRITE(dev_priv->back_bd); 885 - DMA_WRITE(BCI_X_Y(box.x1, box.y1)); 886 - DMA_WRITE(BCI_X_Y(box.x1, box.y1)); 887 - DMA_WRITE(BCI_W_H(box.x2 - box.x1, box.y2 - box.y1)); 902 + DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 903 + DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 904 + DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1, 905 + boxes[i].y2 - boxes[i].y1)); 888 906 DMA_COMMIT(); 889 907 } 890 908 ··· 890 912 } 891 913 892 914 static int savage_dispatch_draw(drm_savage_private_t * dev_priv, 893 - const drm_savage_cmd_header_t __user * start, 894 - const drm_savage_cmd_header_t __user * end, 915 + const drm_savage_cmd_header_t *start, 916 + const drm_savage_cmd_header_t *end, 895 917 const drm_buf_t * dmabuf, 896 - const unsigned int __user * usr_vtxbuf, 918 + const unsigned int *vtxbuf, 897 919 unsigned int vb_size, unsigned int vb_stride, 898 920 unsigned int nbox, 899 - const drm_clip_rect_t __user * usr_boxes) 921 + const drm_clip_rect_t *boxes) 900 922 { 901 923 unsigned int i, j; 902 924 int ret; 903 925 904 926 for (i = 0; i < nbox; ++i) { 905 - drm_clip_rect_t box; 906 - const drm_savage_cmd_header_t __user *usr_cmdbuf; 907 - DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box)); 908 - dev_priv->emit_clip_rect(dev_priv, &box); 927 + const drm_savage_cmd_header_t *cmdbuf; 928 + dev_priv->emit_clip_rect(dev_priv, &boxes[i]); 909 929 910 - usr_cmdbuf = start; 911 - while (usr_cmdbuf < end) { 930 + cmdbuf = start; 931 + while (cmdbuf < end) { 912 932 drm_savage_cmd_header_t cmd_header; 913 - DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf, 914 - sizeof(cmd_header)); 915 - usr_cmdbuf++; 933 + cmd_header = *cmdbuf; 934 + cmdbuf++; 916 935 switch (cmd_header.cmd.cmd) { 917 936 case SAVAGE_CMD_DMA_PRIM: 918 - ret = 919 - savage_dispatch_dma_prim(dev_priv, 920 - &cmd_header, 921 - dmabuf); 937 + ret = savage_dispatch_dma_prim( 938 + dev_priv, &cmd_header, dmabuf); 922 939 break; 923 940 case SAVAGE_CMD_VB_PRIM: 924 - ret = 925 - savage_dispatch_vb_prim(dev_priv, 926 - &cmd_header, 927 - (const uint32_t 928 - __user *) 929 - usr_vtxbuf, vb_size, 930 - vb_stride); 941 + ret = savage_dispatch_vb_prim( 942 + dev_priv, &cmd_header, 943 + vtxbuf, vb_size, vb_stride); 931 944 break; 932 945 case SAVAGE_CMD_DMA_IDX: 933 946 j = (cmd_header.idx.count + 3) / 4; 934 947 /* j was check in savage_bci_cmdbuf */ 935 - ret = 936 - savage_dispatch_dma_idx(dev_priv, 937 - &cmd_header, 938 - (const uint16_t 939 - __user *) 940 - usr_cmdbuf, dmabuf); 941 - usr_cmdbuf += j; 948 + ret = savage_dispatch_dma_idx(dev_priv, 949 + &cmd_header, (const uint16_t *)cmdbuf, 950 + dmabuf); 951 + cmdbuf += j; 942 952 break; 943 953 case SAVAGE_CMD_VB_IDX: 944 954 j = (cmd_header.idx.count + 3) / 4; 945 955 /* j was check in savage_bci_cmdbuf */ 946 - ret = 947 - savage_dispatch_vb_idx(dev_priv, 948 - &cmd_header, 949 - (const uint16_t 950 - __user *)usr_cmdbuf, 951 - (const uint32_t 952 - __user *)usr_vtxbuf, 953 - vb_size, vb_stride); 954 - usr_cmdbuf += j; 956 + ret = savage_dispatch_vb_idx(dev_priv, 957 + &cmd_header, (const uint16_t *)cmdbuf, 958 + (const uint32_t *)vtxbuf, vb_size, 959 + vb_stride); 960 + cmdbuf += j; 955 961 break; 956 962 default: 957 963 /* What's the best return code? EFAULT? */ ··· 960 998 drm_device_dma_t *dma = dev->dma; 961 999 drm_buf_t *dmabuf; 962 1000 drm_savage_cmdbuf_t cmdbuf; 963 - drm_savage_cmd_header_t __user *usr_cmdbuf; 964 - drm_savage_cmd_header_t __user *first_draw_cmd; 965 - unsigned int __user *usr_vtxbuf; 966 - drm_clip_rect_t __user *usr_boxes; 1001 + drm_savage_cmd_header_t *kcmd_addr = NULL; 1002 + drm_savage_cmd_header_t *first_draw_cmd; 1003 + unsigned int *kvb_addr = NULL; 1004 + drm_clip_rect_t *kbox_addr = NULL; 967 1005 unsigned int i, j; 968 1006 int ret = 0; 969 1007 ··· 986 1024 dmabuf = NULL; 987 1025 } 988 1026 989 - usr_cmdbuf = (drm_savage_cmd_header_t __user *) cmdbuf.cmd_addr; 990 - usr_vtxbuf = (unsigned int __user *)cmdbuf.vb_addr; 991 - usr_boxes = (drm_clip_rect_t __user *) cmdbuf.box_addr; 992 - if ((cmdbuf.size && DRM_VERIFYAREA_READ(usr_cmdbuf, cmdbuf.size * 8)) || 993 - (cmdbuf.vb_size && DRM_VERIFYAREA_READ(usr_vtxbuf, cmdbuf.vb_size)) 994 - || (cmdbuf.nbox 995 - && DRM_VERIFYAREA_READ(usr_boxes, 996 - cmdbuf.nbox * sizeof(drm_clip_rect_t)))) 997 - return DRM_ERR(EFAULT); 1027 + /* Copy the user buffers into kernel temporary areas. This hasn't been 1028 + * a performance loss compared to VERIFYAREA_READ/ 1029 + * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct 1030 + * for locking on FreeBSD. 1031 + */ 1032 + if (cmdbuf.size) { 1033 + kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); 1034 + if (kcmd_addr == NULL) 1035 + return ENOMEM; 1036 + 1037 + if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, 1038 + cmdbuf.size * 8)) 1039 + { 1040 + drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); 1041 + return DRM_ERR(EFAULT); 1042 + } 1043 + cmdbuf.cmd_addr = kcmd_addr; 1044 + } 1045 + if (cmdbuf.vb_size) { 1046 + kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER); 1047 + if (kvb_addr == NULL) { 1048 + ret = DRM_ERR(ENOMEM); 1049 + goto done; 1050 + } 1051 + 1052 + if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr, 1053 + cmdbuf.vb_size)) { 1054 + ret = DRM_ERR(EFAULT); 1055 + goto done; 1056 + } 1057 + cmdbuf.vb_addr = kvb_addr; 1058 + } 1059 + if (cmdbuf.nbox) { 1060 + kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(drm_clip_rect_t), 1061 + DRM_MEM_DRIVER); 1062 + if (kbox_addr == NULL) { 1063 + ret = DRM_ERR(ENOMEM); 1064 + goto done; 1065 + } 1066 + 1067 + if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr, 1068 + cmdbuf.nbox * sizeof(drm_clip_rect_t))) { 1069 + ret = DRM_ERR(EFAULT); 1070 + goto done; 1071 + } 1072 + cmdbuf.box_addr = kbox_addr; 1073 + } 998 1074 999 1075 /* Make sure writes to DMA buffers are finished before sending 1000 1076 * DMA commands to the graphics hardware. */ ··· 1046 1046 first_draw_cmd = NULL; 1047 1047 while (i < cmdbuf.size) { 1048 1048 drm_savage_cmd_header_t cmd_header; 1049 - DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf, 1050 - sizeof(cmd_header)); 1051 - usr_cmdbuf++; 1049 + cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr; 1050 + cmdbuf.cmd_addr++; 1052 1051 i++; 1053 1052 1054 1053 /* Group drawing commands with same state to minimize ··· 1067 1068 case SAVAGE_CMD_DMA_PRIM: 1068 1069 case SAVAGE_CMD_VB_PRIM: 1069 1070 if (!first_draw_cmd) 1070 - first_draw_cmd = usr_cmdbuf - 1; 1071 - usr_cmdbuf += j; 1071 + first_draw_cmd = cmdbuf.cmd_addr - 1; 1072 + cmdbuf.cmd_addr += j; 1072 1073 i += j; 1073 1074 break; 1074 1075 default: 1075 1076 if (first_draw_cmd) { 1076 - ret = 1077 - savage_dispatch_draw(dev_priv, 1078 - first_draw_cmd, 1079 - usr_cmdbuf - 1, dmabuf, 1080 - usr_vtxbuf, 1081 - cmdbuf.vb_size, 1082 - cmdbuf.vb_stride, 1083 - cmdbuf.nbox, 1084 - usr_boxes); 1077 + ret = savage_dispatch_draw( 1078 + dev_priv, first_draw_cmd, 1079 + cmdbuf.cmd_addr - 1, 1080 + dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size, 1081 + cmdbuf.vb_stride, 1082 + cmdbuf.nbox, cmdbuf.box_addr); 1085 1083 if (ret != 0) 1086 1084 return ret; 1087 1085 first_draw_cmd = NULL; ··· 1094 1098 DRM_ERROR("command SAVAGE_CMD_STATE extends " 1095 1099 "beyond end of command buffer\n"); 1096 1100 DMA_FLUSH(); 1097 - return DRM_ERR(EINVAL); 1101 + ret = DRM_ERR(EINVAL); 1102 + goto done; 1098 1103 } 1099 1104 ret = savage_dispatch_state(dev_priv, &cmd_header, 1100 - (uint32_t __user *) 1101 - usr_cmdbuf); 1102 - usr_cmdbuf += j; 1105 + (const uint32_t *)cmdbuf.cmd_addr); 1106 + cmdbuf.cmd_addr += j; 1103 1107 i += j; 1104 1108 break; 1105 1109 case SAVAGE_CMD_CLEAR: ··· 1107 1111 DRM_ERROR("command SAVAGE_CMD_CLEAR extends " 1108 1112 "beyond end of command buffer\n"); 1109 1113 DMA_FLUSH(); 1110 - return DRM_ERR(EINVAL); 1114 + ret = DRM_ERR(EINVAL); 1115 + goto done; 1111 1116 } 1112 1117 ret = savage_dispatch_clear(dev_priv, &cmd_header, 1113 - usr_cmdbuf, 1114 - cmdbuf.nbox, usr_boxes); 1115 - usr_cmdbuf++; 1118 + cmdbuf.cmd_addr, 1119 + cmdbuf.nbox, cmdbuf.box_addr); 1120 + cmdbuf.cmd_addr++; 1116 1121 i++; 1117 1122 break; 1118 1123 case SAVAGE_CMD_SWAP: 1119 - ret = savage_dispatch_swap(dev_priv, 1120 - cmdbuf.nbox, usr_boxes); 1124 + ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox, 1125 + cmdbuf.box_addr); 1121 1126 break; 1122 1127 default: 1123 1128 DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd); 1124 1129 DMA_FLUSH(); 1125 - return DRM_ERR(EINVAL); 1130 + ret = DRM_ERR(EINVAL); 1131 + goto done; 1126 1132 } 1127 1133 1128 1134 if (ret != 0) { 1129 1135 DMA_FLUSH(); 1130 - return ret; 1136 + goto done; 1131 1137 } 1132 1138 } 1133 1139 1134 1140 if (first_draw_cmd) { 1135 - ret = 1136 - savage_dispatch_draw(dev_priv, first_draw_cmd, usr_cmdbuf, 1137 - dmabuf, usr_vtxbuf, cmdbuf.vb_size, 1138 - cmdbuf.vb_stride, cmdbuf.nbox, 1139 - usr_boxes); 1141 + ret = savage_dispatch_draw ( 1142 + dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf, 1143 + cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride, 1144 + cmdbuf.nbox, cmdbuf.box_addr); 1140 1145 if (ret != 0) { 1141 1146 DMA_FLUSH(); 1142 - return ret; 1147 + goto done; 1143 1148 } 1144 1149 } 1145 1150 ··· 1154 1157 savage_freelist_put(dev, dmabuf); 1155 1158 } 1156 1159 1157 - return 0; 1160 + done: 1161 + /* If we didn't need to allocate them, these'll be NULL */ 1162 + drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); 1163 + drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER); 1164 + drm_free(kbox_addr, cmdbuf.nbox * sizeof(drm_clip_rect_t), 1165 + DRM_MEM_DRIVER); 1166 + 1167 + return ret; 1158 1168 }