2 * Copyright © 2014 Broadcom
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * Command list validator for VC4.
27 * The VC4 has no IOMMU between it and system memory. So, a user with
28 * access to execute command lists could escalate privilege by
29 * overwriting system memory (drawing to it as a framebuffer) or
30 * reading system memory it shouldn't (reading it as a texture, or
31 * uniform data, or vertex data).
33 * This validates command lists to ensure that all accesses are within
34 * the bounds of the GEM objects referenced. It explicitly whitelists
35 * packets, and looks at the offsets in any address fields to make
36 * sure they're constrained within the BOs they reference.
38 * Note that because of the validation that's happening anyway, this
39 * is where GEM relocation processing happens.
42 #include "vc4_simulator_validate.h"
43 #include "vc4_packet.h"
45 #define VALIDATE_ARGS \
46 struct exec_info *exec, \
51 vc4_use_bo(struct exec_info
*exec
,
53 enum vc4_bo_mode mode
,
54 struct drm_gem_cma_object
**obj
)
58 if (hindex
>= exec
->bo_count
) {
59 DRM_ERROR("BO index %d greater than BO count %d\n",
60 hindex
, exec
->bo_count
);
64 if (exec
->bo
[hindex
].mode
!= mode
) {
65 if (exec
->bo
[hindex
].mode
== VC4_MODE_UNDECIDED
) {
66 exec
->bo
[hindex
].mode
= mode
;
68 DRM_ERROR("BO index %d reused with mode %d vs %d\n",
69 hindex
, exec
->bo
[hindex
].mode
, mode
);
74 *obj
= exec
->bo
[hindex
].bo
;
79 vc4_use_handle(struct exec_info
*exec
,
80 uint32_t gem_handles_packet_index
,
81 enum vc4_bo_mode mode
,
82 struct drm_gem_cma_object
**obj
)
84 return vc4_use_bo(exec
, exec
->bo_index
[gem_handles_packet_index
],
89 gl_shader_rec_size(uint32_t pointer_bits
)
91 uint32_t attribute_count
= pointer_bits
& 7;
92 bool extended
= pointer_bits
& 8;
94 if (attribute_count
== 0)
97 return 36 + attribute_count
* (extended
? 12 : 8);
101 check_fbo_size(struct exec_info
*exec
, struct drm_gem_cma_object
*fbo
,
102 uint32_t offset
, uint8_t tiling_format
, uint8_t cpp
)
104 uint32_t width_align
, height_align
;
105 uint32_t aligned_row_len
, aligned_h
, size
;
107 switch (tiling_format
) {
108 case VC4_TILING_FORMAT_LINEAR
:
112 case VC4_TILING_FORMAT_T
:
116 case VC4_TILING_FORMAT_LT
:
121 DRM_ERROR("buffer tiling %d unsupported\n", tiling_format
);
125 /* The values are limited by the packet bitfields, so we don't need to
126 * worry as much about integer overflow.
128 BUG_ON(exec
->fb_width
> 65535);
129 BUG_ON(exec
->fb_height
> 65535);
131 aligned_row_len
= roundup(exec
->fb_width
* cpp
, width_align
);
132 aligned_h
= roundup(exec
->fb_height
, height_align
);
134 if (INT_MAX
/ aligned_row_len
< aligned_h
) {
135 DRM_ERROR("Overflow in fbo size (%d * %d)\n",
136 aligned_row_len
, aligned_h
);
139 size
= aligned_row_len
* aligned_h
;
141 if (size
+ offset
< size
||
142 size
+ offset
> fbo
->base
.size
) {
143 DRM_ERROR("Overflow in %dx%d fbo size (%d + %d > %d)\n",
144 exec
->fb_width
, exec
->fb_height
, size
, offset
,
153 validate_start_tile_binning(VALIDATE_ARGS
)
155 if (exec
->found_start_tile_binning_packet
) {
156 DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n");
159 exec
->found_start_tile_binning_packet
= true;
161 if (!exec
->found_tile_binning_mode_config_packet
) {
162 DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
170 validate_branch_to_sublist(VALIDATE_ARGS
)
172 struct drm_gem_cma_object
*target
;
175 if (!vc4_use_handle(exec
, 0, VC4_MODE_TILE_ALLOC
, &target
))
178 if (target
!= exec
->tile_alloc_bo
) {
179 DRM_ERROR("Jumping to BOs other than tile alloc unsupported\n");
183 offset
= *(uint32_t *)(untrusted
+ 0);
184 if (offset
% exec
->tile_alloc_init_block_size
||
185 offset
/ exec
->tile_alloc_init_block_size
>
186 exec
->bin_tiles_x
* exec
->bin_tiles_y
) {
187 DRM_ERROR("VC4_PACKET_BRANCH_TO_SUB_LIST must jump to initial "
188 "tile allocation space.\n");
192 *(uint32_t *)(validated
+ 0) = target
->paddr
+ offset
;
198 * validate_loadstore_tile_buffer_general() - Validation for
199 * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL and
200 * VC4_PACKET_STORE_TILE_BUFFER_GENERAL.
202 * The two packets are nearly the same, except for the TLB-clearing management
203 * bits not being present for loads. Additionally, while stores are executed
204 * immediately (using the current tile coordinates), loads are queued to be
205 * executed when the tile coordinates packet occurs.
207 * Note that coordinates packets are validated to be within the declared
208 * bin_x/y, which themselves are verified to match the rendering-configuration
209 * FB width and height (which the hardware uses to clip loads and stores).
212 validate_loadstore_tile_buffer_general(VALIDATE_ARGS
)
214 uint32_t packet_b0
= *(uint8_t *)(untrusted
+ 0);
215 uint32_t packet_b1
= *(uint8_t *)(untrusted
+ 1);
216 struct drm_gem_cma_object
*fbo
;
217 uint32_t buffer_type
= packet_b0
& 0xf;
218 uint32_t offset
, cpp
;
220 switch (buffer_type
) {
221 case VC4_LOADSTORE_TILE_BUFFER_NONE
:
223 case VC4_LOADSTORE_TILE_BUFFER_COLOR
:
224 if ((packet_b1
& VC4_LOADSTORE_TILE_BUFFER_MASK
) ==
225 VC4_LOADSTORE_TILE_BUFFER_RGBA8888
) {
232 case VC4_LOADSTORE_TILE_BUFFER_Z
:
233 case VC4_LOADSTORE_TILE_BUFFER_ZS
:
238 DRM_ERROR("Load/store type %d unsupported\n", buffer_type
);
242 if (!vc4_use_handle(exec
, 0, VC4_MODE_RENDER
, &fbo
))
245 offset
= *(uint32_t *)(untrusted
+ 2);
247 if (!check_fbo_size(exec
, fbo
, offset
,
249 VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK
) >>
250 VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT
),
255 *(uint32_t *)(validated
+ 2) = offset
+ fbo
->paddr
;
261 validate_indexed_prim_list(VALIDATE_ARGS
)
263 struct drm_gem_cma_object
*ib
;
264 uint32_t max_index
= *(uint32_t *)(untrusted
+ 9);
265 uint32_t index_size
= (*(uint8_t *)(untrusted
+ 0) >> 4) ? 2 : 1;
266 uint32_t ib_access_end
= (max_index
+ 1) * index_size
;
268 /* Check overflow condition */
269 if (max_index
== ~0) {
270 DRM_ERROR("unlimited max index\n");
274 if (ib_access_end
< max_index
) {
275 DRM_ERROR("IB access overflow\n");
280 if (!vc4_use_handle(exec
, 0, VC4_MODE_RENDER
, &ib
))
282 if (ib_access_end
> ib
->base
.size
) {
283 DRM_ERROR("IB access out of bounds (%d/%d)\n",
284 ib_access_end
, ib
->base
.size
);
288 *(uint32_t *)(validated
+ 5) =
289 *(uint32_t *)(untrusted
+ 5) + ib
->paddr
;
295 validate_gl_shader_state(VALIDATE_ARGS
)
297 uint32_t i
= exec
->shader_state_count
++;
299 if (i
>= exec
->shader_state_size
) { /* XXX? */
300 DRM_ERROR("More requests for shader states than declared\n");
304 exec
->shader_state
[i
].packet
= VC4_PACKET_GL_SHADER_STATE
;
305 exec
->shader_state
[i
].addr
= *(uint32_t *)untrusted
;
307 if (exec
->shader_state
[i
].addr
& ~0xf) {
308 DRM_ERROR("high bits set in GL shader rec reference\n");
312 *(uint32_t *)validated
= (exec
->shader_rec_p
+
313 exec
->shader_state
[i
].addr
);
315 exec
->shader_rec_p
+=
316 roundup(gl_shader_rec_size(exec
->shader_state
[i
].addr
), 16);
322 validate_nv_shader_state(VALIDATE_ARGS
)
324 uint32_t i
= exec
->shader_state_count
++;
326 if (i
>= exec
->shader_state_size
) {
327 DRM_ERROR("More requests for shader states than declared\n");
331 exec
->shader_state
[i
].packet
= VC4_PACKET_NV_SHADER_STATE
;
332 exec
->shader_state
[i
].addr
= *(uint32_t *)untrusted
;
334 if (exec
->shader_state
[i
].addr
& 15) {
335 DRM_ERROR("NV shader state address 0x%08x misaligned\n",
336 exec
->shader_state
[i
].addr
);
340 *(uint32_t *)validated
= (exec
->shader_state
[i
].addr
+
347 validate_tile_binning_config(VALIDATE_ARGS
)
349 struct drm_gem_cma_object
*tile_allocation
;
350 struct drm_gem_cma_object
*tile_state_data_array
;
352 uint32_t tile_allocation_size
;
354 if (!vc4_use_handle(exec
, 0, VC4_MODE_TILE_ALLOC
, &tile_allocation
) ||
355 !vc4_use_handle(exec
, 1, VC4_MODE_TSDA
, &tile_state_data_array
))
358 if (exec
->found_tile_binning_mode_config_packet
) {
359 DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
362 exec
->found_tile_binning_mode_config_packet
= true;
364 exec
->bin_tiles_x
= *(uint8_t *)(untrusted
+ 12);
365 exec
->bin_tiles_y
= *(uint8_t *)(untrusted
+ 13);
366 flags
= *(uint8_t *)(untrusted
+ 14);
368 if (exec
->bin_tiles_x
== 0 ||
369 exec
->bin_tiles_y
== 0) {
370 DRM_ERROR("Tile binning config of %dx%d too small\n",
371 exec
->bin_tiles_x
, exec
->bin_tiles_y
);
375 /* Our validation relies on the user not getting to set up their own
376 * tile state/tile allocation BO contents.
378 if (!(flags
& VC4_BIN_CONFIG_AUTO_INIT_TSDA
)) {
379 DRM_ERROR("binning config missing "
380 "VC4_BIN_CONFIG_AUTO_INIT_TSDA\n");
384 if (flags
& (VC4_BIN_CONFIG_DB_NON_MS
|
385 VC4_BIN_CONFIG_TILE_BUFFER_64BIT
|
386 VC4_BIN_CONFIG_MS_MODE_4X
)) {
387 DRM_ERROR("unsupported bining config flags 0x%02x\n", flags
);
391 if (*(uint32_t *)(untrusted
+ 0) != 0) {
392 DRM_ERROR("tile allocation offset != 0 unsupported\n");
395 tile_allocation_size
= *(uint32_t *)(untrusted
+ 4);
396 if (tile_allocation_size
> tile_allocation
->base
.size
) {
397 DRM_ERROR("tile allocation size %d > BO size %d",
398 tile_allocation_size
, tile_allocation
->base
.size
);
401 *(uint32_t *)validated
= tile_allocation
->paddr
;
402 exec
->tile_alloc_bo
= tile_allocation
;
404 exec
->tile_alloc_init_block_size
= 1 << (5 + ((flags
>> 5) & 3));
405 if (exec
->bin_tiles_x
* exec
->bin_tiles_y
*
406 exec
->tile_alloc_init_block_size
> tile_allocation_size
) {
407 DRM_ERROR("tile init exceeds tile alloc size (%d vs %d)\n",
408 exec
->bin_tiles_x
* exec
->bin_tiles_y
*
409 exec
->tile_alloc_init_block_size
,
410 tile_allocation_size
);
413 if (*(uint32_t *)(untrusted
+ 8) != 0) {
414 DRM_ERROR("TSDA offset != 0 unsupported\n");
417 if (exec
->bin_tiles_x
* exec
->bin_tiles_y
* 48 >
418 tile_state_data_array
->base
.size
) {
419 DRM_ERROR("TSDA of %db too small for %dx%d bin config\n",
420 tile_state_data_array
->base
.size
,
421 exec
->bin_tiles_x
, exec
->bin_tiles_y
);
423 *(uint32_t *)(validated
+ 8) = tile_state_data_array
->paddr
;
429 validate_tile_rendering_mode_config(VALIDATE_ARGS
)
431 struct drm_gem_cma_object
*fbo
;
432 uint32_t flags
, offset
, cpp
;
434 if (exec
->found_tile_rendering_mode_config_packet
) {
435 DRM_ERROR("Duplicate VC4_PACKET_TILE_RENDERING_MODE_CONFIG\n");
438 exec
->found_tile_rendering_mode_config_packet
= true;
440 if (!vc4_use_handle(exec
, 0, VC4_MODE_RENDER
, &fbo
))
443 exec
->fb_width
= *(uint16_t *)(untrusted
+ 4);
444 exec
->fb_height
= *(uint16_t *)(untrusted
+ 6);
446 /* Make sure that the fb width/height matches the binning config -- we
447 * rely on being able to interchange these for various assertions.
448 * (Within a tile, loads and stores will be clipped to the
449 * width/height, but we allow load/storing to any binned tile).
451 if (exec
->fb_width
<= (exec
->bin_tiles_x
- 1) * 64 ||
452 exec
->fb_width
> exec
->bin_tiles_x
* 64 ||
453 exec
->fb_height
<= (exec
->bin_tiles_y
- 1) * 64 ||
454 exec
->fb_height
> exec
->bin_tiles_y
* 64) {
455 DRM_ERROR("bin config %dx%d doesn't match FB %dx%d\n",
456 exec
->bin_tiles_x
, exec
->bin_tiles_y
,
457 exec
->fb_width
, exec
->fb_height
);
461 flags
= *(uint16_t *)(untrusted
+ 8);
462 if ((flags
& VC4_RENDER_CONFIG_FORMAT_MASK
) ==
463 VC4_RENDER_CONFIG_FORMAT_RGBA8888
) {
469 offset
= *(uint32_t *)untrusted
;
470 if (!check_fbo_size(exec
, fbo
, offset
,
472 VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK
) >>
473 VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT
),
478 *(uint32_t *)validated
= fbo
->paddr
+ offset
;
484 validate_tile_coordinates(VALIDATE_ARGS
)
486 uint8_t tile_x
= *(uint8_t *)(untrusted
+ 0);
487 uint8_t tile_y
= *(uint8_t *)(untrusted
+ 1);
489 if (tile_x
>= exec
->bin_tiles_x
||
490 tile_y
>= exec
->bin_tiles_y
) {
491 DRM_ERROR("Tile coordinates %d,%d > bin config %d,%d\n",
503 validate_gem_handles(VALIDATE_ARGS
)
505 memcpy(exec
->bo_index
, untrusted
, sizeof(exec
->bo_index
));
509 static const struct cmd_info
{
514 int (*func
)(struct exec_info
*exec
, void *validated
, void *untrusted
);
516 [VC4_PACKET_HALT
] = { 1, 1, 1, "halt", NULL
},
517 [VC4_PACKET_NOP
] = { 1, 1, 1, "nop", NULL
},
518 [VC4_PACKET_FLUSH
] = { 1, 1, 1, "flush", NULL
},
519 [VC4_PACKET_FLUSH_ALL
] = { 1, 0, 1, "flush all state", NULL
},
520 [VC4_PACKET_START_TILE_BINNING
] = { 1, 0, 1, "start tile binning", validate_start_tile_binning
},
521 [VC4_PACKET_INCREMENT_SEMAPHORE
] = { 1, 0, 1, "increment semaphore", NULL
},
522 [VC4_PACKET_WAIT_ON_SEMAPHORE
] = { 1, 1, 1, "wait on semaphore", NULL
},
523 /* BRANCH_TO_SUB_LIST is actually supported in the binner as well, but
524 * we only use it from the render CL in order to jump into the tile
527 [VC4_PACKET_BRANCH_TO_SUB_LIST
] = { 0, 1, 5, "branch to sublist", validate_branch_to_sublist
},
528 [VC4_PACKET_STORE_MS_TILE_BUFFER
] = { 0, 1, 1, "store MS resolved tile color buffer", NULL
},
529 [VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF
] = { 0, 1, 1, "store MS resolved tile color buffer and EOF", NULL
},
531 [VC4_PACKET_STORE_TILE_BUFFER_GENERAL
] = { 0, 1, 7, "Store Tile Buffer General", validate_loadstore_tile_buffer_general
},
532 [VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
] = { 0, 1, 7, "Load Tile Buffer General", validate_loadstore_tile_buffer_general
},
534 [VC4_PACKET_GL_INDEXED_PRIMITIVE
] = { 1, 1, 14, "Indexed Primitive List", validate_indexed_prim_list
},
536 /* XXX: bounds check verts? */
537 [VC4_PACKET_GL_ARRAY_PRIMITIVE
] = { 1, 1, 10, "Vertex Array Primitives", NULL
},
539 [VC4_PACKET_PRIMITIVE_LIST_FORMAT
] = { 1, 1, 2, "primitive list format", NULL
}, /* XXX: bin valid? */
541 [VC4_PACKET_GL_SHADER_STATE
] = { 1, 1, 5, "GL Shader State", validate_gl_shader_state
},
542 [VC4_PACKET_NV_SHADER_STATE
] = { 1, 1, 5, "NV Shader State", validate_nv_shader_state
},
544 [VC4_PACKET_CONFIGURATION_BITS
] = { 1, 1, 4, "configuration bits", NULL
},
545 [VC4_PACKET_FLAT_SHADE_FLAGS
] = { 1, 1, 5, "flat shade flags", NULL
},
546 [VC4_PACKET_POINT_SIZE
] = { 1, 1, 5, "point size", NULL
},
547 [VC4_PACKET_LINE_WIDTH
] = { 1, 1, 5, "line width", NULL
},
548 [VC4_PACKET_RHT_X_BOUNDARY
] = { 1, 1, 3, "RHT X boundary", NULL
},
549 [VC4_PACKET_DEPTH_OFFSET
] = { 1, 1, 5, "Depth Offset", NULL
},
550 [VC4_PACKET_CLIP_WINDOW
] = { 1, 1, 9, "Clip Window", NULL
},
551 [VC4_PACKET_VIEWPORT_OFFSET
] = { 1, 1, 5, "Viewport Offset", NULL
},
552 [VC4_PACKET_CLIPPER_XY_SCALING
] = { 1, 1, 9, "Clipper XY Scaling", NULL
},
553 /* Note: The docs say this was also 105, but it was 106 in the
554 * initial userland code drop.
556 [VC4_PACKET_CLIPPER_Z_SCALING
] = { 1, 1, 9, "Clipper Z Scale and Offset", NULL
},
558 [VC4_PACKET_TILE_BINNING_MODE_CONFIG
] = { 1, 0, 16, "tile binning configuration", validate_tile_binning_config
},
560 [VC4_PACKET_TILE_RENDERING_MODE_CONFIG
] = { 0, 1, 11, "tile rendering mode configuration", validate_tile_rendering_mode_config
},
562 [VC4_PACKET_CLEAR_COLORS
] = { 0, 1, 14, "Clear Colors", NULL
},
564 [VC4_PACKET_TILE_COORDINATES
] = { 0, 1, 3, "Tile Coordinates", validate_tile_coordinates
},
566 [VC4_PACKET_GEM_HANDLES
] = { 1, 1, 9, "GEM handles", validate_gem_handles
},
570 vc4_validate_cl(struct drm_device
*dev
,
575 struct exec_info
*exec
)
577 uint32_t dst_offset
= 0;
578 uint32_t src_offset
= 0;
580 while (src_offset
< len
) {
581 void *dst_pkt
= validated
+ dst_offset
;
582 void *src_pkt
= unvalidated
+ src_offset
;
583 u8 cmd
= *(uint8_t *)src_pkt
;
584 const struct cmd_info
*info
;
586 if (cmd
> ARRAY_SIZE(cmd_info
)) {
587 DRM_ERROR("0x%08x: packet %d out of bounds\n",
592 info
= &cmd_info
[cmd
];
594 DRM_ERROR("0x%08x: packet %d invalid\n",
600 DRM_INFO("0x%08x: packet %d (%s) size %d processing...\n",
601 src_offset
, cmd
, info
->name
, info
->len
);
604 if ((is_bin
&& !info
->bin
) ||
605 (!is_bin
&& !info
->render
)) {
606 DRM_ERROR("0x%08x: packet %d (%s) invalid for %s\n",
607 src_offset
, cmd
, info
->name
,
608 is_bin
? "binner" : "render");
612 if (src_offset
+ info
->len
> len
) {
613 DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
614 "exceeds bounds (0x%08x)\n",
615 src_offset
, cmd
, info
->name
, info
->len
,
620 if (cmd
!= VC4_PACKET_GEM_HANDLES
)
621 memcpy(dst_pkt
, src_pkt
, info
->len
);
623 if (info
->func
&& info
->func(exec
,
626 DRM_ERROR("0x%08x: packet %d (%s) failed to "
628 src_offset
, cmd
, info
->name
);
632 src_offset
+= info
->len
;
633 /* GEM handle loading doesn't produce HW packets. */
634 if (cmd
!= VC4_PACKET_GEM_HANDLES
)
635 dst_offset
+= info
->len
;
637 /* When the CL hits halt, it'll stop reading anything else. */
638 if (cmd
== VC4_PACKET_HALT
)
643 exec
->ct0ea
= exec
->ct0ca
+ dst_offset
;
645 if (!exec
->found_start_tile_binning_packet
) {
646 DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");
650 if (!exec
->found_tile_rendering_mode_config_packet
) {
651 DRM_ERROR("Render CL missing VC4_PACKET_TILE_RENDERING_MODE_CONFIG\n");
654 exec
->ct1ea
= exec
->ct1ca
+ dst_offset
;
661 reloc_tex(struct exec_info
*exec
,
662 void *uniform_data_u
,
663 struct vc4_texture_sample_info
*sample
,
664 uint32_t texture_handle_index
)
667 struct drm_gem_cma_object
*tex
;
668 uint32_t unvalidated_p0
= *(uint32_t *)(uniform_data_u
+
669 sample
->p_offset
[0]);
670 uint32_t *validated_p0
= exec
->uniforms_v
+ sample
->p_offset
[0];
672 if (!vc4_use_bo(exec
, texture_handle_index
, VC4_MODE_RENDER
, &tex
))
675 *validated_p0
= tex
->paddr
+ unvalidated_p0
;
681 validate_shader_rec(struct drm_device
*dev
,
682 struct exec_info
*exec
,
683 struct vc4_shader_state
*state
)
685 uint32_t *src_handles
;
687 enum shader_rec_reloc_type
{
691 struct shader_rec_reloc
{
692 enum shader_rec_reloc_type type
;
695 static const struct shader_rec_reloc gl_relocs
[] = {
696 { RELOC_CODE
, 4 }, /* fs */
697 { RELOC_CODE
, 16 }, /* vs */
698 { RELOC_CODE
, 28 }, /* cs */
700 static const struct shader_rec_reloc nv_relocs
[] = {
701 { RELOC_CODE
, 4 }, /* fs */
704 const struct shader_rec_reloc
*relocs
;
705 struct drm_gem_cma_object
*bo
[ARRAY_SIZE(gl_relocs
) + 8];
706 uint32_t nr_attributes
= 0, nr_fixed_relocs
, nr_relocs
, packet_size
;
708 struct vc4_validated_shader_info
*validated_shader
= NULL
;
710 if (state
->packet
== VC4_PACKET_NV_SHADER_STATE
) {
712 nr_fixed_relocs
= ARRAY_SIZE(nv_relocs
);
717 nr_fixed_relocs
= ARRAY_SIZE(gl_relocs
);
719 nr_attributes
= state
->addr
& 0x7;
720 if (nr_attributes
== 0)
722 packet_size
= gl_shader_rec_size(state
->addr
);
724 nr_relocs
= nr_fixed_relocs
+ nr_attributes
;
726 if (nr_relocs
* 4 > exec
->shader_rec_size
) {
727 DRM_ERROR("overflowed shader recs reading %d handles "
728 "from %d bytes left\n",
729 nr_relocs
, exec
->shader_rec_size
);
732 src_handles
= exec
->shader_rec_u
;
733 exec
->shader_rec_u
+= nr_relocs
* 4;
734 exec
->shader_rec_size
-= nr_relocs
* 4;
736 if (packet_size
> exec
->shader_rec_size
) {
737 DRM_ERROR("overflowed shader recs copying %db packet "
738 "from %d bytes left\n",
739 packet_size
, exec
->shader_rec_size
);
742 pkt_u
= exec
->shader_rec_u
;
743 pkt_v
= exec
->shader_rec_v
;
744 memcpy(pkt_v
, pkt_u
, packet_size
);
745 exec
->shader_rec_u
+= packet_size
;
746 /* Shader recs have to be aligned to 16 bytes (due to the attribute
747 * flags being in the low bytes), so round the next validated shader
748 * rec address up. This should be safe, since we've got so many
749 * relocations in a shader rec packet.
751 BUG_ON(roundup(packet_size
, 16) - packet_size
> nr_relocs
* 4);
752 exec
->shader_rec_v
+= roundup(packet_size
, 16);
753 exec
->shader_rec_size
-= packet_size
;
755 for (i
= 0; i
< nr_relocs
; i
++) {
756 enum vc4_bo_mode mode
;
758 if (i
< nr_fixed_relocs
&& relocs
[i
].type
== RELOC_CODE
)
759 mode
= VC4_MODE_SHADER
;
761 mode
= VC4_MODE_RENDER
;
763 if (!vc4_use_bo(exec
, src_handles
[i
], mode
, &bo
[i
])) {
768 for (i
= 0; i
< nr_fixed_relocs
; i
++) {
769 uint32_t o
= relocs
[i
].offset
;
770 uint32_t src_offset
= *(uint32_t *)(pkt_u
+ o
);
771 uint32_t *texture_handles_u
;
772 void *uniform_data_u
;
775 *(uint32_t *)(pkt_v
+ o
) = bo
[i
]->paddr
+ src_offset
;
777 switch (relocs
[i
].type
) {
779 kfree(validated_shader
);
780 validated_shader
= vc4_validate_shader(bo
[i
],
782 if (!validated_shader
)
785 if (validated_shader
->uniforms_src_size
>
786 exec
->uniforms_size
) {
787 DRM_ERROR("Uniforms src buffer overflow\n");
791 texture_handles_u
= exec
->uniforms_u
;
792 uniform_data_u
= (texture_handles_u
+
793 validated_shader
->num_texture_samples
);
795 memcpy(exec
->uniforms_v
, uniform_data_u
,
796 validated_shader
->uniforms_size
);
799 tex
< validated_shader
->num_texture_samples
;
803 &validated_shader
->texture_samples
[tex
],
804 texture_handles_u
[tex
])) {
809 *(uint32_t *)(pkt_v
+ o
+ 4) = exec
->uniforms_p
;
811 exec
->uniforms_u
+= validated_shader
->uniforms_src_size
;
812 exec
->uniforms_v
+= validated_shader
->uniforms_size
;
813 exec
->uniforms_p
+= validated_shader
->uniforms_size
;
822 for (i
= 0; i
< nr_attributes
; i
++) {
823 /* XXX: validation */
824 uint32_t o
= 36 + i
* 8;
825 *(uint32_t *)(pkt_v
+ o
) = (bo
[nr_fixed_relocs
+ i
]->paddr
+
826 *(uint32_t *)(pkt_u
+ o
));
829 kfree(validated_shader
);
834 kfree(validated_shader
);
839 vc4_validate_shader_recs(struct drm_device
*dev
,
840 struct exec_info
*exec
)
845 for (i
= 0; i
< exec
->shader_state_count
; i
++) {
846 ret
= validate_shader_rec(dev
, exec
, &exec
->shader_state
[i
]);