From 2b16b3d75fa9350e358e80a4189d4f592c7394d4 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 22 Jul 2014 20:10:01 -0700 Subject: [PATCH] vc4: Fix things to validate more than one shader state in a submit. --- src/gallium/drivers/vc4/vc4_simulator.c | 17 ++- .../drivers/vc4/vc4_simulator_validate.c | 109 ++++++++++-------- .../drivers/vc4/vc4_simulator_validate.h | 17 ++- 3 files changed, 77 insertions(+), 66 deletions(-) diff --git a/src/gallium/drivers/vc4/vc4_simulator.c b/src/gallium/drivers/vc4/vc4_simulator.c index 0dada687911..879a1a3802b 100644 --- a/src/gallium/drivers/vc4/vc4_simulator.c +++ b/src/gallium/drivers/vc4/vc4_simulator.c @@ -105,7 +105,7 @@ vc4_cl_validate(struct drm_device *dev, struct exec_info *exec) { struct drm_vc4_submit_cl *args = exec->args; void *temp = NULL; - void *bin, *render, *shader_rec; + void *bin, *render; int ret = 0; uint32_t bin_offset = 0; uint32_t render_offset = bin_offset + args->bin_cl_len; @@ -142,7 +142,7 @@ vc4_cl_validate(struct drm_device *dev, struct exec_info *exec) } bin = temp + bin_offset; render = temp + render_offset; - shader_rec = temp + shader_rec_offset; + exec->shader_rec_u = temp + shader_rec_offset; exec->uniforms_u = temp + uniforms_offset; exec->shader_state = temp + exec_size; exec->shader_state_size = args->shader_record_count; @@ -159,7 +159,7 @@ vc4_cl_validate(struct drm_device *dev, struct exec_info *exec) goto fail; } - ret = copy_from_user(shader_rec, args->shader_records, + ret = copy_from_user(exec->shader_rec_u, args->shader_records, args->shader_record_len); if (ret) { DRM_ERROR("Failed to copy in shader recs\n"); @@ -187,7 +187,10 @@ vc4_cl_validate(struct drm_device *dev, struct exec_info *exec) exec->ct0ea = exec->ct0ca + args->bin_cl_len; exec->ct1ca = exec->exec_bo->paddr + render_offset; exec->ct1ea = exec->ct1ca + args->render_cl_len; - exec->shader_paddr = exec->exec_bo->paddr + shader_rec_offset; + + exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset; + exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset; + exec->shader_rec_size = args->shader_record_len; exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset; exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset; @@ -211,11 +214,7 @@ vc4_cl_validate(struct drm_device *dev, struct exec_info *exec) if (ret) goto fail; - ret = vc4_validate_shader_recs(dev, - exec->exec_bo->vaddr + shader_rec_offset, - shader_rec, - args->shader_record_len, - exec); + ret = vc4_validate_shader_recs(dev, exec); fail: kfree(temp); diff --git a/src/gallium/drivers/vc4/vc4_simulator_validate.c b/src/gallium/drivers/vc4/vc4_simulator_validate.c index a67e2345b11..d393517c414 100644 --- a/src/gallium/drivers/vc4/vc4_simulator_validate.c +++ b/src/gallium/drivers/vc4/vc4_simulator_validate.c @@ -47,6 +47,18 @@ void *validated, \ void *untrusted +static uint32_t +gl_shader_rec_size(uint32_t pointer_bits) +{ + uint32_t attribute_count = pointer_bits & 7; + bool extended = pointer_bits & 8; + + if (attribute_count == 0) + attribute_count = 8; + + return 36 + attribute_count * (extended ? 12 : 8); +} + static int validate_branch_to_sublist(VALIDATE_ARGS) { @@ -123,8 +135,15 @@ validate_gl_shader_state(VALIDATE_ARGS) exec->shader_state[i].packet = VC4_PACKET_GL_SHADER_STATE; exec->shader_state[i].addr = *(uint32_t *)untrusted; - *(uint32_t *)validated = exec->shader_state[i].addr + - exec->shader_paddr; + if (exec->shader_state[i].addr & ~0xf) { + DRM_ERROR("high bits set in GL shader rec reference\n"); + return -EINVAL; + } + + *(uint32_t *)validated = (exec->shader_rec_p + + exec->shader_state[i].addr); + + exec->shader_rec_p += gl_shader_rec_size(exec->shader_state[i].addr); return 0; } @@ -148,8 +167,8 @@ validate_nv_shader_state(VALIDATE_ARGS) return -EINVAL; } - *(uint32_t *)validated = - exec->shader_state[i].addr + exec->shader_paddr; + *(uint32_t *)validated = (exec->shader_state[i].addr + + exec->shader_rec_p); return 0; } @@ -374,14 +393,10 @@ reloc_tex(struct exec_info *exec, static int validate_shader_rec(struct drm_device *dev, struct exec_info *exec, - void *validated, - void *unvalidated, - uint32_t len, struct vc4_shader_state *state) { - uint32_t *src_handles = unvalidated; - void *src_pkt; - void *dst_pkt = validated; + uint32_t *src_handles; + void *pkt_u, *pkt_v; enum shader_rec_reloc_type { RELOC_CODE, RELOC_VBO, @@ -401,35 +416,49 @@ validate_shader_rec(struct drm_device *dev, }; const struct shader_rec_reloc *relocs; struct drm_gem_cma_object *bo[ARRAY_SIZE(gl_relocs) + 8]; - uint32_t nr_attributes = 0, nr_relocs, packet_size; + uint32_t nr_attributes = 0, nr_fixed_relocs, nr_relocs, packet_size; int i; struct vc4_validated_shader_info *validated_shader = NULL; if (state->packet == VC4_PACKET_NV_SHADER_STATE) { relocs = nv_relocs; - nr_relocs = ARRAY_SIZE(nv_relocs); + nr_fixed_relocs = ARRAY_SIZE(nv_relocs); packet_size = 16; } else { relocs = gl_relocs; - nr_relocs = ARRAY_SIZE(gl_relocs); + nr_fixed_relocs = ARRAY_SIZE(gl_relocs); nr_attributes = state->addr & 0x7; if (nr_attributes == 0) nr_attributes = 8; - packet_size = 36 + nr_attributes * 8; + packet_size = gl_shader_rec_size(state->addr); } - if ((nr_relocs + nr_attributes) * 4 + packet_size > len) { - DRM_ERROR("overflowed shader packet read " - "(handles %d, packet %d, len %d)\n", - (nr_relocs + nr_attributes) * 4, packet_size, len); + nr_relocs = nr_fixed_relocs + nr_attributes; + + if (nr_relocs * 4 > exec->shader_rec_size) { + DRM_ERROR("overflowed shader recs reading %d handles " + "from %d bytes left\n", + nr_relocs, exec->shader_rec_size); return -EINVAL; } + src_handles = exec->shader_rec_u; + exec->shader_rec_u += nr_relocs * 4; + exec->shader_rec_size -= nr_relocs * 4; - src_pkt = unvalidated + 4 * (nr_relocs + nr_attributes); - memcpy(dst_pkt, src_pkt, packet_size); + if (packet_size > exec->shader_rec_size) { + DRM_ERROR("overflowed shader recs copying %db packet " + "from %d bytes left\n", + packet_size, exec->shader_rec_size); + return -EINVAL; + } + pkt_u = exec->shader_rec_u; + pkt_v = exec->shader_rec_v; + memcpy(pkt_v, pkt_u, packet_size); + exec->shader_rec_u += packet_size; + exec->shader_rec_v += packet_size; - for (i = 0; i < nr_relocs + nr_attributes; i++) { + for (i = 0; i < nr_relocs; i++) { if (src_handles[i] >= exec->bo_count) { DRM_ERROR("shader rec bo index %d > %d\n", src_handles[i], exec->bo_count); @@ -438,14 +467,15 @@ validate_shader_rec(struct drm_device *dev, bo[i] = exec->bo[src_handles[i]]; } - for (i = 0; i < nr_relocs; i++) { + for (i = 0; i < nr_fixed_relocs; i++) { uint32_t o = relocs[i].offset; - uint32_t src_offset = *(uint32_t *)(src_pkt + o); - *(uint32_t *)(dst_pkt + o) = bo[i]->paddr + src_offset; + uint32_t src_offset = *(uint32_t *)(pkt_u + o); uint32_t *texture_handles_u; void *uniform_data_u; uint32_t tex; + *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset; + switch (relocs[i].type) { case RELOC_CODE: kfree(validated_shader); @@ -478,7 +508,7 @@ validate_shader_rec(struct drm_device *dev, } } - *(uint32_t *)(dst_pkt + o + 4) = exec->uniforms_p; + *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p; exec->uniforms_u += validated_shader->uniforms_src_size; exec->uniforms_v += validated_shader->uniforms_size; @@ -494,8 +524,8 @@ validate_shader_rec(struct drm_device *dev, for (i = 0; i < nr_attributes; i++) { /* XXX: validation */ uint32_t o = 36 + i * 8; - *(uint32_t *)(dst_pkt + o) = - bo[nr_relocs + i]->paddr + *(uint32_t *)(src_pkt + o); + *(uint32_t *)(pkt_v + o) = (bo[nr_fixed_relocs + i]->paddr + + *(uint32_t *)(pkt_u + o)); } kfree(validated_shader); @@ -509,38 +539,15 @@ fail: int vc4_validate_shader_recs(struct drm_device *dev, - void *validated, - void *unvalidated, - uint32_t len, struct exec_info *exec) { - uint32_t dst_offset = 0; - uint32_t src_offset = 0; uint32_t i; int ret = 0; for (i = 0; i < exec->shader_state_count; i++) { - if ((exec->shader_state[i].addr & ~0xf) != - (validated - exec->exec_bo->vaddr - - (exec->shader_paddr - exec->exec_bo->paddr))) { - DRM_ERROR("unexpected shader rec offset: " - "0x%08x vs 0x%08x\n", - exec->shader_state[i].addr & ~0xf, - (int)(validated - - exec->exec_bo->vaddr - - (exec->shader_paddr - - exec->exec_bo->paddr))); - return -EINVAL; - } - - ret = validate_shader_rec(dev, exec, - validated + dst_offset, - unvalidated + src_offset, - len - src_offset, - &exec->shader_state[i]); + ret = validate_shader_rec(dev, exec, &exec->shader_state[i]); if (ret) return ret; - /* XXX: incr dst/src offset */ } return ret; diff --git a/src/gallium/drivers/vc4/vc4_simulator_validate.h b/src/gallium/drivers/vc4/vc4_simulator_validate.h index 885a754a9d5..28dd2f65e70 100644 --- a/src/gallium/drivers/vc4/vc4_simulator_validate.h +++ b/src/gallium/drivers/vc4/vc4_simulator_validate.h @@ -114,7 +114,16 @@ struct exec_info { */ uint32_t ct0ca, ct0ea; uint32_t ct1ca, ct1ea; - uint32_t shader_paddr; + + /* Pointers to the shader recs. These paddr gets incremented as CL + * packets are relocated in validate_gl_shader_state, and the vaddrs + * (u and v) get incremented and size decremented as the shader recs + * themselves are validated. + */ + void *shader_rec_u; + void *shader_rec_v; + uint32_t shader_rec_p; + uint32_t shader_rec_size; /* Pointers to the uniform data. These pointers are incremented, and * size decremented, as each batch of uniforms is uploaded. @@ -168,11 +177,7 @@ int vc4_validate_cl(struct drm_device *dev, bool is_bin, struct exec_info *exec); -int vc4_validate_shader_recs(struct drm_device *dev, - void *validated, - void *unvalidated, - uint32_t len, - struct exec_info *exec); +int vc4_validate_shader_recs(struct drm_device *dev, struct exec_info *exec); struct vc4_validated_shader_info * vc4_validate_shader(struct drm_gem_cma_object *shader_obj,