diff options
author | Eric Anholt <[email protected]> | 2014-09-30 16:25:48 -0700 |
---|---|---|
committer | Eric Anholt <[email protected]> | 2014-10-09 09:46:39 +0200 |
commit | 0b96a086cbb4bcf0a5aab1fee6d77c1e40295297 (patch) | |
tree | 469717fdc6feed1f4ab6a3d391782d2d14da6abf /src/gallium/drivers/vc4/vc4_simulator_validate_shaders.c | |
parent | ef9914aa7481e483d6a12f35ed4eb46b26d17235 (diff) |
vc4: Move the mirrored kernel code to a kernel/ directory.
Now this whole setup matches the kernel's file layout much more closely.
Diffstat (limited to 'src/gallium/drivers/vc4/vc4_simulator_validate_shaders.c')
-rw-r--r-- | src/gallium/drivers/vc4/vc4_simulator_validate_shaders.c | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/src/gallium/drivers/vc4/vc4_simulator_validate_shaders.c b/src/gallium/drivers/vc4/vc4_simulator_validate_shaders.c deleted file mode 100644 index 183cd4c977e..00000000000 --- a/src/gallium/drivers/vc4/vc4_simulator_validate_shaders.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright © 2014 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/** - * DOC: Shader validator for VC4. - * - * The VC4 has no IOMMU between it and system memory. So, a user with access - * to execute shaders could escalate privilege by overwriting system memory - * (using the VPM write address register in the general-purpose DMA mode) or - * reading system memory it shouldn't (reading it as a texture, or uniform - * data, or vertex data). - * - * This walks over a shader starting from some offset within a BO, ensuring - * that its accesses are appropriately bounded, and recording how many texture - * accesses are made and where so that we can do relocations for them in the - * uniform stream. - * - * The kernel API has shaders stored in user-mapped BOs. The BOs will be - * forcibly unmapped from the process before validation, and any cache of - * validated state will be flushed if the mapping is faulted back in. - * - * Storing the shaders in BOs means that the validation process will be slow - * due to uncached reads, but since shaders are long-lived and shader BOs are - * never actually modified, this shouldn't be a problem. - */ - -#include "vc4_simulator_validate.h" -#include "vc4_qpu.h" -#include "vc4_qpu_defines.h" - -struct vc4_shader_validation_state { - struct vc4_texture_sample_info tmu_setup[2]; - int tmu_write_count[2]; -}; - -static bool -is_tmu_write(uint32_t waddr) -{ - return (waddr >= QPU_W_TMU0_S && - waddr <= QPU_W_TMU1_B); -} - -static bool -record_validated_texture_sample(struct vc4_validated_shader_info *validated_shader, - struct vc4_shader_validation_state *validation_state, - int tmu) -{ - uint32_t s = validated_shader->num_texture_samples; - int i; - struct vc4_texture_sample_info *temp_samples; - - temp_samples = krealloc(validated_shader->texture_samples, - (s + 1) * sizeof(*temp_samples), - GFP_KERNEL); - if (!temp_samples) - return false; - - memcpy(temp_samples[s].p_offset, - validation_state->tmu_setup[tmu].p_offset, - validation_state->tmu_write_count[tmu] * sizeof(uint32_t)); - for (i = validation_state->tmu_write_count[tmu]; i < 4; i++) - temp_samples[s].p_offset[i] = ~0; - - validated_shader->num_texture_samples = s + 1; - validated_shader->texture_samples = temp_samples; - - return true; -} - -static bool -check_tmu_write(struct vc4_validated_shader_info *validated_shader, - struct vc4_shader_validation_state *validation_state, - uint32_t waddr) -{ - int tmu = waddr > QPU_W_TMU0_B; - - if (!is_tmu_write(waddr)) - return true; - - if (validation_state->tmu_write_count[tmu] >= 4) { - DRM_ERROR("TMU%d got too many parameters before dispatch\n", - tmu); - return false; - } - validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] = - validated_shader->uniforms_size; - validation_state->tmu_write_count[tmu]++; - validated_shader->uniforms_size += 4; - - if (waddr == QPU_W_TMU0_S || waddr == QPU_W_TMU1_S) { - if (!record_validated_texture_sample(validated_shader, - validation_state, tmu)) { - return false; - } - - validation_state->tmu_write_count[tmu] = 0; - } - - return true; -} - -static bool -check_register_write(struct vc4_validated_shader_info *validated_shader, - struct vc4_shader_validation_state *validation_state, - uint32_t waddr) -{ - switch (waddr) { - case QPU_W_UNIFORMS_ADDRESS: - /* XXX: We'll probably need to support this for reladdr, but - * it's definitely a security-related one. - */ - DRM_ERROR("uniforms address load unsupported\n"); - return false; - - case QPU_W_TLB_COLOR_MS: - case QPU_W_TLB_COLOR_ALL: - case QPU_W_TLB_Z: - /* These only interact with the tile buffer, not main memory, - * so they're safe. - */ - return true; - - case QPU_W_TMU0_S: - case QPU_W_TMU0_T: - case QPU_W_TMU0_R: - case QPU_W_TMU0_B: - case QPU_W_TMU1_S: - case QPU_W_TMU1_T: - case QPU_W_TMU1_R: - case QPU_W_TMU1_B: - return check_tmu_write(validated_shader, validation_state, - waddr); - - case QPU_W_HOST_INT: - case QPU_W_TMU_NOSWAP: - case QPU_W_TLB_ALPHA_MASK: - case QPU_W_MUTEX_RELEASE: - /* XXX: I haven't thought about these, so don't support them - * for now. - */ - DRM_ERROR("Unsupported waddr %d\n", waddr); - return false; - - case QPU_W_VPM_ADDR: - DRM_ERROR("General VPM DMA unsupported\n"); - return false; - - case QPU_W_VPM: - case QPU_W_VPMVCD_SETUP: - /* We allow VPM setup in general, even including VPM DMA - * configuration setup, because the (unsafe) DMA can only be - * triggered by QPU_W_VPM_ADDR writes. - */ - return true; - - case QPU_W_TLB_STENCIL_SETUP: - return true; - } - - return true; -} - -static bool -check_instruction_writes(uint64_t inst, - struct vc4_validated_shader_info *validated_shader, - struct vc4_shader_validation_state *validation_state) -{ - uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD); - uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL); - - if (is_tmu_write(waddr_add) && is_tmu_write(waddr_mul)) { - DRM_ERROR("ADD and MUL both set up textures\n"); - return false; - } - - return (check_register_write(validated_shader, validation_state, waddr_add) && - check_register_write(validated_shader, validation_state, waddr_mul)); -} - -static bool -check_instruction_reads(uint64_t inst, - struct vc4_validated_shader_info *validated_shader) -{ - uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD); - uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL); - uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); - uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); - - if (raddr_a == QPU_R_UNIF || - raddr_b == QPU_R_UNIF) { - if (is_tmu_write(waddr_add) || is_tmu_write(waddr_mul)) { - DRM_ERROR("uniform read in the same instruction as " - "texture setup"); - return false; - } - - /* This can't overflow the uint32_t, because we're reading 8 - * bytes of instruction to increment by 4 here, so we'd - * already be OOM. - */ - validated_shader->uniforms_size += 4; - } - - return true; -} - -struct vc4_validated_shader_info * -vc4_validate_shader(struct drm_gem_cma_object *shader_obj, - uint32_t start_offset) -{ - bool found_shader_end = false; - int shader_end_ip = 0; - uint32_t ip, max_ip; - uint64_t *shader; - struct vc4_validated_shader_info *validated_shader; - struct vc4_shader_validation_state validation_state; - - memset(&validation_state, 0, sizeof(validation_state)); - - if (start_offset + sizeof(uint64_t) > shader_obj->base.size) { - DRM_ERROR("shader starting at %d outside of BO sized %d\n", - start_offset, - shader_obj->base.size); - return NULL; - } - shader = shader_obj->vaddr + start_offset; - max_ip = (shader_obj->base.size - start_offset) / sizeof(uint64_t); - - validated_shader = kcalloc(sizeof(*validated_shader), 1, GFP_KERNEL); - if (!validated_shader) - return NULL; - - for (ip = 0; ip < max_ip; ip++) { - uint64_t inst = shader[ip]; - uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); - - switch (sig) { - case QPU_SIG_NONE: - case QPU_SIG_WAIT_FOR_SCOREBOARD: - case QPU_SIG_SCOREBOARD_UNLOCK: - case QPU_SIG_COLOR_LOAD: - case QPU_SIG_LOAD_TMU0: - case QPU_SIG_LOAD_TMU1: - if (!check_instruction_writes(inst, validated_shader, - &validation_state)) { - DRM_ERROR("Bad write at ip %d\n", ip); - goto fail; - } - - if (!check_instruction_reads(inst, validated_shader)) - goto fail; - - break; - - case QPU_SIG_LOAD_IMM: - if (!check_instruction_writes(inst, validated_shader, - &validation_state)) { - DRM_ERROR("Bad LOAD_IMM write at ip %d\n", ip); - goto fail; - } - break; - - case QPU_SIG_PROG_END: - found_shader_end = true; - shader_end_ip = ip; - break; - - default: - DRM_ERROR("Unsupported QPU signal %d at " - "instruction %d\n", sig, ip); - goto fail; - } - - /* There are two delay slots after program end is signaled - * that are still executed, then we're finished. - */ - if (found_shader_end && ip == shader_end_ip + 2) - break; - } - - if (ip == max_ip) { - DRM_ERROR("shader starting at %d failed to terminate before " - "shader BO end at %d\n", - start_offset, - shader_obj->base.size); - goto fail; - } - - /* Again, no chance of integer overflow here because the worst case - * scenario is 8 bytes of uniforms plus handles per 8-byte - * instruction. - */ - validated_shader->uniforms_src_size = - (validated_shader->uniforms_size + - 4 * validated_shader->num_texture_samples); - - return validated_shader; - -fail: - kfree(validated_shader); - return NULL; -} |