956 lines · c
1/*2 * Copyright © 2014 Broadcom3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice (including the next12 * paragraph) shall be included in all copies or substantial portions of the13 * Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS21 * IN THE SOFTWARE.22 */23 24/**25 * DOC: Command list validator for VC4.26 *27 * Since the VC4 has no IOMMU between it and system memory, a user28 * with access to execute command lists could escalate privilege by29 * overwriting system memory (drawing to it as a framebuffer) or30 * reading system memory it shouldn't (reading it as a vertex buffer31 * or index buffer)32 *33 * We validate binner command lists to ensure that all accesses are34 * within the bounds of the GEM objects referenced by the submitted35 * job. It explicitly whitelists packets, and looks at the offsets in36 * any address fields to make sure they're contained within the BOs37 * they reference.38 *39 * Note that because CL validation is already reading the40 * user-submitted CL and writing the validated copy out to the memory41 * that the GPU will actually read, this is also where GEM relocation42 * processing (turning BO references into actual addresses for the GPU43 * to use) happens.44 */45 46#include "uapi/drm/vc4_drm.h"47#include "vc4_drv.h"48#include "vc4_packet.h"49 50#define VALIDATE_ARGS \51 struct vc4_exec_info *exec, \52 void *validated, \53 void *untrusted54 55/** Return the width in pixels of a 64-byte microtile. */56static uint32_t57utile_width(int cpp)58{59 switch (cpp) {60 case 1:61 case 2:62 return 8;63 case 4:64 return 4;65 case 8:66 return 2;67 default:68 pr_err("unknown cpp: %d\n", cpp);69 return 1;70 }71}72 73/** Return the height in pixels of a 64-byte microtile. */74static uint32_t75utile_height(int cpp)76{77 switch (cpp) {78 case 1:79 return 8;80 case 2:81 case 4:82 case 8:83 return 4;84 default:85 pr_err("unknown cpp: %d\n", cpp);86 return 1;87 }88}89 90/**91 * size_is_lt() - Returns whether a miplevel of the given size will92 * use the lineartile (LT) tiling layout rather than the normal T93 * tiling layout.94 * @width: Width in pixels of the miplevel95 * @height: Height in pixels of the miplevel96 * @cpp: Bytes per pixel of the pixel format97 */98static bool99size_is_lt(uint32_t width, uint32_t height, int cpp)100{101 return (width <= 4 * utile_width(cpp) ||102 height <= 4 * utile_height(cpp));103}104 105struct drm_gem_dma_object *106vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex)107{108 struct vc4_dev *vc4 = exec->dev;109 struct drm_gem_dma_object *obj;110 struct vc4_bo *bo;111 112 if (WARN_ON_ONCE(vc4->is_vc5))113 return NULL;114 115 if (hindex >= exec->bo_count) {116 DRM_DEBUG("BO index %d greater than BO count %d\n",117 hindex, exec->bo_count);118 return NULL;119 }120 obj = to_drm_gem_dma_obj(exec->bo[hindex]);121 bo = to_vc4_bo(&obj->base);122 123 if (bo->validated_shader) {124 DRM_DEBUG("Trying to use shader BO as something other than "125 "a shader\n");126 return NULL;127 }128 129 return obj;130}131 132static struct drm_gem_dma_object *133vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index)134{135 return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]);136}137 138static bool139validate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos)140{141 /* Note that the untrusted pointer passed to these functions is142 * incremented past the packet byte.143 */144 return (untrusted - 1 == exec->bin_u + pos);145}146 147static uint32_t148gl_shader_rec_size(uint32_t pointer_bits)149{150 uint32_t attribute_count = pointer_bits & 7;151 bool extended = pointer_bits & 8;152 153 if (attribute_count == 0)154 attribute_count = 8;155 156 if (extended)157 return 100 + attribute_count * 4;158 else159 return 36 + attribute_count * 8;160}161 162bool163vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_dma_object *fbo,164 uint32_t offset, uint8_t tiling_format,165 uint32_t width, uint32_t height, uint8_t cpp)166{167 struct vc4_dev *vc4 = exec->dev;168 uint32_t aligned_width, aligned_height, stride, size;169 uint32_t utile_w = utile_width(cpp);170 uint32_t utile_h = utile_height(cpp);171 172 if (WARN_ON_ONCE(vc4->is_vc5))173 return false;174 175 /* The shaded vertex format stores signed 12.4 fixed point176 * (-2048,2047) offsets from the viewport center, so we should177 * never have a render target larger than 4096. The texture178 * unit can only sample from 2048x2048, so it's even more179 * restricted. This lets us avoid worrying about overflow in180 * our math.181 */182 if (width > 4096 || height > 4096) {183 DRM_DEBUG("Surface dimensions (%d,%d) too large",184 width, height);185 return false;186 }187 188 switch (tiling_format) {189 case VC4_TILING_FORMAT_LINEAR:190 aligned_width = round_up(width, utile_w);191 aligned_height = height;192 break;193 case VC4_TILING_FORMAT_T:194 aligned_width = round_up(width, utile_w * 8);195 aligned_height = round_up(height, utile_h * 8);196 break;197 case VC4_TILING_FORMAT_LT:198 aligned_width = round_up(width, utile_w);199 aligned_height = round_up(height, utile_h);200 break;201 default:202 DRM_DEBUG("buffer tiling %d unsupported\n", tiling_format);203 return false;204 }205 206 stride = aligned_width * cpp;207 size = stride * aligned_height;208 209 if (size + offset < size ||210 size + offset > fbo->base.size) {211 DRM_DEBUG("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n",212 width, height,213 aligned_width, aligned_height,214 size, offset, fbo->base.size);215 return false;216 }217 218 return true;219}220 221static int222validate_flush(VALIDATE_ARGS)223{224 if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) {225 DRM_DEBUG("Bin CL must end with VC4_PACKET_FLUSH\n");226 return -EINVAL;227 }228 exec->found_flush = true;229 230 return 0;231}232 233static int234validate_start_tile_binning(VALIDATE_ARGS)235{236 if (exec->found_start_tile_binning_packet) {237 DRM_DEBUG("Duplicate VC4_PACKET_START_TILE_BINNING\n");238 return -EINVAL;239 }240 exec->found_start_tile_binning_packet = true;241 242 if (!exec->found_tile_binning_mode_config_packet) {243 DRM_DEBUG("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");244 return -EINVAL;245 }246 247 return 0;248}249 250static int251validate_increment_semaphore(VALIDATE_ARGS)252{253 if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) {254 DRM_DEBUG("Bin CL must end with "255 "VC4_PACKET_INCREMENT_SEMAPHORE\n");256 return -EINVAL;257 }258 exec->found_increment_semaphore_packet = true;259 260 return 0;261}262 263static int264validate_indexed_prim_list(VALIDATE_ARGS)265{266 struct drm_gem_dma_object *ib;267 uint32_t length = *(uint32_t *)(untrusted + 1);268 uint32_t offset = *(uint32_t *)(untrusted + 5);269 uint32_t max_index = *(uint32_t *)(untrusted + 9);270 uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;271 struct vc4_shader_state *shader_state;272 273 /* Check overflow condition */274 if (exec->shader_state_count == 0) {275 DRM_DEBUG("shader state must precede primitives\n");276 return -EINVAL;277 }278 shader_state = &exec->shader_state[exec->shader_state_count - 1];279 280 if (max_index > shader_state->max_index)281 shader_state->max_index = max_index;282 283 ib = vc4_use_handle(exec, 0);284 if (!ib)285 return -EINVAL;286 287 exec->bin_dep_seqno = max(exec->bin_dep_seqno,288 to_vc4_bo(&ib->base)->write_seqno);289 290 if (offset > ib->base.size ||291 (ib->base.size - offset) / index_size < length) {292 DRM_DEBUG("IB access overflow (%d + %d*%d > %zd)\n",293 offset, length, index_size, ib->base.size);294 return -EINVAL;295 }296 297 *(uint32_t *)(validated + 5) = ib->dma_addr + offset;298 299 return 0;300}301 302static int303validate_gl_array_primitive(VALIDATE_ARGS)304{305 uint32_t length = *(uint32_t *)(untrusted + 1);306 uint32_t base_index = *(uint32_t *)(untrusted + 5);307 uint32_t max_index;308 struct vc4_shader_state *shader_state;309 310 /* Check overflow condition */311 if (exec->shader_state_count == 0) {312 DRM_DEBUG("shader state must precede primitives\n");313 return -EINVAL;314 }315 shader_state = &exec->shader_state[exec->shader_state_count - 1];316 317 if (length + base_index < length) {318 DRM_DEBUG("primitive vertex count overflow\n");319 return -EINVAL;320 }321 max_index = length + base_index - 1;322 323 if (max_index > shader_state->max_index)324 shader_state->max_index = max_index;325 326 return 0;327}328 329static int330validate_gl_shader_state(VALIDATE_ARGS)331{332 uint32_t i = exec->shader_state_count++;333 334 if (i >= exec->shader_state_size) {335 DRM_DEBUG("More requests for shader states than declared\n");336 return -EINVAL;337 }338 339 exec->shader_state[i].addr = *(uint32_t *)untrusted;340 exec->shader_state[i].max_index = 0;341 342 if (exec->shader_state[i].addr & ~0xf) {343 DRM_DEBUG("high bits set in GL shader rec reference\n");344 return -EINVAL;345 }346 347 *(uint32_t *)validated = (exec->shader_rec_p +348 exec->shader_state[i].addr);349 350 exec->shader_rec_p +=351 roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16);352 353 return 0;354}355 356static int357validate_tile_binning_config(VALIDATE_ARGS)358{359 struct drm_device *dev = exec->exec_bo->base.dev;360 struct vc4_dev *vc4 = to_vc4_dev(dev);361 uint8_t flags;362 uint32_t tile_state_size;363 uint32_t tile_count, bin_addr;364 int bin_slot;365 366 if (exec->found_tile_binning_mode_config_packet) {367 DRM_DEBUG("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");368 return -EINVAL;369 }370 exec->found_tile_binning_mode_config_packet = true;371 372 exec->bin_tiles_x = *(uint8_t *)(untrusted + 12);373 exec->bin_tiles_y = *(uint8_t *)(untrusted + 13);374 tile_count = exec->bin_tiles_x * exec->bin_tiles_y;375 flags = *(uint8_t *)(untrusted + 14);376 377 if (exec->bin_tiles_x == 0 ||378 exec->bin_tiles_y == 0) {379 DRM_DEBUG("Tile binning config of %dx%d too small\n",380 exec->bin_tiles_x, exec->bin_tiles_y);381 return -EINVAL;382 }383 384 if (flags & (VC4_BIN_CONFIG_DB_NON_MS |385 VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) {386 DRM_DEBUG("unsupported binning config flags 0x%02x\n", flags);387 return -EINVAL;388 }389 390 bin_slot = vc4_v3d_get_bin_slot(vc4);391 if (bin_slot < 0) {392 if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {393 drm_err(dev, "Failed to allocate binner memory: %d\n",394 bin_slot);395 }396 return bin_slot;397 }398 399 /* The slot we allocated will only be used by this job, and is400 * free when the job completes rendering.401 */402 exec->bin_slots |= BIT(bin_slot);403 bin_addr = vc4->bin_bo->base.dma_addr + bin_slot * vc4->bin_alloc_size;404 405 /* The tile state data array is 48 bytes per tile, and we put it at406 * the start of a BO containing both it and the tile alloc.407 */408 tile_state_size = 48 * tile_count;409 410 /* Since the tile alloc array will follow us, align. */411 exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096);412 413 *(uint8_t *)(validated + 14) =414 ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |415 VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) |416 VC4_BIN_CONFIG_AUTO_INIT_TSDA |417 VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32,418 VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) |419 VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128,420 VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE));421 422 /* tile alloc address. */423 *(uint32_t *)(validated + 0) = exec->tile_alloc_offset;424 /* tile alloc size. */425 *(uint32_t *)(validated + 4) = (bin_addr + vc4->bin_alloc_size -426 exec->tile_alloc_offset);427 /* tile state address. */428 *(uint32_t *)(validated + 8) = bin_addr;429 430 return 0;431}432 433static int434validate_gem_handles(VALIDATE_ARGS)435{436 memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index));437 return 0;438}439 440#define VC4_DEFINE_PACKET(packet, func) \441 [packet] = { packet ## _SIZE, #packet, func }442 443static const struct cmd_info {444 uint16_t len;445 const char *name;446 int (*func)(struct vc4_exec_info *exec, void *validated,447 void *untrusted);448} cmd_info[] = {449 VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL),450 VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL),451 VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush),452 VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL),453 VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING,454 validate_start_tile_binning),455 VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE,456 validate_increment_semaphore),457 458 VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE,459 validate_indexed_prim_list),460 VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE,461 validate_gl_array_primitive),462 463 VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL),464 465 VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state),466 467 VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL),468 VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL),469 VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL),470 VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL),471 VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL),472 VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL),473 VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL),474 VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL),475 VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL),476 /* Note: The docs say this was also 105, but it was 106 in the477 * initial userland code drop.478 */479 VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL),480 481 VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG,482 validate_tile_binning_config),483 484 VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles),485};486 487int488vc4_validate_bin_cl(struct drm_device *dev,489 void *validated,490 void *unvalidated,491 struct vc4_exec_info *exec)492{493 struct vc4_dev *vc4 = to_vc4_dev(dev);494 uint32_t len = exec->args->bin_cl_size;495 uint32_t dst_offset = 0;496 uint32_t src_offset = 0;497 498 if (WARN_ON_ONCE(vc4->is_vc5))499 return -ENODEV;500 501 while (src_offset < len) {502 void *dst_pkt = validated + dst_offset;503 void *src_pkt = unvalidated + src_offset;504 u8 cmd = *(uint8_t *)src_pkt;505 const struct cmd_info *info;506 507 if (cmd >= ARRAY_SIZE(cmd_info)) {508 DRM_DEBUG("0x%08x: packet %d out of bounds\n",509 src_offset, cmd);510 return -EINVAL;511 }512 513 info = &cmd_info[cmd];514 if (!info->name) {515 DRM_DEBUG("0x%08x: packet %d invalid\n",516 src_offset, cmd);517 return -EINVAL;518 }519 520 if (src_offset + info->len > len) {521 DRM_DEBUG("0x%08x: packet %d (%s) length 0x%08x "522 "exceeds bounds (0x%08x)\n",523 src_offset, cmd, info->name, info->len,524 src_offset + len);525 return -EINVAL;526 }527 528 if (cmd != VC4_PACKET_GEM_HANDLES)529 memcpy(dst_pkt, src_pkt, info->len);530 531 if (info->func && info->func(exec,532 dst_pkt + 1,533 src_pkt + 1)) {534 DRM_DEBUG("0x%08x: packet %d (%s) failed to validate\n",535 src_offset, cmd, info->name);536 return -EINVAL;537 }538 539 src_offset += info->len;540 /* GEM handle loading doesn't produce HW packets. */541 if (cmd != VC4_PACKET_GEM_HANDLES)542 dst_offset += info->len;543 544 /* When the CL hits halt, it'll stop reading anything else. */545 if (cmd == VC4_PACKET_HALT)546 break;547 }548 549 exec->ct0ea = exec->ct0ca + dst_offset;550 551 if (!exec->found_start_tile_binning_packet) {552 DRM_DEBUG("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");553 return -EINVAL;554 }555 556 /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The557 * semaphore is used to trigger the render CL to start up, and the558 * FLUSH is what caps the bin lists with559 * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main560 * render CL when they get called to) and actually triggers the queued561 * semaphore increment.562 */563 if (!exec->found_increment_semaphore_packet || !exec->found_flush) {564 DRM_DEBUG("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + "565 "VC4_PACKET_FLUSH\n");566 return -EINVAL;567 }568 569 return 0;570}571 572static bool573reloc_tex(struct vc4_exec_info *exec,574 void *uniform_data_u,575 struct vc4_texture_sample_info *sample,576 uint32_t texture_handle_index, bool is_cs)577{578 struct drm_gem_dma_object *tex;579 uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);580 uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]);581 uint32_t p2 = (sample->p_offset[2] != ~0 ?582 *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0);583 uint32_t p3 = (sample->p_offset[3] != ~0 ?584 *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0);585 uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0];586 uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK;587 uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS);588 uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH);589 uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT);590 uint32_t cpp, tiling_format, utile_w, utile_h;591 uint32_t i;592 uint32_t cube_map_stride = 0;593 enum vc4_texture_data_type type;594 595 tex = vc4_use_bo(exec, texture_handle_index);596 if (!tex)597 return false;598 599 if (sample->is_direct) {600 uint32_t remaining_size = tex->base.size - p0;601 602 if (p0 > tex->base.size - 4) {603 DRM_DEBUG("UBO offset greater than UBO size\n");604 goto fail;605 }606 if (p1 > remaining_size - 4) {607 DRM_DEBUG("UBO clamp would allow reads "608 "outside of UBO\n");609 goto fail;610 }611 *validated_p0 = tex->dma_addr + p0;612 return true;613 }614 615 if (width == 0)616 width = 2048;617 if (height == 0)618 height = 2048;619 620 if (p0 & VC4_TEX_P0_CMMODE_MASK) {621 if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) ==622 VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE)623 cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK;624 if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) ==625 VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) {626 if (cube_map_stride) {627 DRM_DEBUG("Cube map stride set twice\n");628 goto fail;629 }630 631 cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK;632 }633 if (!cube_map_stride) {634 DRM_DEBUG("Cube map stride not set\n");635 goto fail;636 }637 }638 639 type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) |640 (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4));641 642 switch (type) {643 case VC4_TEXTURE_TYPE_RGBA8888:644 case VC4_TEXTURE_TYPE_RGBX8888:645 case VC4_TEXTURE_TYPE_RGBA32R:646 cpp = 4;647 break;648 case VC4_TEXTURE_TYPE_RGBA4444:649 case VC4_TEXTURE_TYPE_RGBA5551:650 case VC4_TEXTURE_TYPE_RGB565:651 case VC4_TEXTURE_TYPE_LUMALPHA:652 case VC4_TEXTURE_TYPE_S16F:653 case VC4_TEXTURE_TYPE_S16:654 cpp = 2;655 break;656 case VC4_TEXTURE_TYPE_LUMINANCE:657 case VC4_TEXTURE_TYPE_ALPHA:658 case VC4_TEXTURE_TYPE_S8:659 cpp = 1;660 break;661 case VC4_TEXTURE_TYPE_ETC1:662 /* ETC1 is arranged as 64-bit blocks, where each block is 4x4663 * pixels.664 */665 cpp = 8;666 width = (width + 3) >> 2;667 height = (height + 3) >> 2;668 break;669 case VC4_TEXTURE_TYPE_BW1:670 case VC4_TEXTURE_TYPE_A4:671 case VC4_TEXTURE_TYPE_A1:672 case VC4_TEXTURE_TYPE_RGBA64:673 case VC4_TEXTURE_TYPE_YUV422R:674 default:675 DRM_DEBUG("Texture format %d unsupported\n", type);676 goto fail;677 }678 utile_w = utile_width(cpp);679 utile_h = utile_height(cpp);680 681 if (type == VC4_TEXTURE_TYPE_RGBA32R) {682 tiling_format = VC4_TILING_FORMAT_LINEAR;683 } else {684 if (size_is_lt(width, height, cpp))685 tiling_format = VC4_TILING_FORMAT_LT;686 else687 tiling_format = VC4_TILING_FORMAT_T;688 }689 690 if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5,691 tiling_format, width, height, cpp)) {692 goto fail;693 }694 695 /* The mipmap levels are stored before the base of the texture. Make696 * sure there is actually space in the BO.697 */698 for (i = 1; i <= miplevels; i++) {699 uint32_t level_width = max(width >> i, 1u);700 uint32_t level_height = max(height >> i, 1u);701 uint32_t aligned_width, aligned_height;702 uint32_t level_size;703 704 /* Once the levels get small enough, they drop from T to LT. */705 if (tiling_format == VC4_TILING_FORMAT_T &&706 size_is_lt(level_width, level_height, cpp)) {707 tiling_format = VC4_TILING_FORMAT_LT;708 }709 710 switch (tiling_format) {711 case VC4_TILING_FORMAT_T:712 aligned_width = round_up(level_width, utile_w * 8);713 aligned_height = round_up(level_height, utile_h * 8);714 break;715 case VC4_TILING_FORMAT_LT:716 aligned_width = round_up(level_width, utile_w);717 aligned_height = round_up(level_height, utile_h);718 break;719 default:720 aligned_width = round_up(level_width, utile_w);721 aligned_height = level_height;722 break;723 }724 725 level_size = aligned_width * cpp * aligned_height;726 727 if (offset < level_size) {728 DRM_DEBUG("Level %d (%dx%d -> %dx%d) size %db "729 "overflowed buffer bounds (offset %d)\n",730 i, level_width, level_height,731 aligned_width, aligned_height,732 level_size, offset);733 goto fail;734 }735 736 offset -= level_size;737 }738 739 *validated_p0 = tex->dma_addr + p0;740 741 if (is_cs) {742 exec->bin_dep_seqno = max(exec->bin_dep_seqno,743 to_vc4_bo(&tex->base)->write_seqno);744 }745 746 return true;747 fail:748 DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);749 DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1);750 DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2);751 DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3);752 return false;753}754 755static int756validate_gl_shader_rec(struct drm_device *dev,757 struct vc4_exec_info *exec,758 struct vc4_shader_state *state)759{760 uint32_t *src_handles;761 void *pkt_u, *pkt_v;762 static const uint32_t shader_reloc_offsets[] = {763 4, /* fs */764 16, /* vs */765 28, /* cs */766 };767 uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets);768 struct drm_gem_dma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8];769 uint32_t nr_attributes, nr_relocs, packet_size;770 int i;771 772 nr_attributes = state->addr & 0x7;773 if (nr_attributes == 0)774 nr_attributes = 8;775 packet_size = gl_shader_rec_size(state->addr);776 777 nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes;778 if (nr_relocs * 4 > exec->shader_rec_size) {779 DRM_DEBUG("overflowed shader recs reading %d handles "780 "from %d bytes left\n",781 nr_relocs, exec->shader_rec_size);782 return -EINVAL;783 }784 src_handles = exec->shader_rec_u;785 exec->shader_rec_u += nr_relocs * 4;786 exec->shader_rec_size -= nr_relocs * 4;787 788 if (packet_size > exec->shader_rec_size) {789 DRM_DEBUG("overflowed shader recs copying %db packet "790 "from %d bytes left\n",791 packet_size, exec->shader_rec_size);792 return -EINVAL;793 }794 pkt_u = exec->shader_rec_u;795 pkt_v = exec->shader_rec_v;796 memcpy(pkt_v, pkt_u, packet_size);797 exec->shader_rec_u += packet_size;798 /* Shader recs have to be aligned to 16 bytes (due to the attribute799 * flags being in the low bytes), so round the next validated shader800 * rec address up. This should be safe, since we've got so many801 * relocations in a shader rec packet.802 */803 BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4);804 exec->shader_rec_v += roundup(packet_size, 16);805 exec->shader_rec_size -= packet_size;806 807 for (i = 0; i < shader_reloc_count; i++) {808 if (src_handles[i] > exec->bo_count) {809 DRM_DEBUG("Shader handle %d too big\n", src_handles[i]);810 return -EINVAL;811 }812 813 bo[i] = to_drm_gem_dma_obj(exec->bo[src_handles[i]]);814 if (!bo[i])815 return -EINVAL;816 }817 for (i = shader_reloc_count; i < nr_relocs; i++) {818 bo[i] = vc4_use_bo(exec, src_handles[i]);819 if (!bo[i])820 return -EINVAL;821 }822 823 if (((*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD) == 0) !=824 to_vc4_bo(&bo[0]->base)->validated_shader->is_threaded) {825 DRM_DEBUG("Thread mode of CL and FS do not match\n");826 return -EINVAL;827 }828 829 if (to_vc4_bo(&bo[1]->base)->validated_shader->is_threaded ||830 to_vc4_bo(&bo[2]->base)->validated_shader->is_threaded) {831 DRM_DEBUG("cs and vs cannot be threaded\n");832 return -EINVAL;833 }834 835 for (i = 0; i < shader_reloc_count; i++) {836 struct vc4_validated_shader_info *validated_shader;837 uint32_t o = shader_reloc_offsets[i];838 uint32_t src_offset = *(uint32_t *)(pkt_u + o);839 uint32_t *texture_handles_u;840 void *uniform_data_u;841 uint32_t tex, uni;842 843 *(uint32_t *)(pkt_v + o) = bo[i]->dma_addr + src_offset;844 845 if (src_offset != 0) {846 DRM_DEBUG("Shaders must be at offset 0 of "847 "the BO.\n");848 return -EINVAL;849 }850 851 validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;852 if (!validated_shader)853 return -EINVAL;854 855 if (validated_shader->uniforms_src_size >856 exec->uniforms_size) {857 DRM_DEBUG("Uniforms src buffer overflow\n");858 return -EINVAL;859 }860 861 texture_handles_u = exec->uniforms_u;862 uniform_data_u = (texture_handles_u +863 validated_shader->num_texture_samples);864 865 memcpy(exec->uniforms_v, uniform_data_u,866 validated_shader->uniforms_size);867 868 for (tex = 0;869 tex < validated_shader->num_texture_samples;870 tex++) {871 if (!reloc_tex(exec,872 uniform_data_u,873 &validated_shader->texture_samples[tex],874 texture_handles_u[tex],875 i == 2)) {876 return -EINVAL;877 }878 }879 880 /* Fill in the uniform slots that need this shader's881 * start-of-uniforms address (used for resetting the uniform882 * stream in the presence of control flow).883 */884 for (uni = 0;885 uni < validated_shader->num_uniform_addr_offsets;886 uni++) {887 uint32_t o = validated_shader->uniform_addr_offsets[uni];888 ((uint32_t *)exec->uniforms_v)[o] = exec->uniforms_p;889 }890 891 *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;892 893 exec->uniforms_u += validated_shader->uniforms_src_size;894 exec->uniforms_v += validated_shader->uniforms_size;895 exec->uniforms_p += validated_shader->uniforms_size;896 }897 898 for (i = 0; i < nr_attributes; i++) {899 struct drm_gem_dma_object *vbo =900 bo[ARRAY_SIZE(shader_reloc_offsets) + i];901 uint32_t o = 36 + i * 8;902 uint32_t offset = *(uint32_t *)(pkt_u + o + 0);903 uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;904 uint32_t stride = *(uint8_t *)(pkt_u + o + 5);905 uint32_t max_index;906 907 exec->bin_dep_seqno = max(exec->bin_dep_seqno,908 to_vc4_bo(&vbo->base)->write_seqno);909 910 if (state->addr & 0x8)911 stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;912 913 if (vbo->base.size < offset ||914 vbo->base.size - offset < attr_size) {915 DRM_DEBUG("BO offset overflow (%d + %d > %zu)\n",916 offset, attr_size, vbo->base.size);917 return -EINVAL;918 }919 920 if (stride != 0) {921 max_index = ((vbo->base.size - offset - attr_size) /922 stride);923 if (state->max_index > max_index) {924 DRM_DEBUG("primitives use index %d out of "925 "supplied %d\n",926 state->max_index, max_index);927 return -EINVAL;928 }929 }930 931 *(uint32_t *)(pkt_v + o) = vbo->dma_addr + offset;932 }933 934 return 0;935}936 937int938vc4_validate_shader_recs(struct drm_device *dev,939 struct vc4_exec_info *exec)940{941 struct vc4_dev *vc4 = to_vc4_dev(dev);942 uint32_t i;943 int ret = 0;944 945 if (WARN_ON_ONCE(vc4->is_vc5))946 return -ENODEV;947 948 for (i = 0; i < exec->shader_state_count; i++) {949 ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]);950 if (ret)951 return ret;952 }953 954 return ret;955}956