162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright © 2014 Broadcom 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next 1262306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 1362306a36Sopenharmony_ci * Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2162306a36Sopenharmony_ci * IN THE SOFTWARE. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/** 2562306a36Sopenharmony_ci * DOC: Command list validator for VC4. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Since the VC4 has no IOMMU between it and system memory, a user 2862306a36Sopenharmony_ci * with access to execute command lists could escalate privilege by 2962306a36Sopenharmony_ci * overwriting system memory (drawing to it as a framebuffer) or 3062306a36Sopenharmony_ci * reading system memory it shouldn't (reading it as a vertex buffer 3162306a36Sopenharmony_ci * or index buffer) 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * We validate binner command lists to ensure that all accesses are 3462306a36Sopenharmony_ci * within the bounds of the GEM objects referenced by the submitted 3562306a36Sopenharmony_ci * job. It explicitly whitelists packets, and looks at the offsets in 3662306a36Sopenharmony_ci * any address fields to make sure they're contained within the BOs 3762306a36Sopenharmony_ci * they reference. 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * Note that because CL validation is already reading the 4062306a36Sopenharmony_ci * user-submitted CL and writing the validated copy out to the memory 4162306a36Sopenharmony_ci * that the GPU will actually read, this is also where GEM relocation 4262306a36Sopenharmony_ci * processing (turning BO references into actual addresses for the GPU 4362306a36Sopenharmony_ci * to use) happens. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include "uapi/drm/vc4_drm.h" 4762306a36Sopenharmony_ci#include "vc4_drv.h" 4862306a36Sopenharmony_ci#include "vc4_packet.h" 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define VALIDATE_ARGS \ 5162306a36Sopenharmony_ci struct vc4_exec_info *exec, \ 5262306a36Sopenharmony_ci void *validated, \ 5362306a36Sopenharmony_ci void *untrusted 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/** Return the width in pixels of a 64-byte microtile. */ 5662306a36Sopenharmony_cistatic uint32_t 5762306a36Sopenharmony_ciutile_width(int cpp) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci switch (cpp) { 6062306a36Sopenharmony_ci case 1: 6162306a36Sopenharmony_ci case 2: 6262306a36Sopenharmony_ci return 8; 6362306a36Sopenharmony_ci case 4: 6462306a36Sopenharmony_ci return 4; 6562306a36Sopenharmony_ci case 8: 6662306a36Sopenharmony_ci return 2; 6762306a36Sopenharmony_ci default: 6862306a36Sopenharmony_ci DRM_ERROR("unknown cpp: %d\n", cpp); 6962306a36Sopenharmony_ci return 1; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** Return the height in pixels of a 64-byte microtile. */ 7462306a36Sopenharmony_cistatic uint32_t 7562306a36Sopenharmony_ciutile_height(int cpp) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci switch (cpp) { 7862306a36Sopenharmony_ci case 1: 7962306a36Sopenharmony_ci return 8; 8062306a36Sopenharmony_ci case 2: 8162306a36Sopenharmony_ci case 4: 8262306a36Sopenharmony_ci case 8: 8362306a36Sopenharmony_ci return 4; 8462306a36Sopenharmony_ci default: 8562306a36Sopenharmony_ci DRM_ERROR("unknown cpp: %d\n", cpp); 8662306a36Sopenharmony_ci return 1; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/** 9162306a36Sopenharmony_ci * size_is_lt() - Returns whether a miplevel of the given size will 9262306a36Sopenharmony_ci * use the lineartile (LT) tiling layout rather than the normal T 9362306a36Sopenharmony_ci * tiling layout. 9462306a36Sopenharmony_ci * @width: Width in pixels of the miplevel 9562306a36Sopenharmony_ci * @height: Height in pixels of the miplevel 9662306a36Sopenharmony_ci * @cpp: Bytes per pixel of the pixel format 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_cistatic bool 9962306a36Sopenharmony_cisize_is_lt(uint32_t width, uint32_t height, int cpp) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return (width <= 4 * utile_width(cpp) || 10262306a36Sopenharmony_ci height <= 4 * utile_height(cpp)); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct drm_gem_dma_object * 10662306a36Sopenharmony_civc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct vc4_dev *vc4 = exec->dev; 10962306a36Sopenharmony_ci struct drm_gem_dma_object *obj; 11062306a36Sopenharmony_ci struct vc4_bo *bo; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (WARN_ON_ONCE(vc4->is_vc5)) 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (hindex >= exec->bo_count) { 11662306a36Sopenharmony_ci DRM_DEBUG("BO index %d greater than BO count %d\n", 11762306a36Sopenharmony_ci hindex, exec->bo_count); 11862306a36Sopenharmony_ci return NULL; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci obj = to_drm_gem_dma_obj(exec->bo[hindex]); 12162306a36Sopenharmony_ci bo = to_vc4_bo(&obj->base); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (bo->validated_shader) { 12462306a36Sopenharmony_ci DRM_DEBUG("Trying to use shader BO as something other than " 12562306a36Sopenharmony_ci "a shader\n"); 12662306a36Sopenharmony_ci return NULL; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return obj; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic struct drm_gem_dma_object * 13362306a36Sopenharmony_civc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic bool 13962306a36Sopenharmony_civalidate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci /* Note that the untrusted pointer passed to these functions is 14262306a36Sopenharmony_ci * incremented past the packet byte. 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ci return (untrusted - 1 == exec->bin_u + pos); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic uint32_t 14862306a36Sopenharmony_cigl_shader_rec_size(uint32_t pointer_bits) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci uint32_t attribute_count = pointer_bits & 7; 15162306a36Sopenharmony_ci bool extended = pointer_bits & 8; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (attribute_count == 0) 15462306a36Sopenharmony_ci attribute_count = 8; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (extended) 15762306a36Sopenharmony_ci return 100 + attribute_count * 4; 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci return 36 + attribute_count * 8; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cibool 16362306a36Sopenharmony_civc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_dma_object *fbo, 16462306a36Sopenharmony_ci uint32_t offset, uint8_t tiling_format, 16562306a36Sopenharmony_ci uint32_t width, uint32_t height, uint8_t cpp) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct vc4_dev *vc4 = exec->dev; 16862306a36Sopenharmony_ci uint32_t aligned_width, aligned_height, stride, size; 16962306a36Sopenharmony_ci uint32_t utile_w = utile_width(cpp); 17062306a36Sopenharmony_ci uint32_t utile_h = utile_height(cpp); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (WARN_ON_ONCE(vc4->is_vc5)) 17362306a36Sopenharmony_ci return false; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* The shaded vertex format stores signed 12.4 fixed point 17662306a36Sopenharmony_ci * (-2048,2047) offsets from the viewport center, so we should 17762306a36Sopenharmony_ci * never have a render target larger than 4096. The texture 17862306a36Sopenharmony_ci * unit can only sample from 2048x2048, so it's even more 17962306a36Sopenharmony_ci * restricted. This lets us avoid worrying about overflow in 18062306a36Sopenharmony_ci * our math. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (width > 4096 || height > 4096) { 18362306a36Sopenharmony_ci DRM_DEBUG("Surface dimensions (%d,%d) too large", 18462306a36Sopenharmony_ci width, height); 18562306a36Sopenharmony_ci return false; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci switch (tiling_format) { 18962306a36Sopenharmony_ci case VC4_TILING_FORMAT_LINEAR: 19062306a36Sopenharmony_ci aligned_width = round_up(width, utile_w); 19162306a36Sopenharmony_ci aligned_height = height; 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci case VC4_TILING_FORMAT_T: 19462306a36Sopenharmony_ci aligned_width = round_up(width, utile_w * 8); 19562306a36Sopenharmony_ci aligned_height = round_up(height, utile_h * 8); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci case VC4_TILING_FORMAT_LT: 19862306a36Sopenharmony_ci aligned_width = round_up(width, utile_w); 19962306a36Sopenharmony_ci aligned_height = round_up(height, utile_h); 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci default: 20262306a36Sopenharmony_ci DRM_DEBUG("buffer tiling %d unsupported\n", tiling_format); 20362306a36Sopenharmony_ci return false; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci stride = aligned_width * cpp; 20762306a36Sopenharmony_ci size = stride * aligned_height; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (size + offset < size || 21062306a36Sopenharmony_ci size + offset > fbo->base.size) { 21162306a36Sopenharmony_ci DRM_DEBUG("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n", 21262306a36Sopenharmony_ci width, height, 21362306a36Sopenharmony_ci aligned_width, aligned_height, 21462306a36Sopenharmony_ci size, offset, fbo->base.size); 21562306a36Sopenharmony_ci return false; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return true; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int 22262306a36Sopenharmony_civalidate_flush(VALIDATE_ARGS) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) { 22562306a36Sopenharmony_ci DRM_DEBUG("Bin CL must end with VC4_PACKET_FLUSH\n"); 22662306a36Sopenharmony_ci return -EINVAL; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci exec->found_flush = true; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int 23462306a36Sopenharmony_civalidate_start_tile_binning(VALIDATE_ARGS) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci if (exec->found_start_tile_binning_packet) { 23762306a36Sopenharmony_ci DRM_DEBUG("Duplicate VC4_PACKET_START_TILE_BINNING\n"); 23862306a36Sopenharmony_ci return -EINVAL; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci exec->found_start_tile_binning_packet = true; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!exec->found_tile_binning_mode_config_packet) { 24362306a36Sopenharmony_ci DRM_DEBUG("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); 24462306a36Sopenharmony_ci return -EINVAL; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int 25162306a36Sopenharmony_civalidate_increment_semaphore(VALIDATE_ARGS) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) { 25462306a36Sopenharmony_ci DRM_DEBUG("Bin CL must end with " 25562306a36Sopenharmony_ci "VC4_PACKET_INCREMENT_SEMAPHORE\n"); 25662306a36Sopenharmony_ci return -EINVAL; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci exec->found_increment_semaphore_packet = true; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int 26462306a36Sopenharmony_civalidate_indexed_prim_list(VALIDATE_ARGS) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct drm_gem_dma_object *ib; 26762306a36Sopenharmony_ci uint32_t length = *(uint32_t *)(untrusted + 1); 26862306a36Sopenharmony_ci uint32_t offset = *(uint32_t *)(untrusted + 5); 26962306a36Sopenharmony_ci uint32_t max_index = *(uint32_t *)(untrusted + 9); 27062306a36Sopenharmony_ci uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1; 27162306a36Sopenharmony_ci struct vc4_shader_state *shader_state; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Check overflow condition */ 27462306a36Sopenharmony_ci if (exec->shader_state_count == 0) { 27562306a36Sopenharmony_ci DRM_DEBUG("shader state must precede primitives\n"); 27662306a36Sopenharmony_ci return -EINVAL; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci shader_state = &exec->shader_state[exec->shader_state_count - 1]; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (max_index > shader_state->max_index) 28162306a36Sopenharmony_ci shader_state->max_index = max_index; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ib = vc4_use_handle(exec, 0); 28462306a36Sopenharmony_ci if (!ib) 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci exec->bin_dep_seqno = max(exec->bin_dep_seqno, 28862306a36Sopenharmony_ci to_vc4_bo(&ib->base)->write_seqno); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (offset > ib->base.size || 29162306a36Sopenharmony_ci (ib->base.size - offset) / index_size < length) { 29262306a36Sopenharmony_ci DRM_DEBUG("IB access overflow (%d + %d*%d > %zd)\n", 29362306a36Sopenharmony_ci offset, length, index_size, ib->base.size); 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci *(uint32_t *)(validated + 5) = ib->dma_addr + offset; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int 30362306a36Sopenharmony_civalidate_gl_array_primitive(VALIDATE_ARGS) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci uint32_t length = *(uint32_t *)(untrusted + 1); 30662306a36Sopenharmony_ci uint32_t base_index = *(uint32_t *)(untrusted + 5); 30762306a36Sopenharmony_ci uint32_t max_index; 30862306a36Sopenharmony_ci struct vc4_shader_state *shader_state; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Check overflow condition */ 31162306a36Sopenharmony_ci if (exec->shader_state_count == 0) { 31262306a36Sopenharmony_ci DRM_DEBUG("shader state must precede primitives\n"); 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci shader_state = &exec->shader_state[exec->shader_state_count - 1]; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (length + base_index < length) { 31862306a36Sopenharmony_ci DRM_DEBUG("primitive vertex count overflow\n"); 31962306a36Sopenharmony_ci return -EINVAL; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci max_index = length + base_index - 1; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (max_index > shader_state->max_index) 32462306a36Sopenharmony_ci shader_state->max_index = max_index; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int 33062306a36Sopenharmony_civalidate_gl_shader_state(VALIDATE_ARGS) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci uint32_t i = exec->shader_state_count++; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (i >= exec->shader_state_size) { 33562306a36Sopenharmony_ci DRM_DEBUG("More requests for shader states than declared\n"); 33662306a36Sopenharmony_ci return -EINVAL; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci exec->shader_state[i].addr = *(uint32_t *)untrusted; 34062306a36Sopenharmony_ci exec->shader_state[i].max_index = 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (exec->shader_state[i].addr & ~0xf) { 34362306a36Sopenharmony_ci DRM_DEBUG("high bits set in GL shader rec reference\n"); 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci *(uint32_t *)validated = (exec->shader_rec_p + 34862306a36Sopenharmony_ci exec->shader_state[i].addr); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci exec->shader_rec_p += 35162306a36Sopenharmony_ci roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int 35762306a36Sopenharmony_civalidate_tile_binning_config(VALIDATE_ARGS) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct drm_device *dev = exec->exec_bo->base.dev; 36062306a36Sopenharmony_ci struct vc4_dev *vc4 = to_vc4_dev(dev); 36162306a36Sopenharmony_ci uint8_t flags; 36262306a36Sopenharmony_ci uint32_t tile_state_size; 36362306a36Sopenharmony_ci uint32_t tile_count, bin_addr; 36462306a36Sopenharmony_ci int bin_slot; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (exec->found_tile_binning_mode_config_packet) { 36762306a36Sopenharmony_ci DRM_DEBUG("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); 36862306a36Sopenharmony_ci return -EINVAL; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci exec->found_tile_binning_mode_config_packet = true; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci exec->bin_tiles_x = *(uint8_t *)(untrusted + 12); 37362306a36Sopenharmony_ci exec->bin_tiles_y = *(uint8_t *)(untrusted + 13); 37462306a36Sopenharmony_ci tile_count = exec->bin_tiles_x * exec->bin_tiles_y; 37562306a36Sopenharmony_ci flags = *(uint8_t *)(untrusted + 14); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (exec->bin_tiles_x == 0 || 37862306a36Sopenharmony_ci exec->bin_tiles_y == 0) { 37962306a36Sopenharmony_ci DRM_DEBUG("Tile binning config of %dx%d too small\n", 38062306a36Sopenharmony_ci exec->bin_tiles_x, exec->bin_tiles_y); 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (flags & (VC4_BIN_CONFIG_DB_NON_MS | 38562306a36Sopenharmony_ci VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) { 38662306a36Sopenharmony_ci DRM_DEBUG("unsupported binning config flags 0x%02x\n", flags); 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci bin_slot = vc4_v3d_get_bin_slot(vc4); 39162306a36Sopenharmony_ci if (bin_slot < 0) { 39262306a36Sopenharmony_ci if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) { 39362306a36Sopenharmony_ci DRM_ERROR("Failed to allocate binner memory: %d\n", 39462306a36Sopenharmony_ci bin_slot); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci return bin_slot; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* The slot we allocated will only be used by this job, and is 40062306a36Sopenharmony_ci * free when the job completes rendering. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci exec->bin_slots |= BIT(bin_slot); 40362306a36Sopenharmony_ci bin_addr = vc4->bin_bo->base.dma_addr + bin_slot * vc4->bin_alloc_size; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* The tile state data array is 48 bytes per tile, and we put it at 40662306a36Sopenharmony_ci * the start of a BO containing both it and the tile alloc. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ci tile_state_size = 48 * tile_count; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Since the tile alloc array will follow us, align. */ 41162306a36Sopenharmony_ci exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci *(uint8_t *)(validated + 14) = 41462306a36Sopenharmony_ci ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | 41562306a36Sopenharmony_ci VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) | 41662306a36Sopenharmony_ci VC4_BIN_CONFIG_AUTO_INIT_TSDA | 41762306a36Sopenharmony_ci VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32, 41862306a36Sopenharmony_ci VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) | 41962306a36Sopenharmony_ci VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, 42062306a36Sopenharmony_ci VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* tile alloc address. */ 42362306a36Sopenharmony_ci *(uint32_t *)(validated + 0) = exec->tile_alloc_offset; 42462306a36Sopenharmony_ci /* tile alloc size. */ 42562306a36Sopenharmony_ci *(uint32_t *)(validated + 4) = (bin_addr + vc4->bin_alloc_size - 42662306a36Sopenharmony_ci exec->tile_alloc_offset); 42762306a36Sopenharmony_ci /* tile state address. */ 42862306a36Sopenharmony_ci *(uint32_t *)(validated + 8) = bin_addr; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int 43462306a36Sopenharmony_civalidate_gem_handles(VALIDATE_ARGS) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index)); 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#define VC4_DEFINE_PACKET(packet, func) \ 44162306a36Sopenharmony_ci [packet] = { packet ## _SIZE, #packet, func } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic const struct cmd_info { 44462306a36Sopenharmony_ci uint16_t len; 44562306a36Sopenharmony_ci const char *name; 44662306a36Sopenharmony_ci int (*func)(struct vc4_exec_info *exec, void *validated, 44762306a36Sopenharmony_ci void *untrusted); 44862306a36Sopenharmony_ci} cmd_info[] = { 44962306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL), 45062306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL), 45162306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush), 45262306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL), 45362306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, 45462306a36Sopenharmony_ci validate_start_tile_binning), 45562306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, 45662306a36Sopenharmony_ci validate_increment_semaphore), 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, 45962306a36Sopenharmony_ci validate_indexed_prim_list), 46062306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, 46162306a36Sopenharmony_ci validate_gl_array_primitive), 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL), 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state), 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL), 46862306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL), 46962306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL), 47062306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL), 47162306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL), 47262306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL), 47362306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL), 47462306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL), 47562306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL), 47662306a36Sopenharmony_ci /* Note: The docs say this was also 105, but it was 106 in the 47762306a36Sopenharmony_ci * initial userland code drop. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL), 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, 48262306a36Sopenharmony_ci validate_tile_binning_config), 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles), 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ciint 48862306a36Sopenharmony_civc4_validate_bin_cl(struct drm_device *dev, 48962306a36Sopenharmony_ci void *validated, 49062306a36Sopenharmony_ci void *unvalidated, 49162306a36Sopenharmony_ci struct vc4_exec_info *exec) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct vc4_dev *vc4 = to_vc4_dev(dev); 49462306a36Sopenharmony_ci uint32_t len = exec->args->bin_cl_size; 49562306a36Sopenharmony_ci uint32_t dst_offset = 0; 49662306a36Sopenharmony_ci uint32_t src_offset = 0; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (WARN_ON_ONCE(vc4->is_vc5)) 49962306a36Sopenharmony_ci return -ENODEV; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci while (src_offset < len) { 50262306a36Sopenharmony_ci void *dst_pkt = validated + dst_offset; 50362306a36Sopenharmony_ci void *src_pkt = unvalidated + src_offset; 50462306a36Sopenharmony_ci u8 cmd = *(uint8_t *)src_pkt; 50562306a36Sopenharmony_ci const struct cmd_info *info; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (cmd >= ARRAY_SIZE(cmd_info)) { 50862306a36Sopenharmony_ci DRM_DEBUG("0x%08x: packet %d out of bounds\n", 50962306a36Sopenharmony_ci src_offset, cmd); 51062306a36Sopenharmony_ci return -EINVAL; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci info = &cmd_info[cmd]; 51462306a36Sopenharmony_ci if (!info->name) { 51562306a36Sopenharmony_ci DRM_DEBUG("0x%08x: packet %d invalid\n", 51662306a36Sopenharmony_ci src_offset, cmd); 51762306a36Sopenharmony_ci return -EINVAL; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (src_offset + info->len > len) { 52162306a36Sopenharmony_ci DRM_DEBUG("0x%08x: packet %d (%s) length 0x%08x " 52262306a36Sopenharmony_ci "exceeds bounds (0x%08x)\n", 52362306a36Sopenharmony_ci src_offset, cmd, info->name, info->len, 52462306a36Sopenharmony_ci src_offset + len); 52562306a36Sopenharmony_ci return -EINVAL; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (cmd != VC4_PACKET_GEM_HANDLES) 52962306a36Sopenharmony_ci memcpy(dst_pkt, src_pkt, info->len); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (info->func && info->func(exec, 53262306a36Sopenharmony_ci dst_pkt + 1, 53362306a36Sopenharmony_ci src_pkt + 1)) { 53462306a36Sopenharmony_ci DRM_DEBUG("0x%08x: packet %d (%s) failed to validate\n", 53562306a36Sopenharmony_ci src_offset, cmd, info->name); 53662306a36Sopenharmony_ci return -EINVAL; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci src_offset += info->len; 54062306a36Sopenharmony_ci /* GEM handle loading doesn't produce HW packets. */ 54162306a36Sopenharmony_ci if (cmd != VC4_PACKET_GEM_HANDLES) 54262306a36Sopenharmony_ci dst_offset += info->len; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* When the CL hits halt, it'll stop reading anything else. */ 54562306a36Sopenharmony_ci if (cmd == VC4_PACKET_HALT) 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci exec->ct0ea = exec->ct0ca + dst_offset; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (!exec->found_start_tile_binning_packet) { 55262306a36Sopenharmony_ci DRM_DEBUG("Bin CL missing VC4_PACKET_START_TILE_BINNING\n"); 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The 55762306a36Sopenharmony_ci * semaphore is used to trigger the render CL to start up, and the 55862306a36Sopenharmony_ci * FLUSH is what caps the bin lists with 55962306a36Sopenharmony_ci * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main 56062306a36Sopenharmony_ci * render CL when they get called to) and actually triggers the queued 56162306a36Sopenharmony_ci * semaphore increment. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci if (!exec->found_increment_semaphore_packet || !exec->found_flush) { 56462306a36Sopenharmony_ci DRM_DEBUG("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + " 56562306a36Sopenharmony_ci "VC4_PACKET_FLUSH\n"); 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic bool 57362306a36Sopenharmony_cireloc_tex(struct vc4_exec_info *exec, 57462306a36Sopenharmony_ci void *uniform_data_u, 57562306a36Sopenharmony_ci struct vc4_texture_sample_info *sample, 57662306a36Sopenharmony_ci uint32_t texture_handle_index, bool is_cs) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct drm_gem_dma_object *tex; 57962306a36Sopenharmony_ci uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); 58062306a36Sopenharmony_ci uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]); 58162306a36Sopenharmony_ci uint32_t p2 = (sample->p_offset[2] != ~0 ? 58262306a36Sopenharmony_ci *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0); 58362306a36Sopenharmony_ci uint32_t p3 = (sample->p_offset[3] != ~0 ? 58462306a36Sopenharmony_ci *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0); 58562306a36Sopenharmony_ci uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0]; 58662306a36Sopenharmony_ci uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK; 58762306a36Sopenharmony_ci uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS); 58862306a36Sopenharmony_ci uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH); 58962306a36Sopenharmony_ci uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT); 59062306a36Sopenharmony_ci uint32_t cpp, tiling_format, utile_w, utile_h; 59162306a36Sopenharmony_ci uint32_t i; 59262306a36Sopenharmony_ci uint32_t cube_map_stride = 0; 59362306a36Sopenharmony_ci enum vc4_texture_data_type type; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci tex = vc4_use_bo(exec, texture_handle_index); 59662306a36Sopenharmony_ci if (!tex) 59762306a36Sopenharmony_ci return false; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (sample->is_direct) { 60062306a36Sopenharmony_ci uint32_t remaining_size = tex->base.size - p0; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (p0 > tex->base.size - 4) { 60362306a36Sopenharmony_ci DRM_DEBUG("UBO offset greater than UBO size\n"); 60462306a36Sopenharmony_ci goto fail; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci if (p1 > remaining_size - 4) { 60762306a36Sopenharmony_ci DRM_DEBUG("UBO clamp would allow reads " 60862306a36Sopenharmony_ci "outside of UBO\n"); 60962306a36Sopenharmony_ci goto fail; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci *validated_p0 = tex->dma_addr + p0; 61262306a36Sopenharmony_ci return true; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (width == 0) 61662306a36Sopenharmony_ci width = 2048; 61762306a36Sopenharmony_ci if (height == 0) 61862306a36Sopenharmony_ci height = 2048; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (p0 & VC4_TEX_P0_CMMODE_MASK) { 62162306a36Sopenharmony_ci if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) == 62262306a36Sopenharmony_ci VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) 62362306a36Sopenharmony_ci cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK; 62462306a36Sopenharmony_ci if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) == 62562306a36Sopenharmony_ci VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) { 62662306a36Sopenharmony_ci if (cube_map_stride) { 62762306a36Sopenharmony_ci DRM_DEBUG("Cube map stride set twice\n"); 62862306a36Sopenharmony_ci goto fail; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci if (!cube_map_stride) { 63462306a36Sopenharmony_ci DRM_DEBUG("Cube map stride not set\n"); 63562306a36Sopenharmony_ci goto fail; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) | 64062306a36Sopenharmony_ci (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4)); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci switch (type) { 64362306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGBA8888: 64462306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGBX8888: 64562306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGBA32R: 64662306a36Sopenharmony_ci cpp = 4; 64762306a36Sopenharmony_ci break; 64862306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGBA4444: 64962306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGBA5551: 65062306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGB565: 65162306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_LUMALPHA: 65262306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_S16F: 65362306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_S16: 65462306a36Sopenharmony_ci cpp = 2; 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_LUMINANCE: 65762306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_ALPHA: 65862306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_S8: 65962306a36Sopenharmony_ci cpp = 1; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_ETC1: 66262306a36Sopenharmony_ci /* ETC1 is arranged as 64-bit blocks, where each block is 4x4 66362306a36Sopenharmony_ci * pixels. 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci cpp = 8; 66662306a36Sopenharmony_ci width = (width + 3) >> 2; 66762306a36Sopenharmony_ci height = (height + 3) >> 2; 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_BW1: 67062306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_A4: 67162306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_A1: 67262306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_RGBA64: 67362306a36Sopenharmony_ci case VC4_TEXTURE_TYPE_YUV422R: 67462306a36Sopenharmony_ci default: 67562306a36Sopenharmony_ci DRM_DEBUG("Texture format %d unsupported\n", type); 67662306a36Sopenharmony_ci goto fail; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci utile_w = utile_width(cpp); 67962306a36Sopenharmony_ci utile_h = utile_height(cpp); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (type == VC4_TEXTURE_TYPE_RGBA32R) { 68262306a36Sopenharmony_ci tiling_format = VC4_TILING_FORMAT_LINEAR; 68362306a36Sopenharmony_ci } else { 68462306a36Sopenharmony_ci if (size_is_lt(width, height, cpp)) 68562306a36Sopenharmony_ci tiling_format = VC4_TILING_FORMAT_LT; 68662306a36Sopenharmony_ci else 68762306a36Sopenharmony_ci tiling_format = VC4_TILING_FORMAT_T; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5, 69162306a36Sopenharmony_ci tiling_format, width, height, cpp)) { 69262306a36Sopenharmony_ci goto fail; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* The mipmap levels are stored before the base of the texture. Make 69662306a36Sopenharmony_ci * sure there is actually space in the BO. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci for (i = 1; i <= miplevels; i++) { 69962306a36Sopenharmony_ci uint32_t level_width = max(width >> i, 1u); 70062306a36Sopenharmony_ci uint32_t level_height = max(height >> i, 1u); 70162306a36Sopenharmony_ci uint32_t aligned_width, aligned_height; 70262306a36Sopenharmony_ci uint32_t level_size; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* Once the levels get small enough, they drop from T to LT. */ 70562306a36Sopenharmony_ci if (tiling_format == VC4_TILING_FORMAT_T && 70662306a36Sopenharmony_ci size_is_lt(level_width, level_height, cpp)) { 70762306a36Sopenharmony_ci tiling_format = VC4_TILING_FORMAT_LT; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci switch (tiling_format) { 71162306a36Sopenharmony_ci case VC4_TILING_FORMAT_T: 71262306a36Sopenharmony_ci aligned_width = round_up(level_width, utile_w * 8); 71362306a36Sopenharmony_ci aligned_height = round_up(level_height, utile_h * 8); 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci case VC4_TILING_FORMAT_LT: 71662306a36Sopenharmony_ci aligned_width = round_up(level_width, utile_w); 71762306a36Sopenharmony_ci aligned_height = round_up(level_height, utile_h); 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci default: 72062306a36Sopenharmony_ci aligned_width = round_up(level_width, utile_w); 72162306a36Sopenharmony_ci aligned_height = level_height; 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci level_size = aligned_width * cpp * aligned_height; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (offset < level_size) { 72862306a36Sopenharmony_ci DRM_DEBUG("Level %d (%dx%d -> %dx%d) size %db " 72962306a36Sopenharmony_ci "overflowed buffer bounds (offset %d)\n", 73062306a36Sopenharmony_ci i, level_width, level_height, 73162306a36Sopenharmony_ci aligned_width, aligned_height, 73262306a36Sopenharmony_ci level_size, offset); 73362306a36Sopenharmony_ci goto fail; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci offset -= level_size; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci *validated_p0 = tex->dma_addr + p0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (is_cs) { 74262306a36Sopenharmony_ci exec->bin_dep_seqno = max(exec->bin_dep_seqno, 74362306a36Sopenharmony_ci to_vc4_bo(&tex->base)->write_seqno); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci return true; 74762306a36Sopenharmony_ci fail: 74862306a36Sopenharmony_ci DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0); 74962306a36Sopenharmony_ci DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1); 75062306a36Sopenharmony_ci DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2); 75162306a36Sopenharmony_ci DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3); 75262306a36Sopenharmony_ci return false; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int 75662306a36Sopenharmony_civalidate_gl_shader_rec(struct drm_device *dev, 75762306a36Sopenharmony_ci struct vc4_exec_info *exec, 75862306a36Sopenharmony_ci struct vc4_shader_state *state) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci uint32_t *src_handles; 76162306a36Sopenharmony_ci void *pkt_u, *pkt_v; 76262306a36Sopenharmony_ci static const uint32_t shader_reloc_offsets[] = { 76362306a36Sopenharmony_ci 4, /* fs */ 76462306a36Sopenharmony_ci 16, /* vs */ 76562306a36Sopenharmony_ci 28, /* cs */ 76662306a36Sopenharmony_ci }; 76762306a36Sopenharmony_ci uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); 76862306a36Sopenharmony_ci struct drm_gem_dma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8]; 76962306a36Sopenharmony_ci uint32_t nr_attributes, nr_relocs, packet_size; 77062306a36Sopenharmony_ci int i; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci nr_attributes = state->addr & 0x7; 77362306a36Sopenharmony_ci if (nr_attributes == 0) 77462306a36Sopenharmony_ci nr_attributes = 8; 77562306a36Sopenharmony_ci packet_size = gl_shader_rec_size(state->addr); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes; 77862306a36Sopenharmony_ci if (nr_relocs * 4 > exec->shader_rec_size) { 77962306a36Sopenharmony_ci DRM_DEBUG("overflowed shader recs reading %d handles " 78062306a36Sopenharmony_ci "from %d bytes left\n", 78162306a36Sopenharmony_ci nr_relocs, exec->shader_rec_size); 78262306a36Sopenharmony_ci return -EINVAL; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci src_handles = exec->shader_rec_u; 78562306a36Sopenharmony_ci exec->shader_rec_u += nr_relocs * 4; 78662306a36Sopenharmony_ci exec->shader_rec_size -= nr_relocs * 4; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (packet_size > exec->shader_rec_size) { 78962306a36Sopenharmony_ci DRM_DEBUG("overflowed shader recs copying %db packet " 79062306a36Sopenharmony_ci "from %d bytes left\n", 79162306a36Sopenharmony_ci packet_size, exec->shader_rec_size); 79262306a36Sopenharmony_ci return -EINVAL; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci pkt_u = exec->shader_rec_u; 79562306a36Sopenharmony_ci pkt_v = exec->shader_rec_v; 79662306a36Sopenharmony_ci memcpy(pkt_v, pkt_u, packet_size); 79762306a36Sopenharmony_ci exec->shader_rec_u += packet_size; 79862306a36Sopenharmony_ci /* Shader recs have to be aligned to 16 bytes (due to the attribute 79962306a36Sopenharmony_ci * flags being in the low bytes), so round the next validated shader 80062306a36Sopenharmony_ci * rec address up. This should be safe, since we've got so many 80162306a36Sopenharmony_ci * relocations in a shader rec packet. 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4); 80462306a36Sopenharmony_ci exec->shader_rec_v += roundup(packet_size, 16); 80562306a36Sopenharmony_ci exec->shader_rec_size -= packet_size; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci for (i = 0; i < shader_reloc_count; i++) { 80862306a36Sopenharmony_ci if (src_handles[i] > exec->bo_count) { 80962306a36Sopenharmony_ci DRM_DEBUG("Shader handle %d too big\n", src_handles[i]); 81062306a36Sopenharmony_ci return -EINVAL; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci bo[i] = to_drm_gem_dma_obj(exec->bo[src_handles[i]]); 81462306a36Sopenharmony_ci if (!bo[i]) 81562306a36Sopenharmony_ci return -EINVAL; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci for (i = shader_reloc_count; i < nr_relocs; i++) { 81862306a36Sopenharmony_ci bo[i] = vc4_use_bo(exec, src_handles[i]); 81962306a36Sopenharmony_ci if (!bo[i]) 82062306a36Sopenharmony_ci return -EINVAL; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (((*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD) == 0) != 82462306a36Sopenharmony_ci to_vc4_bo(&bo[0]->base)->validated_shader->is_threaded) { 82562306a36Sopenharmony_ci DRM_DEBUG("Thread mode of CL and FS do not match\n"); 82662306a36Sopenharmony_ci return -EINVAL; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (to_vc4_bo(&bo[1]->base)->validated_shader->is_threaded || 83062306a36Sopenharmony_ci to_vc4_bo(&bo[2]->base)->validated_shader->is_threaded) { 83162306a36Sopenharmony_ci DRM_DEBUG("cs and vs cannot be threaded\n"); 83262306a36Sopenharmony_ci return -EINVAL; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci for (i = 0; i < shader_reloc_count; i++) { 83662306a36Sopenharmony_ci struct vc4_validated_shader_info *validated_shader; 83762306a36Sopenharmony_ci uint32_t o = shader_reloc_offsets[i]; 83862306a36Sopenharmony_ci uint32_t src_offset = *(uint32_t *)(pkt_u + o); 83962306a36Sopenharmony_ci uint32_t *texture_handles_u; 84062306a36Sopenharmony_ci void *uniform_data_u; 84162306a36Sopenharmony_ci uint32_t tex, uni; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci *(uint32_t *)(pkt_v + o) = bo[i]->dma_addr + src_offset; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (src_offset != 0) { 84662306a36Sopenharmony_ci DRM_DEBUG("Shaders must be at offset 0 of " 84762306a36Sopenharmony_ci "the BO.\n"); 84862306a36Sopenharmony_ci return -EINVAL; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader; 85262306a36Sopenharmony_ci if (!validated_shader) 85362306a36Sopenharmony_ci return -EINVAL; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (validated_shader->uniforms_src_size > 85662306a36Sopenharmony_ci exec->uniforms_size) { 85762306a36Sopenharmony_ci DRM_DEBUG("Uniforms src buffer overflow\n"); 85862306a36Sopenharmony_ci return -EINVAL; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci texture_handles_u = exec->uniforms_u; 86262306a36Sopenharmony_ci uniform_data_u = (texture_handles_u + 86362306a36Sopenharmony_ci validated_shader->num_texture_samples); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci memcpy(exec->uniforms_v, uniform_data_u, 86662306a36Sopenharmony_ci validated_shader->uniforms_size); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci for (tex = 0; 86962306a36Sopenharmony_ci tex < validated_shader->num_texture_samples; 87062306a36Sopenharmony_ci tex++) { 87162306a36Sopenharmony_ci if (!reloc_tex(exec, 87262306a36Sopenharmony_ci uniform_data_u, 87362306a36Sopenharmony_ci &validated_shader->texture_samples[tex], 87462306a36Sopenharmony_ci texture_handles_u[tex], 87562306a36Sopenharmony_ci i == 2)) { 87662306a36Sopenharmony_ci return -EINVAL; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* Fill in the uniform slots that need this shader's 88162306a36Sopenharmony_ci * start-of-uniforms address (used for resetting the uniform 88262306a36Sopenharmony_ci * stream in the presence of control flow). 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci for (uni = 0; 88562306a36Sopenharmony_ci uni < validated_shader->num_uniform_addr_offsets; 88662306a36Sopenharmony_ci uni++) { 88762306a36Sopenharmony_ci uint32_t o = validated_shader->uniform_addr_offsets[uni]; 88862306a36Sopenharmony_ci ((uint32_t *)exec->uniforms_v)[o] = exec->uniforms_p; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci exec->uniforms_u += validated_shader->uniforms_src_size; 89462306a36Sopenharmony_ci exec->uniforms_v += validated_shader->uniforms_size; 89562306a36Sopenharmony_ci exec->uniforms_p += validated_shader->uniforms_size; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci for (i = 0; i < nr_attributes; i++) { 89962306a36Sopenharmony_ci struct drm_gem_dma_object *vbo = 90062306a36Sopenharmony_ci bo[ARRAY_SIZE(shader_reloc_offsets) + i]; 90162306a36Sopenharmony_ci uint32_t o = 36 + i * 8; 90262306a36Sopenharmony_ci uint32_t offset = *(uint32_t *)(pkt_u + o + 0); 90362306a36Sopenharmony_ci uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1; 90462306a36Sopenharmony_ci uint32_t stride = *(uint8_t *)(pkt_u + o + 5); 90562306a36Sopenharmony_ci uint32_t max_index; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci exec->bin_dep_seqno = max(exec->bin_dep_seqno, 90862306a36Sopenharmony_ci to_vc4_bo(&vbo->base)->write_seqno); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (state->addr & 0x8) 91162306a36Sopenharmony_ci stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (vbo->base.size < offset || 91462306a36Sopenharmony_ci vbo->base.size - offset < attr_size) { 91562306a36Sopenharmony_ci DRM_DEBUG("BO offset overflow (%d + %d > %zu)\n", 91662306a36Sopenharmony_ci offset, attr_size, vbo->base.size); 91762306a36Sopenharmony_ci return -EINVAL; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (stride != 0) { 92162306a36Sopenharmony_ci max_index = ((vbo->base.size - offset - attr_size) / 92262306a36Sopenharmony_ci stride); 92362306a36Sopenharmony_ci if (state->max_index > max_index) { 92462306a36Sopenharmony_ci DRM_DEBUG("primitives use index %d out of " 92562306a36Sopenharmony_ci "supplied %d\n", 92662306a36Sopenharmony_ci state->max_index, max_index); 92762306a36Sopenharmony_ci return -EINVAL; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci *(uint32_t *)(pkt_v + o) = vbo->dma_addr + offset; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return 0; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ciint 93862306a36Sopenharmony_civc4_validate_shader_recs(struct drm_device *dev, 93962306a36Sopenharmony_ci struct vc4_exec_info *exec) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct vc4_dev *vc4 = to_vc4_dev(dev); 94262306a36Sopenharmony_ci uint32_t i; 94362306a36Sopenharmony_ci int ret = 0; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (WARN_ON_ONCE(vc4->is_vc5)) 94662306a36Sopenharmony_ci return -ENODEV; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci for (i = 0; i < exec->shader_state_count; i++) { 94962306a36Sopenharmony_ci ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]); 95062306a36Sopenharmony_ci if (ret) 95162306a36Sopenharmony_ci return ret; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return ret; 95562306a36Sopenharmony_ci} 956