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 /** Return the width in pixels of a 64-byte microtile. */
64 DRM_ERROR("unknown cpp: %d\n", cpp
);
69 /** Return the height in pixels of a 64-byte microtile. */
81 DRM_ERROR("unknown cpp: %d\n", cpp
);
87 * The texture unit decides what tiling format a particular miplevel is using
88 * this function, so we lay out our miptrees accordingly.
91 size_is_lt(uint32_t width
, uint32_t height
, int cpp
)
93 return (width
<= 4 * utile_width(cpp
) ||
94 height
<= 4 * utile_height(cpp
));
98 vc4_use_bo(struct exec_info
*exec
,
100 enum vc4_bo_mode mode
,
101 struct drm_gem_cma_object
**obj
)
105 if (hindex
>= exec
->bo_count
) {
106 DRM_ERROR("BO index %d greater than BO count %d\n",
107 hindex
, exec
->bo_count
);
111 if (exec
->bo
[hindex
].mode
!= mode
) {
112 if (exec
->bo
[hindex
].mode
== VC4_MODE_UNDECIDED
) {
113 exec
->bo
[hindex
].mode
= mode
;
115 DRM_ERROR("BO index %d reused with mode %d vs %d\n",
116 hindex
, exec
->bo
[hindex
].mode
, mode
);
121 *obj
= exec
->bo
[hindex
].bo
;
126 vc4_use_handle(struct exec_info
*exec
,
127 uint32_t gem_handles_packet_index
,
128 enum vc4_bo_mode mode
,
129 struct drm_gem_cma_object
**obj
)
131 return vc4_use_bo(exec
, exec
->bo_index
[gem_handles_packet_index
],
136 gl_shader_rec_size(uint32_t pointer_bits
)
138 uint32_t attribute_count
= pointer_bits
& 7;
139 bool extended
= pointer_bits
& 8;
141 if (attribute_count
== 0)
145 return 100 + attribute_count
* 4;
147 return 36 + attribute_count
* 8;
151 check_tex_size(struct exec_info
*exec
, struct drm_gem_cma_object
*fbo
,
152 uint32_t offset
, uint8_t tiling_format
,
153 uint32_t width
, uint32_t height
, uint8_t cpp
)
155 uint32_t aligned_width
, aligned_height
, stride
, size
;
156 uint32_t utile_w
= utile_width(cpp
);
157 uint32_t utile_h
= utile_height(cpp
);
159 /* The values are limited by the packet/texture parameter bitfields,
160 * so we don't need to worry as much about integer overflow.
162 BUG_ON(width
> 65535);
163 BUG_ON(height
> 65535);
165 switch (tiling_format
) {
166 case VC4_TILING_FORMAT_LINEAR
:
167 aligned_width
= roundup(width
, 16 / cpp
);
168 aligned_height
= height
;
170 case VC4_TILING_FORMAT_T
:
171 aligned_width
= roundup(width
, utile_w
* 8);
172 aligned_height
= roundup(height
, utile_h
* 8);
174 case VC4_TILING_FORMAT_LT
:
175 aligned_width
= roundup(width
, utile_w
);
176 aligned_height
= roundup(height
, utile_h
);
179 DRM_ERROR("buffer tiling %d unsupported\n", tiling_format
);
183 stride
= aligned_width
* cpp
;
185 if (INT_MAX
/ stride
< aligned_height
) {
186 DRM_ERROR("Overflow in fbo size (%dx%d -> %dx%d)\n",
188 aligned_width
, aligned_height
);
191 size
= stride
* aligned_height
;
193 if (size
+ offset
< size
||
194 size
+ offset
> fbo
->base
.size
) {
195 DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %d)\n",
197 aligned_width
, aligned_height
,
198 size
, offset
, fbo
->base
.size
);
206 validate_start_tile_binning(VALIDATE_ARGS
)
208 if (exec
->found_start_tile_binning_packet
) {
209 DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n");
212 exec
->found_start_tile_binning_packet
= true;
214 if (!exec
->found_tile_binning_mode_config_packet
) {
215 DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
223 validate_branch_to_sublist(VALIDATE_ARGS
)
225 struct drm_gem_cma_object
*target
;
228 if (!vc4_use_handle(exec
, 0, VC4_MODE_TILE_ALLOC
, &target
))
231 if (target
!= exec
->tile_alloc_bo
) {
232 DRM_ERROR("Jumping to BOs other than tile alloc unsupported\n");
236 offset
= *(uint32_t *)(untrusted
+ 0);
237 if (offset
% exec
->tile_alloc_init_block_size
||
238 offset
/ exec
->tile_alloc_init_block_size
>
239 exec
->bin_tiles_x
* exec
->bin_tiles_y
) {
240 DRM_ERROR("VC4_PACKET_BRANCH_TO_SUB_LIST must jump to initial "
241 "tile allocation space.\n");
245 *(uint32_t *)(validated
+ 0) = target
->paddr
+ offset
;
251 * validate_loadstore_tile_buffer_general() - Validation for
252 * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL and
253 * VC4_PACKET_STORE_TILE_BUFFER_GENERAL.
255 * The two packets are nearly the same, except for the TLB-clearing management
256 * bits not being present for loads. Additionally, while stores are executed
257 * immediately (using the current tile coordinates), loads are queued to be
258 * executed when the tile coordinates packet occurs.
260 * Note that coordinates packets are validated to be within the declared
261 * bin_x/y, which themselves are verified to match the rendering-configuration
262 * FB width and height (which the hardware uses to clip loads and stores).
265 validate_loadstore_tile_buffer_general(VALIDATE_ARGS
)
267 uint32_t packet_b0
= *(uint8_t *)(untrusted
+ 0);
268 uint32_t packet_b1
= *(uint8_t *)(untrusted
+ 1);
269 struct drm_gem_cma_object
*fbo
;
270 uint32_t buffer_type
= packet_b0
& 0xf;
271 uint32_t offset
, cpp
;
273 switch (buffer_type
) {
274 case VC4_LOADSTORE_TILE_BUFFER_NONE
:
276 case VC4_LOADSTORE_TILE_BUFFER_COLOR
:
277 if ((packet_b1
& VC4_LOADSTORE_TILE_BUFFER_MASK
) ==
278 VC4_LOADSTORE_TILE_BUFFER_RGBA8888
) {
285 case VC4_LOADSTORE_TILE_BUFFER_Z
:
286 case VC4_LOADSTORE_TILE_BUFFER_ZS
:
291 DRM_ERROR("Load/store type %d unsupported\n", buffer_type
);
295 if (!vc4_use_handle(exec
, 0, VC4_MODE_RENDER
, &fbo
))
298 offset
= *(uint32_t *)(untrusted
+ 2) & ~0xf;
300 if (!check_tex_size(exec
, fbo
, offset
,
302 VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK
) >>
303 VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT
),
304 exec
->fb_width
, exec
->fb_height
, cpp
)) {
308 *(uint32_t *)(validated
+ 2) = offset
+ fbo
->paddr
;
314 validate_indexed_prim_list(VALIDATE_ARGS
)
316 struct drm_gem_cma_object
*ib
;
317 uint32_t length
= *(uint32_t *)(untrusted
+ 1);
318 uint32_t offset
= *(uint32_t *)(untrusted
+ 5);
319 uint32_t max_index
= *(uint32_t *)(untrusted
+ 9);
320 uint32_t index_size
= (*(uint8_t *)(untrusted
+ 0) >> 4) ? 2 : 1;
321 struct vc4_shader_state
*shader_state
;
323 /* Check overflow condition */
324 if (exec
->shader_state_count
== 0) {
325 DRM_ERROR("shader state must precede primitives\n");
328 shader_state
= &exec
->shader_state
[exec
->shader_state_count
- 1];
330 if (max_index
> shader_state
->max_index
)
331 shader_state
->max_index
= max_index
;
333 if (!vc4_use_handle(exec
, 0, VC4_MODE_RENDER
, &ib
))
336 if (offset
> ib
->base
.size
||
337 (ib
->base
.size
- offset
) / index_size
< length
) {
338 DRM_ERROR("IB access overflow (%d + %d*%d > %d)\n",
339 offset
, length
, index_size
, ib
->base
.size
);
343 *(uint32_t *)(validated
+ 5) = ib
->paddr
+ offset
;
349 validate_gl_array_primitive(VALIDATE_ARGS
)
351 uint32_t length
= *(uint32_t *)(untrusted
+ 1);
352 uint32_t base_index
= *(uint32_t *)(untrusted
+ 5);
354 struct vc4_shader_state
*shader_state
;
356 /* Check overflow condition */
357 if (exec
->shader_state_count
== 0) {
358 DRM_ERROR("shader state must precede primitives\n");
361 shader_state
= &exec
->shader_state
[exec
->shader_state_count
- 1];
363 if (length
+ base_index
< length
) {
364 DRM_ERROR("primitive vertex count overflow\n");
367 max_index
= length
+ base_index
- 1;
369 if (max_index
> shader_state
->max_index
)
370 shader_state
->max_index
= max_index
;
376 validate_gl_shader_state(VALIDATE_ARGS
)
378 uint32_t i
= exec
->shader_state_count
++;
380 if (i
>= exec
->shader_state_size
) {
381 DRM_ERROR("More requests for shader states than declared\n");
385 exec
->shader_state
[i
].packet
= VC4_PACKET_GL_SHADER_STATE
;
386 exec
->shader_state
[i
].addr
= *(uint32_t *)untrusted
;
387 exec
->shader_state
[i
].max_index
= 0;
389 if (exec
->shader_state
[i
].addr
& ~0xf) {
390 DRM_ERROR("high bits set in GL shader rec reference\n");
394 *(uint32_t *)validated
= (exec
->shader_rec_p
+
395 exec
->shader_state
[i
].addr
);
397 exec
->shader_rec_p
+=
398 roundup(gl_shader_rec_size(exec
->shader_state
[i
].addr
), 16);
404 validate_nv_shader_state(VALIDATE_ARGS
)
406 uint32_t i
= exec
->shader_state_count
++;
408 if (i
>= exec
->shader_state_size
) {
409 DRM_ERROR("More requests for shader states than declared\n");
413 exec
->shader_state
[i
].packet
= VC4_PACKET_NV_SHADER_STATE
;
414 exec
->shader_state
[i
].addr
= *(uint32_t *)untrusted
;
416 if (exec
->shader_state
[i
].addr
& 15) {
417 DRM_ERROR("NV shader state address 0x%08x misaligned\n",
418 exec
->shader_state
[i
].addr
);
422 *(uint32_t *)validated
= (exec
->shader_state
[i
].addr
+
429 validate_tile_binning_config(VALIDATE_ARGS
)
431 struct drm_gem_cma_object
*tile_allocation
;
432 struct drm_gem_cma_object
*tile_state_data_array
;
434 uint32_t tile_allocation_size
;
436 if (!vc4_use_handle(exec
, 0, VC4_MODE_TILE_ALLOC
, &tile_allocation
) ||
437 !vc4_use_handle(exec
, 1, VC4_MODE_TSDA
, &tile_state_data_array
))
440 if (exec
->found_tile_binning_mode_config_packet
) {
441 DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
444 exec
->found_tile_binning_mode_config_packet
= true;
446 exec
->bin_tiles_x
= *(uint8_t *)(untrusted
+ 12);
447 exec
->bin_tiles_y
= *(uint8_t *)(untrusted
+ 13);
448 flags
= *(uint8_t *)(untrusted
+ 14);
450 if (exec
->bin_tiles_x
== 0 ||
451 exec
->bin_tiles_y
== 0) {
452 DRM_ERROR("Tile binning config of %dx%d too small\n",
453 exec
->bin_tiles_x
, exec
->bin_tiles_y
);
457 /* Our validation relies on the user not getting to set up their own
458 * tile state/tile allocation BO contents.
460 if (!(flags
& VC4_BIN_CONFIG_AUTO_INIT_TSDA
)) {
461 DRM_ERROR("binning config missing "
462 "VC4_BIN_CONFIG_AUTO_INIT_TSDA\n");
466 if (flags
& (VC4_BIN_CONFIG_DB_NON_MS
|
467 VC4_BIN_CONFIG_TILE_BUFFER_64BIT
|
468 VC4_BIN_CONFIG_MS_MODE_4X
)) {
469 DRM_ERROR("unsupported bining config flags 0x%02x\n", flags
);
473 if (*(uint32_t *)(untrusted
+ 0) != 0) {
474 DRM_ERROR("tile allocation offset != 0 unsupported\n");
477 tile_allocation_size
= *(uint32_t *)(untrusted
+ 4);
478 if (tile_allocation_size
> tile_allocation
->base
.size
) {
479 DRM_ERROR("tile allocation size %d > BO size %d",
480 tile_allocation_size
, tile_allocation
->base
.size
);
483 *(uint32_t *)validated
= tile_allocation
->paddr
;
484 exec
->tile_alloc_bo
= tile_allocation
;
486 exec
->tile_alloc_init_block_size
= 1 << (5 + ((flags
>> 5) & 3));
487 if (exec
->bin_tiles_x
* exec
->bin_tiles_y
*
488 exec
->tile_alloc_init_block_size
> tile_allocation_size
) {
489 DRM_ERROR("tile init exceeds tile alloc size (%d vs %d)\n",
490 exec
->bin_tiles_x
* exec
->bin_tiles_y
*
491 exec
->tile_alloc_init_block_size
,
492 tile_allocation_size
);
495 if (*(uint32_t *)(untrusted
+ 8) != 0) {
496 DRM_ERROR("TSDA offset != 0 unsupported\n");
499 if (exec
->bin_tiles_x
* exec
->bin_tiles_y
* 48 >
500 tile_state_data_array
->base
.size
) {
501 DRM_ERROR("TSDA of %db too small for %dx%d bin config\n",
502 tile_state_data_array
->base
.size
,
503 exec
->bin_tiles_x
, exec
->bin_tiles_y
);
505 *(uint32_t *)(validated
+ 8) = tile_state_data_array
->paddr
;
511 validate_tile_rendering_mode_config(VALIDATE_ARGS
)
513 struct drm_gem_cma_object
*fbo
;
514 uint32_t flags
, offset
, cpp
;
516 if (exec
->found_tile_rendering_mode_config_packet
) {
517 DRM_ERROR("Duplicate VC4_PACKET_TILE_RENDERING_MODE_CONFIG\n");
520 exec
->found_tile_rendering_mode_config_packet
= true;
522 if (!vc4_use_handle(exec
, 0, VC4_MODE_RENDER
, &fbo
))
525 exec
->fb_width
= *(uint16_t *)(untrusted
+ 4);
526 exec
->fb_height
= *(uint16_t *)(untrusted
+ 6);
528 /* Make sure that the fb width/height matches the binning config -- we
529 * rely on being able to interchange these for various assertions.
530 * (Within a tile, loads and stores will be clipped to the
531 * width/height, but we allow load/storing to any binned tile).
533 if (exec
->fb_width
<= (exec
->bin_tiles_x
- 1) * 64 ||
534 exec
->fb_width
> exec
->bin_tiles_x
* 64 ||
535 exec
->fb_height
<= (exec
->bin_tiles_y
- 1) * 64 ||
536 exec
->fb_height
> exec
->bin_tiles_y
* 64) {
537 DRM_ERROR("bin config %dx%d doesn't match FB %dx%d\n",
538 exec
->bin_tiles_x
, exec
->bin_tiles_y
,
539 exec
->fb_width
, exec
->fb_height
);
543 flags
= *(uint16_t *)(untrusted
+ 8);
544 if ((flags
& VC4_RENDER_CONFIG_FORMAT_MASK
) ==
545 VC4_RENDER_CONFIG_FORMAT_RGBA8888
) {
551 offset
= *(uint32_t *)untrusted
;
552 if (!check_tex_size(exec
, fbo
, offset
,
554 VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK
) >>
555 VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT
),
556 exec
->fb_width
, exec
->fb_height
, cpp
)) {
560 *(uint32_t *)validated
= fbo
->paddr
+ offset
;
566 validate_tile_coordinates(VALIDATE_ARGS
)
568 uint8_t tile_x
= *(uint8_t *)(untrusted
+ 0);
569 uint8_t tile_y
= *(uint8_t *)(untrusted
+ 1);
571 if (tile_x
>= exec
->bin_tiles_x
||
572 tile_y
>= exec
->bin_tiles_y
) {
573 DRM_ERROR("Tile coordinates %d,%d > bin config %d,%d\n",
585 validate_gem_handles(VALIDATE_ARGS
)
587 memcpy(exec
->bo_index
, untrusted
, sizeof(exec
->bo_index
));
591 static const struct cmd_info
{
596 int (*func
)(struct exec_info
*exec
, void *validated
, void *untrusted
);
598 [VC4_PACKET_HALT
] = { 1, 1, 1, "halt", NULL
},
599 [VC4_PACKET_NOP
] = { 1, 1, 1, "nop", NULL
},
600 [VC4_PACKET_FLUSH
] = { 1, 1, 1, "flush", NULL
},
601 [VC4_PACKET_FLUSH_ALL
] = { 1, 0, 1, "flush all state", NULL
},
602 [VC4_PACKET_START_TILE_BINNING
] = { 1, 0, 1, "start tile binning", validate_start_tile_binning
},
603 [VC4_PACKET_INCREMENT_SEMAPHORE
] = { 1, 0, 1, "increment semaphore", NULL
},
604 [VC4_PACKET_WAIT_ON_SEMAPHORE
] = { 1, 1, 1, "wait on semaphore", NULL
},
605 /* BRANCH_TO_SUB_LIST is actually supported in the binner as well, but
606 * we only use it from the render CL in order to jump into the tile
609 [VC4_PACKET_BRANCH_TO_SUB_LIST
] = { 0, 1, 5, "branch to sublist", validate_branch_to_sublist
},
610 [VC4_PACKET_STORE_MS_TILE_BUFFER
] = { 0, 1, 1, "store MS resolved tile color buffer", NULL
},
611 [VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF
] = { 0, 1, 1, "store MS resolved tile color buffer and EOF", NULL
},
613 [VC4_PACKET_STORE_TILE_BUFFER_GENERAL
] = { 0, 1, 7, "Store Tile Buffer General", validate_loadstore_tile_buffer_general
},
614 [VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
] = { 0, 1, 7, "Load Tile Buffer General", validate_loadstore_tile_buffer_general
},
616 [VC4_PACKET_GL_INDEXED_PRIMITIVE
] = { 1, 1, 14, "Indexed Primitive List", validate_indexed_prim_list
},
618 [VC4_PACKET_GL_ARRAY_PRIMITIVE
] = { 1, 1, 10, "Vertex Array Primitives", validate_gl_array_primitive
},
620 /* This is only used by clipped primitives (packets 48 and 49), which
621 * we don't support parsing yet.
623 [VC4_PACKET_PRIMITIVE_LIST_FORMAT
] = { 1, 1, 2, "primitive list format", NULL
},
625 [VC4_PACKET_GL_SHADER_STATE
] = { 1, 1, 5, "GL Shader State", validate_gl_shader_state
},
626 [VC4_PACKET_NV_SHADER_STATE
] = { 1, 1, 5, "NV Shader State", validate_nv_shader_state
},
628 [VC4_PACKET_CONFIGURATION_BITS
] = { 1, 1, 4, "configuration bits", NULL
},
629 [VC4_PACKET_FLAT_SHADE_FLAGS
] = { 1, 1, 5, "flat shade flags", NULL
},
630 [VC4_PACKET_POINT_SIZE
] = { 1, 1, 5, "point size", NULL
},
631 [VC4_PACKET_LINE_WIDTH
] = { 1, 1, 5, "line width", NULL
},
632 [VC4_PACKET_RHT_X_BOUNDARY
] = { 1, 1, 3, "RHT X boundary", NULL
},
633 [VC4_PACKET_DEPTH_OFFSET
] = { 1, 1, 5, "Depth Offset", NULL
},
634 [VC4_PACKET_CLIP_WINDOW
] = { 1, 1, 9, "Clip Window", NULL
},
635 [VC4_PACKET_VIEWPORT_OFFSET
] = { 1, 1, 5, "Viewport Offset", NULL
},
636 [VC4_PACKET_CLIPPER_XY_SCALING
] = { 1, 1, 9, "Clipper XY Scaling", NULL
},
637 /* Note: The docs say this was also 105, but it was 106 in the
638 * initial userland code drop.
640 [VC4_PACKET_CLIPPER_Z_SCALING
] = { 1, 1, 9, "Clipper Z Scale and Offset", NULL
},
642 [VC4_PACKET_TILE_BINNING_MODE_CONFIG
] = { 1, 0, 16, "tile binning configuration", validate_tile_binning_config
},
644 [VC4_PACKET_TILE_RENDERING_MODE_CONFIG
] = { 0, 1, 11, "tile rendering mode configuration", validate_tile_rendering_mode_config
},
646 [VC4_PACKET_CLEAR_COLORS
] = { 0, 1, 14, "Clear Colors", NULL
},
648 [VC4_PACKET_TILE_COORDINATES
] = { 0, 1, 3, "Tile Coordinates", validate_tile_coordinates
},
650 [VC4_PACKET_GEM_HANDLES
] = { 1, 1, 9, "GEM handles", validate_gem_handles
},
654 vc4_validate_cl(struct drm_device
*dev
,
659 struct exec_info
*exec
)
661 uint32_t dst_offset
= 0;
662 uint32_t src_offset
= 0;
664 while (src_offset
< len
) {
665 void *dst_pkt
= validated
+ dst_offset
;
666 void *src_pkt
= unvalidated
+ src_offset
;
667 u8 cmd
= *(uint8_t *)src_pkt
;
668 const struct cmd_info
*info
;
670 if (cmd
> ARRAY_SIZE(cmd_info
)) {
671 DRM_ERROR("0x%08x: packet %d out of bounds\n",
676 info
= &cmd_info
[cmd
];
678 DRM_ERROR("0x%08x: packet %d invalid\n",
684 DRM_INFO("0x%08x: packet %d (%s) size %d processing...\n",
685 src_offset
, cmd
, info
->name
, info
->len
);
688 if ((is_bin
&& !info
->bin
) ||
689 (!is_bin
&& !info
->render
)) {
690 DRM_ERROR("0x%08x: packet %d (%s) invalid for %s\n",
691 src_offset
, cmd
, info
->name
,
692 is_bin
? "binner" : "render");
696 if (src_offset
+ info
->len
> len
) {
697 DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
698 "exceeds bounds (0x%08x)\n",
699 src_offset
, cmd
, info
->name
, info
->len
,
704 if (cmd
!= VC4_PACKET_GEM_HANDLES
)
705 memcpy(dst_pkt
, src_pkt
, info
->len
);
707 if (info
->func
&& info
->func(exec
,
710 DRM_ERROR("0x%08x: packet %d (%s) failed to "
712 src_offset
, cmd
, info
->name
);
716 src_offset
+= info
->len
;
717 /* GEM handle loading doesn't produce HW packets. */
718 if (cmd
!= VC4_PACKET_GEM_HANDLES
)
719 dst_offset
+= info
->len
;
721 /* When the CL hits halt, it'll stop reading anything else. */
722 if (cmd
== VC4_PACKET_HALT
)
727 exec
->ct0ea
= exec
->ct0ca
+ dst_offset
;
729 if (!exec
->found_start_tile_binning_packet
) {
730 DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");
734 if (!exec
->found_tile_rendering_mode_config_packet
) {
735 DRM_ERROR("Render CL missing VC4_PACKET_TILE_RENDERING_MODE_CONFIG\n");
738 exec
->ct1ea
= exec
->ct1ca
+ dst_offset
;
745 reloc_tex(struct exec_info
*exec
,
746 void *uniform_data_u
,
747 struct vc4_texture_sample_info
*sample
,
748 uint32_t texture_handle_index
)
751 struct drm_gem_cma_object
*tex
;
752 uint32_t p0
= *(uint32_t *)(uniform_data_u
+ sample
->p_offset
[0]);
753 uint32_t p1
= *(uint32_t *)(uniform_data_u
+ sample
->p_offset
[1]);
754 uint32_t *validated_p0
= exec
->uniforms_v
+ sample
->p_offset
[0];
755 uint32_t offset
= p0
& ~0xfff;
756 uint32_t miplevels
= (p0
& 15);
757 uint32_t width
= (p1
>> 8) & 2047;
758 uint32_t height
= (p1
>> 20) & 2047;
759 uint32_t cpp
, tiling_format
, utile_w
, utile_h
;
761 enum vc4_texture_data_type type
;
769 DRM_ERROR("Cube maps unsupported\n");
773 type
= ((p0
>> 4) & 15) | ((p1
>> 31) << 4);
776 case VC4_TEXTURE_TYPE_RGBA8888
:
777 case VC4_TEXTURE_TYPE_RGBX8888
:
778 case VC4_TEXTURE_TYPE_RGBA32R
:
781 case VC4_TEXTURE_TYPE_RGBA4444
:
782 case VC4_TEXTURE_TYPE_RGBA5551
:
783 case VC4_TEXTURE_TYPE_RGB565
:
784 case VC4_TEXTURE_TYPE_LUMALPHA
:
785 case VC4_TEXTURE_TYPE_S16F
:
786 case VC4_TEXTURE_TYPE_S16
:
789 case VC4_TEXTURE_TYPE_LUMINANCE
:
790 case VC4_TEXTURE_TYPE_ALPHA
:
791 case VC4_TEXTURE_TYPE_S8
:
794 case VC4_TEXTURE_TYPE_ETC1
:
795 case VC4_TEXTURE_TYPE_BW1
:
796 case VC4_TEXTURE_TYPE_A4
:
797 case VC4_TEXTURE_TYPE_A1
:
798 case VC4_TEXTURE_TYPE_RGBA64
:
799 case VC4_TEXTURE_TYPE_YUV422R
:
801 DRM_ERROR("Texture format %d unsupported\n", type
);
804 utile_w
= utile_width(cpp
);
805 utile_h
= utile_height(cpp
);
807 if (type
== VC4_TEXTURE_TYPE_RGBA32R
) {
808 tiling_format
= VC4_TILING_FORMAT_LINEAR
;
810 if (size_is_lt(width
, height
, cpp
))
811 tiling_format
= VC4_TILING_FORMAT_LT
;
813 tiling_format
= VC4_TILING_FORMAT_T
;
816 if (!vc4_use_bo(exec
, texture_handle_index
, VC4_MODE_RENDER
, &tex
))
819 if (!check_tex_size(exec
, tex
, offset
, tiling_format
,
820 width
, height
, cpp
)) {
824 /* The mipmap levels are stored before the base of the texture. Make
825 * sure there is actually space in the BO.
827 for (i
= 1; i
<= miplevels
; i
++) {
828 uint32_t level_width
= max(width
>> i
, 1u);
829 uint32_t level_height
= max(height
>> i
, 1u);
830 uint32_t aligned_width
, aligned_height
;
833 /* Once the levels get small enough, they drop from T to LT. */
834 if (tiling_format
== VC4_TILING_FORMAT_T
&&
835 size_is_lt(level_width
, level_height
, cpp
)) {
836 tiling_format
= VC4_TILING_FORMAT_LT
;
839 switch (tiling_format
) {
840 case VC4_TILING_FORMAT_T
:
841 aligned_width
= roundup(level_width
, utile_w
* 8);
842 aligned_height
= roundup(level_height
, utile_h
* 8);
844 case VC4_TILING_FORMAT_LT
:
845 aligned_width
= roundup(level_width
, utile_w
);
846 aligned_height
= roundup(level_height
, utile_h
);
849 aligned_width
= roundup(level_width
, 16 / cpp
);
850 aligned_height
= height
;
854 level_size
= aligned_width
* cpp
* aligned_height
;
856 if (offset
< level_size
) {
857 DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db "
858 "overflowed buffer bounds (offset %d)\n",
859 i
, level_width
, level_height
,
860 aligned_width
, aligned_height
,
865 offset
-= level_size
;
868 *validated_p0
= tex
->paddr
+ p0
;
874 validate_shader_rec(struct drm_device
*dev
,
875 struct exec_info
*exec
,
876 struct vc4_shader_state
*state
)
878 uint32_t *src_handles
;
880 enum shader_rec_reloc_type
{
884 struct shader_rec_reloc
{
885 enum shader_rec_reloc_type type
;
888 static const struct shader_rec_reloc gl_relocs
[] = {
889 { RELOC_CODE
, 4 }, /* fs */
890 { RELOC_CODE
, 16 }, /* vs */
891 { RELOC_CODE
, 28 }, /* cs */
893 static const struct shader_rec_reloc nv_relocs
[] = {
894 { RELOC_CODE
, 4 }, /* fs */
897 const struct shader_rec_reloc
*relocs
;
898 struct drm_gem_cma_object
*bo
[ARRAY_SIZE(gl_relocs
) + 8];
899 uint32_t nr_attributes
= 0, nr_fixed_relocs
, nr_relocs
, packet_size
;
901 struct vc4_validated_shader_info
*validated_shader
= NULL
;
903 if (state
->packet
== VC4_PACKET_NV_SHADER_STATE
) {
905 nr_fixed_relocs
= ARRAY_SIZE(nv_relocs
);
910 nr_fixed_relocs
= ARRAY_SIZE(gl_relocs
);
912 nr_attributes
= state
->addr
& 0x7;
913 if (nr_attributes
== 0)
915 packet_size
= gl_shader_rec_size(state
->addr
);
917 nr_relocs
= nr_fixed_relocs
+ nr_attributes
;
919 if (nr_relocs
* 4 > exec
->shader_rec_size
) {
920 DRM_ERROR("overflowed shader recs reading %d handles "
921 "from %d bytes left\n",
922 nr_relocs
, exec
->shader_rec_size
);
925 src_handles
= exec
->shader_rec_u
;
926 exec
->shader_rec_u
+= nr_relocs
* 4;
927 exec
->shader_rec_size
-= nr_relocs
* 4;
929 if (packet_size
> exec
->shader_rec_size
) {
930 DRM_ERROR("overflowed shader recs copying %db packet "
931 "from %d bytes left\n",
932 packet_size
, exec
->shader_rec_size
);
935 pkt_u
= exec
->shader_rec_u
;
936 pkt_v
= exec
->shader_rec_v
;
937 memcpy(pkt_v
, pkt_u
, packet_size
);
938 exec
->shader_rec_u
+= packet_size
;
939 /* Shader recs have to be aligned to 16 bytes (due to the attribute
940 * flags being in the low bytes), so round the next validated shader
941 * rec address up. This should be safe, since we've got so many
942 * relocations in a shader rec packet.
944 BUG_ON(roundup(packet_size
, 16) - packet_size
> nr_relocs
* 4);
945 exec
->shader_rec_v
+= roundup(packet_size
, 16);
946 exec
->shader_rec_size
-= packet_size
;
948 for (i
= 0; i
< nr_relocs
; i
++) {
949 enum vc4_bo_mode mode
;
951 if (i
< nr_fixed_relocs
&& relocs
[i
].type
== RELOC_CODE
)
952 mode
= VC4_MODE_SHADER
;
954 mode
= VC4_MODE_RENDER
;
956 if (!vc4_use_bo(exec
, src_handles
[i
], mode
, &bo
[i
])) {
961 for (i
= 0; i
< nr_fixed_relocs
; i
++) {
962 uint32_t o
= relocs
[i
].offset
;
963 uint32_t src_offset
= *(uint32_t *)(pkt_u
+ o
);
964 uint32_t *texture_handles_u
;
965 void *uniform_data_u
;
968 *(uint32_t *)(pkt_v
+ o
) = bo
[i
]->paddr
+ src_offset
;
970 switch (relocs
[i
].type
) {
972 kfree(validated_shader
);
973 validated_shader
= vc4_validate_shader(bo
[i
],
975 if (!validated_shader
)
978 if (validated_shader
->uniforms_src_size
>
979 exec
->uniforms_size
) {
980 DRM_ERROR("Uniforms src buffer overflow\n");
984 texture_handles_u
= exec
->uniforms_u
;
985 uniform_data_u
= (texture_handles_u
+
986 validated_shader
->num_texture_samples
);
988 memcpy(exec
->uniforms_v
, uniform_data_u
,
989 validated_shader
->uniforms_size
);
992 tex
< validated_shader
->num_texture_samples
;
996 &validated_shader
->texture_samples
[tex
],
997 texture_handles_u
[tex
])) {
1002 *(uint32_t *)(pkt_v
+ o
+ 4) = exec
->uniforms_p
;
1004 exec
->uniforms_u
+= validated_shader
->uniforms_src_size
;
1005 exec
->uniforms_v
+= validated_shader
->uniforms_size
;
1006 exec
->uniforms_p
+= validated_shader
->uniforms_size
;
1015 for (i
= 0; i
< nr_attributes
; i
++) {
1016 struct drm_gem_cma_object
*vbo
= bo
[nr_fixed_relocs
+ i
];
1017 uint32_t o
= 36 + i
* 8;
1018 uint32_t offset
= *(uint32_t *)(pkt_u
+ o
+ 0);
1019 uint32_t attr_size
= *(uint8_t *)(pkt_u
+ o
+ 4) + 1;
1020 uint32_t stride
= *(uint8_t *)(pkt_u
+ o
+ 5);
1023 if (state
->addr
& 0x8)
1024 stride
|= (*(uint32_t *)(pkt_u
+ 100 + i
* 4)) & ~0xff;
1026 if (vbo
->base
.size
< offset
||
1027 vbo
->base
.size
- offset
< attr_size
) {
1028 DRM_ERROR("BO offset overflow (%d + %d > %d)\n",
1029 offset
, attr_size
, vbo
->base
.size
);
1034 max_index
= ((vbo
->base
.size
- offset
- attr_size
) /
1036 if (state
->max_index
> max_index
) {
1037 DRM_ERROR("primitives use index %d out of supplied %d\n",
1038 state
->max_index
, max_index
);
1043 *(uint32_t *)(pkt_v
+ o
) = vbo
->paddr
+ offset
;
1046 kfree(validated_shader
);
1051 kfree(validated_shader
);
1056 vc4_validate_shader_recs(struct drm_device
*dev
,
1057 struct exec_info
*exec
)
1062 for (i
= 0; i
< exec
->shader_state_count
; i
++) {
1063 ret
= validate_shader_rec(dev
, exec
, &exec
->shader_state
[i
]);