/* registers for base address */
 #define G2D_SRC_BASE_ADDR              0x0304
+#define G2D_SRC_COLOR_MODE             0x030C
+#define G2D_SRC_LEFT_TOP               0x0310
+#define G2D_SRC_RIGHT_BOTTOM           0x0314
 #define G2D_SRC_PLANE2_BASE_ADDR       0x0318
 #define G2D_DST_BASE_ADDR              0x0404
+#define G2D_DST_COLOR_MODE             0x040C
+#define G2D_DST_LEFT_TOP               0x0410
+#define G2D_DST_RIGHT_BOTTOM           0x0414
 #define G2D_DST_PLANE2_BASE_ADDR       0x0418
 #define G2D_PAT_BASE_ADDR              0x0500
 #define G2D_MSK_BASE_ADDR              0x0520
 #define G2D_START_NHOLT                        (1 << 1)
 #define G2D_START_BITBLT               (1 << 0)
 
+/* buffer color format */
+#define G2D_FMT_XRGB8888               0
+#define G2D_FMT_ARGB8888               1
+#define G2D_FMT_RGB565                 2
+#define G2D_FMT_XRGB1555               3
+#define G2D_FMT_ARGB1555               4
+#define G2D_FMT_XRGB4444               5
+#define G2D_FMT_ARGB4444               6
+#define G2D_FMT_PACKED_RGB888          7
+#define G2D_FMT_A8                     11
+#define G2D_FMT_L8                     12
+
+/* buffer valid length */
+#define G2D_LEN_MIN                    1
+#define G2D_LEN_MAX                    8000
+
 #define G2D_CMDLIST_SIZE               (PAGE_SIZE / 4)
 #define G2D_CMDLIST_NUM                        64
 #define G2D_CMDLIST_POOL_SIZE          (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
        u32             last;   /* last data offset */
 };
 
+/*
+ * A structure of buffer description
+ *
+ * @format: color format
+ * @left_x: the x coordinates of left top corner
+ * @top_y: the y coordinates of left top corner
+ * @right_x: the x coordinates of right bottom corner
+ * @bottom_y: the y coordinates of right bottom corner
+ *
+ */
+struct g2d_buf_desc {
+       unsigned int    format;
+       unsigned int    left_x;
+       unsigned int    top_y;
+       unsigned int    right_x;
+       unsigned int    bottom_y;
+};
+
 /*
  * A structure of buffer information
  *
  * @reg_types: stores regitster type in the order of requested command
  * @handles: stores buffer handle in its reg_type position
  * @types: stores buffer type in its reg_type position
+ * @descs: stores buffer description in its reg_type position
  *
  */
 struct g2d_buf_info {
        enum g2d_reg_type       reg_types[MAX_REG_TYPE_NR];
        unsigned long           handles[MAX_REG_TYPE_NR];
        unsigned int            types[MAX_REG_TYPE_NR];
+       struct g2d_buf_desc     descs[MAX_REG_TYPE_NR];
 };
 
 struct drm_exynos_pending_g2d_event {
 
        switch (reg_offset) {
        case G2D_SRC_BASE_ADDR:
+       case G2D_SRC_COLOR_MODE:
+       case G2D_SRC_LEFT_TOP:
+       case G2D_SRC_RIGHT_BOTTOM:
                reg_type = REG_TYPE_SRC;
                break;
        case G2D_SRC_PLANE2_BASE_ADDR:
                reg_type = REG_TYPE_SRC_PLANE2;
                break;
        case G2D_DST_BASE_ADDR:
+       case G2D_DST_COLOR_MODE:
+       case G2D_DST_LEFT_TOP:
+       case G2D_DST_RIGHT_BOTTOM:
                reg_type = REG_TYPE_DST;
                break;
        case G2D_DST_PLANE2_BASE_ADDR:
        return reg_type;
 }
 
+static unsigned long g2d_get_buf_bpp(unsigned int format)
+{
+       unsigned long bpp;
+
+       switch (format) {
+       case G2D_FMT_XRGB8888:
+       case G2D_FMT_ARGB8888:
+               bpp = 4;
+               break;
+       case G2D_FMT_RGB565:
+       case G2D_FMT_XRGB1555:
+       case G2D_FMT_ARGB1555:
+       case G2D_FMT_XRGB4444:
+       case G2D_FMT_ARGB4444:
+               bpp = 2;
+               break;
+       case G2D_FMT_PACKED_RGB888:
+               bpp = 3;
+               break;
+       default:
+               bpp = 1;
+               break;
+       }
+
+       return bpp;
+}
+
+static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
+                                               enum g2d_reg_type reg_type,
+                                               unsigned long size)
+{
+       unsigned int width, height;
+       unsigned long area;
+
+       /*
+        * check source and destination buffers only.
+        * so the others are always valid.
+        */
+       if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
+               return true;
+
+       width = buf_desc->right_x - buf_desc->left_x;
+       if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
+               DRM_ERROR("width[%u] is out of range!\n", width);
+               return false;
+       }
+
+       height = buf_desc->bottom_y - buf_desc->top_y;
+       if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
+               DRM_ERROR("height[%u] is out of range!\n", height);
+               return false;
+       }
+
+       area = (unsigned long)width * (unsigned long)height *
+                                       g2d_get_buf_bpp(buf_desc->format);
+       if (area > size) {
+               DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
+               return false;
+       }
+
+       return true;
+}
+
 static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
                                struct g2d_cmdlist_node *node,
                                struct drm_device *drm_dev,
        int i;
 
        for (i = 0; i < buf_info->map_nr; i++) {
+               struct g2d_buf_desc *buf_desc;
                enum g2d_reg_type reg_type;
                int reg_pos;
                unsigned long handle;
                        goto err;
                }
 
