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