vc4: Add validation of raster-format textures.
authorEric Anholt <eric@anholt.net>
Sun, 3 Aug 2014 04:28:34 +0000 (21:28 -0700)
committerEric Anholt <eric@anholt.net>
Mon, 11 Aug 2014 21:45:32 +0000 (14:45 -0700)
... and reject everything else, for now.

v2: Rebase on v2 of the rendering config validation change.

src/gallium/drivers/vc4/vc4_simulator_validate.c
src/gallium/drivers/vc4/vc4_simulator_validate.h

index 241ca17f33f8fd25038d0298c1cb987928d5205a..421107a0b0582c66663eb5f70f7327df89ea465c 100644 (file)
@@ -101,8 +101,9 @@ gl_shader_rec_size(uint32_t pointer_bits)
 }
 
 static bool
-check_fbo_size(struct exec_info *exec, struct drm_gem_cma_object *fbo,
-              uint32_t offset, uint8_t tiling_format, uint8_t cpp)
+check_tex_size(struct exec_info *exec, struct drm_gem_cma_object *fbo,
+              uint32_t offset, uint8_t tiling_format,
+              uint32_t width, uint32_t height, uint8_t cpp)
 {
        uint32_t width_align, height_align;
        uint32_t aligned_row_len, aligned_h, size;
@@ -125,14 +126,14 @@ check_fbo_size(struct exec_info *exec, struct drm_gem_cma_object *fbo,
                return false;
        }
 
-       /* The values are limited by the packet bitfields, so we don't need to
-        * worry as much about integer overflow.
+       /* The values are limited by the packet/texture parameter bitfields,
+        * so we don't need to worry as much about integer overflow.
         */
-       BUG_ON(exec->fb_width > 65535);
-       BUG_ON(exec->fb_height > 65535);
+       BUG_ON(width > 65535);
+       BUG_ON(height > 65535);
 
-       aligned_row_len = roundup(exec->fb_width * cpp, width_align);
-       aligned_h = roundup(exec->fb_height, height_align);
+       aligned_row_len = roundup(width * cpp, width_align);
+       aligned_h = roundup(height, height_align);
 
        if (INT_MAX / aligned_row_len < aligned_h) {
                DRM_ERROR("Overflow in fbo size (%d * %d)\n",
@@ -144,8 +145,7 @@ check_fbo_size(struct exec_info *exec, struct drm_gem_cma_object *fbo,
        if (size + offset < size ||
            size + offset > fbo->base.size) {
                DRM_ERROR("Overflow in %dx%d fbo size (%d + %d > %d)\n",
-                         exec->fb_width, exec->fb_height, size, offset,
-                         fbo->base.size);
+                         width, height, size, offset, fbo->base.size);
                return false;
        }
 
@@ -247,11 +247,11 @@ validate_loadstore_tile_buffer_general(VALIDATE_ARGS)
 
        offset = *(uint32_t *)(untrusted + 2);
 
-       if (!check_fbo_size(exec, fbo, offset,
+       if (!check_tex_size(exec, fbo, offset,
                            ((packet_b0 &
                              VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK) >>
                             VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT),
-                           cpp)) {
+                           exec->fb_width, exec->fb_height, cpp)) {
                return -EINVAL;
        }
 
@@ -499,11 +499,11 @@ validate_tile_rendering_mode_config(VALIDATE_ARGS)
        }
 
        offset = *(uint32_t *)untrusted;
-       if (!check_fbo_size(exec, fbo, offset,
+       if (!check_tex_size(exec, fbo, offset,
                            ((flags &
                              VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK) >>
                             VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT),
-                           cpp)) {
+                           exec->fb_width, exec->fb_height, cpp)) {
                return -EINVAL;
        }
 
@@ -699,14 +699,91 @@ reloc_tex(struct exec_info *exec,
 
 {
        struct drm_gem_cma_object *tex;
-       uint32_t unvalidated_p0 = *(uint32_t *)(uniform_data_u +
-                                               sample->p_offset[0]);
+       uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
+       uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]);
        uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0];
+       uint32_t offset = p0 & ~0xfff;
+       uint32_t miplevels = (p0 & 0x15);
+       uint32_t width = (p1 >> 8) & 2047;
+       uint32_t height = (p1 >> 20) & 2047;
+       uint32_t type, cpp, tiling_format;
+       int i;
+
+       if (width == 0)
+               width = 2048;
+       if (height == 0)
+               height = 2048;
+
+       if (p0 & (1 << 9)) {
+               DRM_ERROR("Cube maps unsupported\n");
+               return false;
+       }
+
+       type = ((p0 >> 4) & 15) | ((p1 >> 31) << 4);
+
+       switch (type) {
+       case 0: /* RGBA8888 */
+       case 1: /* RGBX8888 */
+       case 16: /* RGBA32R */
+               cpp = 4;
+               break;
+       case 2: /* RGBA4444 */
+       case 3: /* RGBA5551 */
+       case 4: /* RGB565 */
+       case 7: /* LUMALPHA */
+       case 9: /* S16F */
+       case 11: /* S16 */
+               cpp = 2;
+               break;
+       case 5: /* LUMINANCE */
+       case 6: /* ALPHA */
+       case 10: /* S8 */
+               cpp = 1;
+               break;
+       case 8: /* ETC1 */
+       case 12: /* BW1 */
+       case 13: /* A4 */
+       case 14: /* A1 */
+       case 15: /* RGBA64 */
+       case 17: /* YUV422R */
+       default:
+               DRM_ERROR("Texture format %d unsupported\n", type);
+               return false;
+       }
+
+       if (type == 16) {
+               tiling_format = VC4_TILING_FORMAT_LINEAR;
+       } else {
+               DRM_ERROR("Tiling formats not yet supported\n");
+               return false;
+       }
 
        if (!vc4_use_bo(exec, texture_handle_index, VC4_MODE_RENDER, &tex))
                return false;
 
-       *validated_p0 = tex->paddr + unvalidated_p0;
+       if (!check_tex_size(exec, tex, offset, tiling_format,
+                           width, height, cpp)) {
+               return false;
+       }
+
+       /* The mipmap levels are stored before the base of the texture.  Make
+        * sure there is actually space in the BO.
+        */
+       for (i = 1; i <= miplevels; i++) {
+               uint32_t level_width = align(max(width >> i, 1), 16 / cpp);
+               uint32_t level_height = max(height >> i, 1);
+               uint32_t level_size = level_width * level_height * cpp;
+
+               if (offset < level_size) {
+                       DRM_ERROR("Level %d (%dx%d) size %db overflowed "
+                                 "buffer bounds (offset %d)\n",
+                                 i, level_width, level_height,
+                                 level_size, offset);
+                       return false;
+               }
+       }
+
+       *validated_p0 = tex->paddr + p0;
 
        return true;
 }
index 8b74df2bdad0ca29226a608a471f2299299f6bd2..39419b4207802ce126db0d4f309d9d1317837b90 100644 (file)
@@ -41,6 +41,8 @@
 #define kfree(ptr) free(ptr)
 #define krealloc(ptr, size, args) realloc(ptr, size)
 #define roundup(x, y) align(x, y)
+#define max(x, y) MAX2(x, y)
+#define min(x, y) MiN2(x, y)
 #define BUG_ON(condition) assert(!(condition))
 
 static inline int