vc4: Add a bunch of validation of the binning mode config.
authorEric Anholt <eric@anholt.net>
Sat, 2 Aug 2014 00:11:38 +0000 (17:11 -0700)
committerEric Anholt <eric@anholt.net>
Mon, 11 Aug 2014 21:45:31 +0000 (14:45 -0700)
src/gallium/drivers/vc4/vc4_simulator_validate.c
src/gallium/drivers/vc4/vc4_simulator_validate.h

index 3db74a0b18b62cf3a3d8898ae5cebad32eca52f0..97a1f7468544927e72ae6882ecd09b122b8c2361 100644 (file)
@@ -97,18 +97,47 @@ gl_shader_rec_size(uint32_t pointer_bits)
        return 36 + attribute_count * (extended ? 12 : 8);
 }
 
+static int
+validate_start_tile_binning(VALIDATE_ARGS)
+{
+       if (exec->found_start_tile_binning_packet) {
+               DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n");
+               return -EINVAL;
+       }
+       exec->found_start_tile_binning_packet = true;
+
+       if (!exec->found_tile_binning_mode_config_packet) {
+               DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int
 validate_branch_to_sublist(VALIDATE_ARGS)
 {
        struct drm_gem_cma_object *target;
-
-       /* XXX: Validate address jumped to */
+       uint32_t offset;
 
        if (!vc4_use_handle(exec, 0, VC4_MODE_TILE_ALLOC, &target))
                return -EINVAL;
 
-       *(uint32_t *)(validated + 0) =
-               *(uint32_t *)(untrusted + 0) + target->paddr;
+       if (target != exec->tile_alloc_bo) {
+               DRM_ERROR("Juimping to BOs other than tile alloc unsupported\n");
+               return -EINVAL;
+       }
+
+       offset = *(uint32_t *)(untrusted + 0);
+       if (offset % exec->tile_alloc_init_block_size ||
+           offset / exec->tile_alloc_init_block_size >
+           exec->bin_tiles_x * exec->bin_tiles_y) {
+               DRM_ERROR("VC4_PACKET_BRANCH_TO_SUB_LIST must jump to initial "
+                         "tile allocation space.\n");
+               return -EINVAL;
+       }
+
+       *(uint32_t *)(validated + 0) = target->paddr + offset;
 
        return 0;
 }
@@ -223,17 +252,79 @@ validate_tile_binning_config(VALIDATE_ARGS)
 {
        struct drm_gem_cma_object *tile_allocation;
        struct drm_gem_cma_object *tile_state_data_array;
+       uint8_t flags;
+       uint32_t tile_allocation_size;
 
        if (!vc4_use_handle(exec, 0, VC4_MODE_TILE_ALLOC, &tile_allocation) ||
            !vc4_use_handle(exec, 1, VC4_MODE_TSDA, &tile_state_data_array))
                return -EINVAL;
 
-       /* XXX: Validate offsets */
-       *(uint32_t *)validated =
-               *(uint32_t *)untrusted + tile_allocation->paddr;
+       if (exec->found_tile_binning_mode_config_packet) {
+               DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
+               return -EINVAL;
+       }
+       exec->found_tile_binning_mode_config_packet = true;
 
-       *(uint32_t *)(validated + 8) =
-               *(uint32_t *)(untrusted + 8) + tile_state_data_array->paddr;
+       exec->bin_tiles_x = *(uint8_t *)(untrusted + 12);
+       exec->bin_tiles_y = *(uint8_t *)(untrusted + 13);
+       flags = *(uint8_t *)(untrusted + 14);
+
+       if (exec->bin_tiles_x == 0 ||
+           exec->bin_tiles_y == 0) {
+               DRM_ERROR("Tile binning config of %dx%d too small\n",
+                         exec->bin_tiles_x, exec->bin_tiles_y);
+               return -EINVAL;
+       }
+
+       /* Our validation relies on the user not getting to set up their own
+        * tile state/tile allocation BO contents.
+        */
+       if (!(flags & VC4_BIN_CONFIG_AUTO_INIT_TSDA)) {
+               DRM_ERROR("binning config missing "
+                         "VC4_BIN_CONFIG_AUTO_INIT_TSDA\n");
+               return -EINVAL;
+       }
+
+       if (flags & (VC4_BIN_CONFIG_DB_NON_MS |
+                    VC4_BIN_CONFIG_TILE_BUFFER_64BIT |
+                    VC4_BIN_CONFIG_MS_MODE_4X)) {
+               DRM_ERROR("unsupported bining config flags 0x%02x\n", flags);
+               return -EINVAL;
+       }
+
+       if (*(uint32_t *)(untrusted + 0) != 0) {
+               DRM_ERROR("tile allocation offset != 0 unsupported\n");
+               return -EINVAL;
+       }
+       tile_allocation_size = *(uint32_t *)(untrusted + 4);
+       if (tile_allocation_size > tile_allocation->base.size) {
+               DRM_ERROR("tile allocation size %d > BO size %d",
+                         tile_allocation_size, tile_allocation->base.size);
+               return -EINVAL;
+       }
+       *(uint32_t *)validated = tile_allocation->paddr;
+       exec->tile_alloc_bo = tile_allocation;
+
+       exec->tile_alloc_init_block_size = 1 << (5 + ((flags >> 5) & 3));
+       if (exec->bin_tiles_x * exec->bin_tiles_y *
+           exec->tile_alloc_init_block_size > tile_allocation_size) {
+               DRM_ERROR("tile init exceeds tile alloc size (%d vs %d)\n",
+                         exec->bin_tiles_x * exec->bin_tiles_y *
+                         exec->tile_alloc_init_block_size,
+                         tile_allocation_size);
+               return -EINVAL;
+       }
+       if (*(uint32_t *)(untrusted + 8) != 0) {
+               DRM_ERROR("TSDA offset != 0 unsupported\n");
+               return -EINVAL;
+       }
+       if (exec->bin_tiles_x * exec->bin_tiles_y * 48 >
+           tile_state_data_array->base.size) {
+               DRM_ERROR("TSDA of %db too small for %dx%d bin config\n",
+                         tile_state_data_array->base.size,
+                         exec->bin_tiles_x, exec->bin_tiles_y);
+       }
+       *(uint32_t *)(validated + 8) = tile_state_data_array->paddr;
 
        return 0;
 }
@@ -253,6 +344,25 @@ validate_tile_rendering_mode_config(VALIDATE_ARGS)
        return 0;
 }
 
+static int
+validate_tile_coordinates(VALIDATE_ARGS)
+{
+       uint8_t tile_x = *(uint8_t *)(untrusted + 0);
+       uint8_t tile_y = *(uint8_t *)(untrusted + 1);
+
+       if (tile_x >= exec->bin_tiles_x ||
+           tile_y >= exec->bin_tiles_y) {
+               DRM_ERROR("Tile coordinates %d,%d > bin config %d,%d\n",
+                         tile_x,
+                         tile_y,
+                         exec->bin_tiles_x,
+                         exec->bin_tiles_y);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int
 validate_gem_handles(VALIDATE_ARGS)
 {
@@ -271,10 +381,14 @@ static const struct cmd_info {
        [VC4_PACKET_NOP] = { 1, 1, 1, "nop", NULL },
        [VC4_PACKET_FLUSH] = { 1, 1, 1, "flush", NULL },
        [VC4_PACKET_FLUSH_ALL] = { 1, 0, 1, "flush all state", NULL },
-       [VC4_PACKET_START_TILE_BINNING] = { 1, 0, 1, "start tile binning", NULL },
+       [VC4_PACKET_START_TILE_BINNING] = { 1, 0, 1, "start tile binning", validate_start_tile_binning },
        [VC4_PACKET_INCREMENT_SEMAPHORE] = { 1, 0, 1, "increment semaphore", NULL },
        [VC4_PACKET_WAIT_ON_SEMAPHORE] = { 1, 1, 1, "wait on semaphore", NULL },
-       [VC4_PACKET_BRANCH_TO_SUB_LIST] = { 1, 1, 5, "branch to sublist", validate_branch_to_sublist },
+       /* BRANCH_TO_SUB_LIST is actually supported in the binner as well, but
+        * we only use it from the render CL in order to jump into the tile
+        * allocation BO.
+        */
+       [VC4_PACKET_BRANCH_TO_SUB_LIST] = { 0, 1, 5, "branch to sublist", validate_branch_to_sublist },
        [VC4_PACKET_STORE_MS_TILE_BUFFER] = { 0, 1, 1, "store MS resolved tile color buffer", NULL },
        [VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF] = { 0, 1, 1, "store MS resolved tile color buffer and EOF", NULL },
 
@@ -313,10 +427,7 @@ static const struct cmd_info {
 
        [VC4_PACKET_CLEAR_COLORS] = { 0, 1, 14, "Clear Colors", NULL },
 
-       /* XXX: Do we need to validate here?  It's got tile x/y number for
-        * rendering
-        */
-       [VC4_PACKET_TILE_COORDINATES] = { 0, 1, 3, "Tile Coordinates", NULL },
+       [VC4_PACKET_TILE_COORDINATES] = { 0, 1, 3, "Tile Coordinates", validate_tile_coordinates },
 
        [VC4_PACKET_GEM_HANDLES] = { 1, 1, 9, "GEM handles", validate_gem_handles },
 };
@@ -394,10 +505,16 @@ vc4_validate_cl(struct drm_device *dev,
                        break;
        }
 
-       if (is_bin)
+       if (is_bin) {
                exec->ct0ea = exec->ct0ca + dst_offset;
-       else
+
+               if (!exec->found_start_tile_binning_packet) {
+                       DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");
+                       return -EINVAL;
+               }
+       } else {
                exec->ct1ea = exec->ct1ca + dst_offset;
+       }
 
        return 0;
 }
index 1f3d23f881e88ab4ee13c8403af98a2c1080e383..d26f0d6f8c0bb0fe5aa6b7da07486336b6d6453b 100644 (file)
@@ -119,6 +119,12 @@ struct exec_info {
        /** How many shader state records the validator has seen. */
        uint32_t shader_state_count;
 
+       bool found_tile_binning_mode_config_packet;
+       bool found_start_tile_binning_packet;
+       uint8_t bin_tiles_x, bin_tiles_y;
+       uint32_t tile_alloc_init_block_size;
+       struct drm_gem_cma_object *tile_alloc_bo;
+
        /**
         * Computed addresses pointing into exec_bo where we start the
         * bin thread (ct0) and render thread (ct1).