aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorYoungJun Cho <yj44.cho@samsung.com>2013-03-11 08:17:52 -0400
committerInki Dae <inki.dae@samsung.com>2013-03-20 06:09:11 -0400
commit2dec17c70e7567f226331c26d8daa0c16d3e7e6d (patch)
tree4438cf80d988b7aa6fedda3104c8e669eb56d699 /drivers/gpu
parenta4f19aaab3e69f9d15cc995e3378d27c8ef4f780 (diff)
drm/exynos: Check g2d cmd list for g2d restrictions
This patch checks command list from user for g2d restrictions. For now, g2d driver wasn't considered for G2D hardware restrictions properly. The below is the restrictions to G2D hardware and this patch considers them. - width or height value in the command list has to be in valid range (1 to 8000 pixels) - The requested area should be less than buffer size. - right has to be bigger than left. - bottom has to be bigger than top. Changelog v2: - Fix merge conflict. Signed-off-by: YoungJun Cho <yj44.cho@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 1a022dc4188e..47a493c8a71f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -48,8 +48,14 @@
48 48
49/* registers for base address */ 49/* registers for base address */
50#define G2D_SRC_BASE_ADDR 0x0304 50#define G2D_SRC_BASE_ADDR 0x0304
51#define G2D_SRC_COLOR_MODE 0x030C
52#define G2D_SRC_LEFT_TOP 0x0310
53#define G2D_SRC_RIGHT_BOTTOM 0x0314
51#define G2D_SRC_PLANE2_BASE_ADDR 0x0318 54#define G2D_SRC_PLANE2_BASE_ADDR 0x0318
52#define G2D_DST_BASE_ADDR 0x0404 55#define G2D_DST_BASE_ADDR 0x0404
56#define G2D_DST_COLOR_MODE 0x040C
57#define G2D_DST_LEFT_TOP 0x0410
58#define G2D_DST_RIGHT_BOTTOM 0x0414
53#define G2D_DST_PLANE2_BASE_ADDR 0x0418 59#define G2D_DST_PLANE2_BASE_ADDR 0x0418
54#define G2D_PAT_BASE_ADDR 0x0500 60#define G2D_PAT_BASE_ADDR 0x0500
55#define G2D_MSK_BASE_ADDR 0x0520 61#define G2D_MSK_BASE_ADDR 0x0520
@@ -91,6 +97,22 @@
91#define G2D_START_NHOLT (1 << 1) 97#define G2D_START_NHOLT (1 << 1)
92#define G2D_START_BITBLT (1 << 0) 98#define G2D_START_BITBLT (1 << 0)
93 99
100/* buffer color format */
101#define G2D_FMT_XRGB8888 0
102#define G2D_FMT_ARGB8888 1
103#define G2D_FMT_RGB565 2
104#define G2D_FMT_XRGB1555 3
105#define G2D_FMT_ARGB1555 4
106#define G2D_FMT_XRGB4444 5
107#define G2D_FMT_ARGB4444 6
108#define G2D_FMT_PACKED_RGB888 7
109#define G2D_FMT_A8 11
110#define G2D_FMT_L8 12
111
112/* buffer valid length */
113#define G2D_LEN_MIN 1
114#define G2D_LEN_MAX 8000
115
94#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) 116#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4)
95#define G2D_CMDLIST_NUM 64 117#define G2D_CMDLIST_NUM 64
96#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) 118#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
@@ -123,12 +145,31 @@ struct g2d_cmdlist {
123}; 145};
124 146
125/* 147/*
148 * A structure of buffer description
149 *
150 * @format: color format
151 * @left_x: the x coordinates of left top corner
152 * @top_y: the y coordinates of left top corner
153 * @right_x: the x coordinates of right bottom corner
154 * @bottom_y: the y coordinates of right bottom corner
155 *
156 */
157struct g2d_buf_desc {
158 unsigned int format;
159 unsigned int left_x;
160 unsigned int top_y;
161 unsigned int right_x;
162 unsigned int bottom_y;
163};
164
165/*
126 * A structure of buffer information 166 * A structure of buffer information
127 * 167 *
128 * @map_nr: manages the number of mapped buffers 168 * @map_nr: manages the number of mapped buffers
129 * @reg_types: stores regitster type in the order of requested command 169 * @reg_types: stores regitster type in the order of requested command
130 * @handles: stores buffer handle in its reg_type position 170 * @handles: stores buffer handle in its reg_type position
131 * @types: stores buffer type in its reg_type position 171 * @types: stores buffer type in its reg_type position
172 * @descs: stores buffer description in its reg_type position
132 * 173 *
133 */ 174 */
134struct g2d_buf_info { 175struct g2d_buf_info {
@@ -136,6 +177,7 @@ struct g2d_buf_info {
136 enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; 177 enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
137 unsigned long handles[MAX_REG_TYPE_NR]; 178 unsigned long handles[MAX_REG_TYPE_NR];
138 unsigned int types[MAX_REG_TYPE_NR]; 179 unsigned int types[MAX_REG_TYPE_NR];
180 struct g2d_buf_desc descs[MAX_REG_TYPE_NR];
139}; 181};
140 182
141struct drm_exynos_pending_g2d_event { 183struct drm_exynos_pending_g2d_event {
@@ -543,12 +585,18 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
543 585
544 switch (reg_offset) { 586 switch (reg_offset) {
545 case G2D_SRC_BASE_ADDR: 587 case G2D_SRC_BASE_ADDR:
588 case G2D_SRC_COLOR_MODE:
589 case G2D_SRC_LEFT_TOP:
590 case G2D_SRC_RIGHT_BOTTOM:
546 reg_type = REG_TYPE_SRC; 591 reg_type = REG_TYPE_SRC;
547 break; 592 break;
548 case G2D_SRC_PLANE2_BASE_ADDR: 593 case G2D_SRC_PLANE2_BASE_ADDR:
549 reg_type = REG_TYPE_SRC_PLANE2; 594 reg_type = REG_TYPE_SRC_PLANE2;
550 break; 595 break;
551 case G2D_DST_BASE_ADDR: 596 case G2D_DST_BASE_ADDR:
597 case G2D_DST_COLOR_MODE:
598 case G2D_DST_LEFT_TOP:
599 case G2D_DST_RIGHT_BOTTOM:
552 reg_type = REG_TYPE_DST; 600 reg_type = REG_TYPE_DST;
553 break; 601 break;
554 case G2D_DST_PLANE2_BASE_ADDR: 602 case G2D_DST_PLANE2_BASE_ADDR:
@@ -569,6 +617,69 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
569 return reg_type; 617 return reg_type;
570} 618}
571 619
620static unsigned long g2d_get_buf_bpp(unsigned int format)
621{
622 unsigned long bpp;
623
624 switch (format) {
625 case G2D_FMT_XRGB8888:
626 case G2D_FMT_ARGB8888:
627 bpp = 4;
628 break;
629 case G2D_FMT_RGB565:
630 case G2D_FMT_XRGB1555:
631 case G2D_FMT_ARGB1555:
632 case G2D_FMT_XRGB4444:
633 case G2D_FMT_ARGB4444:
634 bpp = 2;
635 break;
636 case G2D_FMT_PACKED_RGB888:
637 bpp = 3;
638 break;
639 default:
640 bpp = 1;
641 break;
642 }
643
644 return bpp;
645}
646
647static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
648 enum g2d_reg_type reg_type,
649 unsigned long size)
650{
651 unsigned int width, height;
652 unsigned long area;
653
654 /*
655 * check source and destination buffers only.
656 * so the others are always valid.
657 */
658 if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
659 return true;
660
661 width = buf_desc->right_x - buf_desc->left_x;
662 if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
663 DRM_ERROR("width[%u] is out of range!\n", width);
664 return false;
665 }
666
667 height = buf_desc->bottom_y - buf_desc->top_y;
668 if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
669 DRM_ERROR("height[%u] is out of range!\n", height);
670 return false;
671 }
672
673 area = (unsigned long)width * (unsigned long)height *
674 g2d_get_buf_bpp(buf_desc->format);
675 if (area > size) {
676 DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
677 return false;
678 }
679
680 return true;
681}
682
572static int g2d_map_cmdlist_gem(struct g2d_data *g2d, 683static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
573 struct g2d_cmdlist_node *node, 684 struct g2d_cmdlist_node *node,
574 struct drm_device *drm_dev, 685 struct drm_device *drm_dev,
@@ -581,6 +692,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
581 int i; 692 int i;
582 693
583 for (i = 0; i < buf_info->map_nr; i++) { 694 for (i = 0; i < buf_info->map_nr; i++) {
695 struct g2d_buf_desc *buf_desc;
584 enum g2d_reg_type reg_type; 696 enum g2d_reg_type reg_type;
585 int reg_pos; 697 int reg_pos;
586 unsigned long handle; 698 unsigned long handle;
@@ -597,7 +709,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
597 goto err; 709 goto err;
598 } 710 }
599 711
712 buf_desc = &buf_info->descs[reg_type];
713
600 if (buf_info->types[reg_type] == BUF_TYPE_GEM) { 714 if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
715 unsigned long size;
716
717 size = exynos_drm_gem_get_size(drm_dev, handle, file);
718 if (!size) {
719 ret = -EFAULT;
720 goto err;
721 }
722
723 if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
724 size)) {
725 ret = -EFAULT;
726 goto err;
727 }
728
601 addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, 729 addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
602 file); 730 file);
603 if (IS_ERR(addr)) { 731 if (IS_ERR(addr)) {
@@ -613,6 +741,12 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
613 goto err; 741 goto err;
614 } 742 }
615 743
744 if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
745 g2d_userptr.size)) {
746 ret = -EFAULT;
747 goto err;
748 }
749
616 addr = g2d_userptr_get_dma_addr(drm_dev, 750 addr = g2d_userptr_get_dma_addr(drm_dev,
617 g2d_userptr.userptr, 751 g2d_userptr.userptr,
618 g2d_userptr.size, 752 g2d_userptr.size,
@@ -645,11 +779,13 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
645 int i; 779 int i;
646 780
647 for (i = 0; i < buf_info->map_nr; i++) { 781 for (i = 0; i < buf_info->map_nr; i++) {
782 struct g2d_buf_desc *buf_desc;
648 enum g2d_reg_type reg_type; 783 enum g2d_reg_type reg_type;
649 unsigned long handle; 784 unsigned long handle;
650 785
651 reg_type = buf_info->reg_types[i]; 786 reg_type = buf_info->reg_types[i];
652 787
788 buf_desc = &buf_info->descs[reg_type];
653 handle = buf_info->handles[reg_type]; 789 handle = buf_info->handles[reg_type];
654 790
655 if (buf_info->types[reg_type] == BUF_TYPE_GEM) 791 if (buf_info->types[reg_type] == BUF_TYPE_GEM)
@@ -662,6 +798,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
662 buf_info->reg_types[i] = REG_TYPE_NONE; 798 buf_info->reg_types[i] = REG_TYPE_NONE;
663 buf_info->handles[reg_type] = 0; 799 buf_info->handles[reg_type] = 0;
664 buf_info->types[reg_type] = 0; 800 buf_info->types[reg_type] = 0;
801 memset(buf_desc, 0x00, sizeof(*buf_desc));
665 } 802 }
666 803
667 buf_info->map_nr = 0; 804 buf_info->map_nr = 0;
@@ -808,7 +945,9 @@ static int g2d_check_reg_offset(struct device *dev,
808 945
809 for (i = 0; i < nr; i++) { 946 for (i = 0; i < nr; i++) {
810 struct g2d_buf_info *buf_info = &node->buf_info; 947 struct g2d_buf_info *buf_info = &node->buf_info;
948 struct g2d_buf_desc *buf_desc;
811 enum g2d_reg_type reg_type; 949 enum g2d_reg_type reg_type;
950 unsigned long value;
812 951
813 index = cmdlist->last - 2 * (i + 1); 952 index = cmdlist->last - 2 * (i + 1);
814 953
@@ -839,6 +978,50 @@ static int g2d_check_reg_offset(struct device *dev,
839 } else 978 } else
840 buf_info->types[reg_type] = BUF_TYPE_GEM; 979 buf_info->types[reg_type] = BUF_TYPE_GEM;
841 break; 980 break;
981 case G2D_SRC_COLOR_MODE:
982 case G2D_DST_COLOR_MODE:
983 if (for_addr)
984 goto err;
985
986 reg_type = g2d_get_reg_type(reg_offset);
987 if (reg_type == REG_TYPE_NONE)
988 goto err;
989
990 buf_desc = &buf_info->descs[reg_type];
991 value = cmdlist->data[index + 1];
992
993 buf_desc->format = value & 0xf;
994 break;
995 case G2D_SRC_LEFT_TOP:
996 case G2D_DST_LEFT_TOP:
997 if (for_addr)
998 goto err;
999
1000 reg_type = g2d_get_reg_type(reg_offset);
1001 if (reg_type == REG_TYPE_NONE)
1002 goto err;
1003
1004 buf_desc = &buf_info->descs[reg_type];
1005 value = cmdlist->data[index + 1];
1006
1007 buf_desc->left_x = value & 0x1fff;
1008 buf_desc->top_y = (value & 0x1fff0000) >> 16;
1009 break;
1010 case G2D_SRC_RIGHT_BOTTOM:
1011 case G2D_DST_RIGHT_BOTTOM:
1012 if (for_addr)
1013 goto err;
1014
1015 reg_type = g2d_get_reg_type(reg_offset);
1016 if (reg_type == REG_TYPE_NONE)
1017 goto err;
1018
1019 buf_desc = &buf_info->descs[reg_type];
1020 value = cmdlist->data[index + 1];
1021
1022 buf_desc->right_x = value & 0x1fff;
1023 buf_desc->bottom_y = (value & 0x1fff0000) >> 16;
1024 break;
842 default: 1025 default:
843 if (for_addr) 1026 if (for_addr)
844 goto err; 1027 goto err;