0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007
0008 #include "etnaviv_gem.h"
0009 #include "etnaviv_gpu.h"
0010
0011 #include "cmdstream.xml.h"
0012
0013 #define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
0014
0015 struct etna_validation_state {
0016 struct etnaviv_gpu *gpu;
0017 const struct drm_etnaviv_gem_submit_reloc *relocs;
0018 unsigned int num_relocs;
0019 u32 *start;
0020 };
0021
0022 static const struct {
0023 u16 offset;
0024 u16 size;
0025 } etnaviv_sensitive_states[] __initconst = {
0026 #define ST(start, num) { (start) >> 2, (num) }
0027
0028 ST(0x1200, 1),
0029 ST(0x1228, 1),
0030 ST(0x1238, 1),
0031 ST(0x1284, 1),
0032 ST(0x128c, 1),
0033 ST(0x1304, 1),
0034 ST(0x1310, 1),
0035 ST(0x1318, 1),
0036 ST(0x12800, 4),
0037 ST(0x128a0, 4),
0038 ST(0x128c0, 4),
0039 ST(0x12970, 4),
0040 ST(0x12a00, 8),
0041 ST(0x12b40, 8),
0042 ST(0x12b80, 8),
0043 ST(0x12ce0, 8),
0044
0045 ST(0x0644, 1),
0046 ST(0x064c, 1),
0047 ST(0x0680, 8),
0048 ST(0x086c, 1),
0049 ST(0x1028, 1),
0050 ST(0x1410, 1),
0051 ST(0x1430, 1),
0052 ST(0x1458, 1),
0053 ST(0x1460, 8),
0054 ST(0x1480, 8),
0055 ST(0x1500, 8),
0056 ST(0x1520, 8),
0057 ST(0x1608, 1),
0058 ST(0x1610, 1),
0059 ST(0x1658, 1),
0060 ST(0x165c, 1),
0061 ST(0x1664, 1),
0062 ST(0x1668, 1),
0063 ST(0x16a4, 1),
0064 ST(0x16c0, 8),
0065 ST(0x16e0, 8),
0066 ST(0x1740, 8),
0067 ST(0x17c0, 8),
0068 ST(0x17e0, 8),
0069 ST(0x2400, 14 * 16),
0070 ST(0x3824, 1),
0071 ST(0x10800, 32 * 16),
0072 ST(0x14600, 16),
0073 ST(0x14800, 8 * 8),
0074 #undef ST
0075 };
0076
0077 #define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
0078 static DECLARE_BITMAP(etnaviv_states, ETNAVIV_STATES_SIZE);
0079
0080 void __init etnaviv_validate_init(void)
0081 {
0082 unsigned int i;
0083
0084 for (i = 0; i < ARRAY_SIZE(etnaviv_sensitive_states); i++)
0085 bitmap_set(etnaviv_states, etnaviv_sensitive_states[i].offset,
0086 etnaviv_sensitive_states[i].size);
0087 }
0088
0089 static void etnaviv_warn_if_non_sensitive(struct etna_validation_state *state,
0090 unsigned int buf_offset, unsigned int state_addr)
0091 {
0092 if (state->num_relocs && state->relocs->submit_offset < buf_offset) {
0093 dev_warn_once(state->gpu->dev,
0094 "%s: relocation for non-sensitive state 0x%x at offset %u\n",
0095 __func__, state_addr,
0096 state->relocs->submit_offset);
0097 while (state->num_relocs &&
0098 state->relocs->submit_offset < buf_offset) {
0099 state->relocs++;
0100 state->num_relocs--;
0101 }
0102 }
0103 }
0104
0105 static bool etnaviv_validate_load_state(struct etna_validation_state *state,
0106 u32 *ptr, unsigned int state_offset, unsigned int num)
0107 {
0108 unsigned int size = min(ETNAVIV_STATES_SIZE, state_offset + num);
0109 unsigned int st_offset = state_offset, buf_offset;
0110
0111 for_each_set_bit_from(st_offset, etnaviv_states, size) {
0112 buf_offset = (ptr - state->start +
0113 st_offset - state_offset) * 4;
0114
0115 etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4);
0116 if (state->num_relocs &&
0117 state->relocs->submit_offset == buf_offset) {
0118 state->relocs++;
0119 state->num_relocs--;
0120 continue;
0121 }
0122
0123 dev_warn_ratelimited(state->gpu->dev,
0124 "%s: load state touches restricted state 0x%x at offset %u\n",
0125 __func__, st_offset * 4, buf_offset);
0126 return false;
0127 }
0128
0129 if (state->num_relocs) {
0130 buf_offset = (ptr - state->start + num) * 4;
0131 etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4 +
0132 state->relocs->submit_offset -
0133 buf_offset);
0134 }
0135
0136 return true;
0137 }
0138
0139 static uint8_t cmd_length[32] = {
0140 [FE_OPCODE_DRAW_PRIMITIVES] = 4,
0141 [FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6,
0142 [FE_OPCODE_DRAW_INSTANCED] = 4,
0143 [FE_OPCODE_NOP] = 2,
0144 [FE_OPCODE_STALL] = 2,
0145 };
0146
0147 bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, u32 *stream,
0148 unsigned int size,
0149 struct drm_etnaviv_gem_submit_reloc *relocs,
0150 unsigned int reloc_size)
0151 {
0152 struct etna_validation_state state;
0153 u32 *buf = stream;
0154 u32 *end = buf + size;
0155
0156 state.gpu = gpu;
0157 state.relocs = relocs;
0158 state.num_relocs = reloc_size;
0159 state.start = stream;
0160
0161 while (buf < end) {
0162 u32 cmd = *buf;
0163 unsigned int len, n, off;
0164 unsigned int op = cmd >> 27;
0165
0166 switch (op) {
0167 case FE_OPCODE_LOAD_STATE:
0168 n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
0169 len = ALIGN(1 + n, 2);
0170 if (buf + len > end)
0171 break;
0172
0173 off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET);
0174 if (!etnaviv_validate_load_state(&state, buf + 1,
0175 off, n))
0176 return false;
0177 break;
0178
0179 case FE_OPCODE_DRAW_2D:
0180 n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT);
0181 if (n == 0)
0182 n = 256;
0183 len = 2 + n * 2;
0184 break;
0185
0186 default:
0187 len = cmd_length[op];
0188 if (len == 0) {
0189 dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
0190 __func__, op, buf - state.start);
0191 return false;
0192 }
0193 break;
0194 }
0195
0196 buf += len;
0197 }
0198
0199 if (buf > end) {
0200 dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
0201 __func__, buf - state.start, size);
0202 return false;
0203 }
0204
0205 return true;
0206 }