+               buf_desc = &buf_info->descs[reg_type];
+
                if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
+                       unsigned long size;
+
+                       size = exynos_drm_gem_get_size(drm_dev, handle, file);
+                       if (!size) {
+                               ret = -EFAULT;
+                               goto err;
+                       }
+
+                       if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
+                                                                       size)) {
+                               ret = -EFAULT;
+                               goto err;
+                       }
+
                        addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
                                                                file);
                        if (IS_ERR(addr)) {
                                goto err;
                        }
 
+                       if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
+                                                       g2d_userptr.size)) {
+                               ret = -EFAULT;
+                               goto err;
+                       }
+
                        addr = g2d_userptr_get_dma_addr(drm_dev,
                                                        g2d_userptr.userptr,
                                                        g2d_userptr.size,
        int i;
 
        for (i = 0; i < buf_info->map_nr; i++) {
+               struct g2d_buf_desc *buf_desc;
                enum g2d_reg_type reg_type;
                unsigned long handle;
 
                reg_type = buf_info->reg_types[i];
 
+               buf_desc = &buf_info->descs[reg_type];
                handle = buf_info->handles[reg_type];
 
                if (buf_info->types[reg_type] == BUF_TYPE_GEM)
                buf_info->reg_types[i] = REG_TYPE_NONE;
                buf_info->handles[reg_type] = 0;
                buf_info->types[reg_type] = 0;
+               memset(buf_desc, 0x00, sizeof(*buf_desc));
        }
 
        buf_info->map_nr = 0;
 
        for (i = 0; i < nr; i++) {
                struct g2d_buf_info *buf_info = &node->buf_info;
+               struct g2d_buf_desc *buf_desc;
                enum g2d_reg_type reg_type;
+               unsigned long value;
 
                index = cmdlist->last - 2 * (i + 1);
 
                        } else
                                buf_info->types[reg_type] = BUF_TYPE_GEM;
                        break;
+               case G2D_SRC_COLOR_MODE:
+               case G2D_DST_COLOR_MODE:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       value = cmdlist->data[index + 1];
+
+                       buf_desc->format = value & 0xf;
+                       break;
+               case G2D_SRC_LEFT_TOP:
+               case G2D_DST_LEFT_TOP:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       value = cmdlist->data[index + 1];
+
+                       buf_desc->left_x = value & 0x1fff;
+                       buf_desc->top_y = (value & 0x1fff0000) >> 16;
+                       break;
+               case G2D_SRC_RIGHT_BOTTOM:
+               case G2D_DST_RIGHT_BOTTOM:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       value = cmdlist->data[index + 1];
+
+                       buf_desc->right_x = value & 0x1fff;
+                       buf_desc->bottom_y = (value & 0x1fff0000) >> 16;
+                       break;
                default:
                        if (for_addr)
                                goto err;