1*f6ffbd4fSLucas Stach // SPDX-License-Identifier: GPL-2.0
2a8c21a54SThe etnaviv authors /*
3*f6ffbd4fSLucas Stach * Copyright (C) 2015-2018 Etnaviv Project
4a8c21a54SThe etnaviv authors */
5a8c21a54SThe etnaviv authors
6a8c21a54SThe etnaviv authors #include <linux/kernel.h>
7a8c21a54SThe etnaviv authors
8a8c21a54SThe etnaviv authors #include "etnaviv_gem.h"
9a8c21a54SThe etnaviv authors #include "etnaviv_gpu.h"
10a8c21a54SThe etnaviv authors
11a8c21a54SThe etnaviv authors #include "cmdstream.xml.h"
12a8c21a54SThe etnaviv authors
13a8c21a54SThe etnaviv authors #define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
14a8c21a54SThe etnaviv authors
15a8c21a54SThe etnaviv authors struct etna_validation_state {
16a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu;
17a8c21a54SThe etnaviv authors const struct drm_etnaviv_gem_submit_reloc *relocs;
18a8c21a54SThe etnaviv authors unsigned int num_relocs;
19a8c21a54SThe etnaviv authors u32 *start;
20a8c21a54SThe etnaviv authors };
21a8c21a54SThe etnaviv authors
22a8c21a54SThe etnaviv authors static const struct {
23a8c21a54SThe etnaviv authors u16 offset;
24a8c21a54SThe etnaviv authors u16 size;
25a8c21a54SThe etnaviv authors } etnaviv_sensitive_states[] __initconst = {
26a8c21a54SThe etnaviv authors #define ST(start, num) { (start) >> 2, (num) }
27a8c21a54SThe etnaviv authors /* 2D */
28a8c21a54SThe etnaviv authors ST(0x1200, 1),
29a8c21a54SThe etnaviv authors ST(0x1228, 1),
30a8c21a54SThe etnaviv authors ST(0x1238, 1),
31a8c21a54SThe etnaviv authors ST(0x1284, 1),
32a8c21a54SThe etnaviv authors ST(0x128c, 1),
33a8c21a54SThe etnaviv authors ST(0x1304, 1),
34a8c21a54SThe etnaviv authors ST(0x1310, 1),
35a8c21a54SThe etnaviv authors ST(0x1318, 1),
36a8c21a54SThe etnaviv authors ST(0x12800, 4),
37a8c21a54SThe etnaviv authors ST(0x128a0, 4),
38a8c21a54SThe etnaviv authors ST(0x128c0, 4),
39a8c21a54SThe etnaviv authors ST(0x12970, 4),
40a8c21a54SThe etnaviv authors ST(0x12a00, 8),
41a8c21a54SThe etnaviv authors ST(0x12b40, 8),
42a8c21a54SThe etnaviv authors ST(0x12b80, 8),
43a8c21a54SThe etnaviv authors ST(0x12ce0, 8),
44a8c21a54SThe etnaviv authors /* 3D */
45a8c21a54SThe etnaviv authors ST(0x0644, 1),
46a8c21a54SThe etnaviv authors ST(0x064c, 1),
47a8c21a54SThe etnaviv authors ST(0x0680, 8),
48a1540a7fSWladimir J. van der Laan ST(0x086c, 1),
49a1540a7fSWladimir J. van der Laan ST(0x1028, 1),
50a8c21a54SThe etnaviv authors ST(0x1410, 1),
51a8c21a54SThe etnaviv authors ST(0x1430, 1),
52a8c21a54SThe etnaviv authors ST(0x1458, 1),
53a8c21a54SThe etnaviv authors ST(0x1460, 8),
54a8c21a54SThe etnaviv authors ST(0x1480, 8),
55a8c21a54SThe etnaviv authors ST(0x1500, 8),
56a8c21a54SThe etnaviv authors ST(0x1520, 8),
57a8c21a54SThe etnaviv authors ST(0x1608, 1),
58a8c21a54SThe etnaviv authors ST(0x1610, 1),
59a8c21a54SThe etnaviv authors ST(0x1658, 1),
60a8c21a54SThe etnaviv authors ST(0x165c, 1),
61a8c21a54SThe etnaviv authors ST(0x1664, 1),
62a8c21a54SThe etnaviv authors ST(0x1668, 1),
63a8c21a54SThe etnaviv authors ST(0x16a4, 1),
64a8c21a54SThe etnaviv authors ST(0x16c0, 8),
65a8c21a54SThe etnaviv authors ST(0x16e0, 8),
66a8c21a54SThe etnaviv authors ST(0x1740, 8),
67a1540a7fSWladimir J. van der Laan ST(0x17c0, 8),
68a1540a7fSWladimir J. van der Laan ST(0x17e0, 8),
69a8c21a54SThe etnaviv authors ST(0x2400, 14 * 16),
70b6047ebaSChristian Gmeiner ST(0x3824, 1),
71a8c21a54SThe etnaviv authors ST(0x10800, 32 * 16),
72a1540a7fSWladimir J. van der Laan ST(0x14600, 16),
73a1540a7fSWladimir J. van der Laan ST(0x14800, 8 * 8),
74a8c21a54SThe etnaviv authors #undef ST
75a8c21a54SThe etnaviv authors };
76a8c21a54SThe etnaviv authors
77a8c21a54SThe etnaviv authors #define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
78a8c21a54SThe etnaviv authors static DECLARE_BITMAP(etnaviv_states, ETNAVIV_STATES_SIZE);
79a8c21a54SThe etnaviv authors
etnaviv_validate_init(void)80a8c21a54SThe etnaviv authors void __init etnaviv_validate_init(void)
81a8c21a54SThe etnaviv authors {
82a8c21a54SThe etnaviv authors unsigned int i;
83a8c21a54SThe etnaviv authors
84a8c21a54SThe etnaviv authors for (i = 0; i < ARRAY_SIZE(etnaviv_sensitive_states); i++)
85a8c21a54SThe etnaviv authors bitmap_set(etnaviv_states, etnaviv_sensitive_states[i].offset,
86a8c21a54SThe etnaviv authors etnaviv_sensitive_states[i].size);
87a8c21a54SThe etnaviv authors }
88a8c21a54SThe etnaviv authors
etnaviv_warn_if_non_sensitive(struct etna_validation_state * state,unsigned int buf_offset,unsigned int state_addr)89a8c21a54SThe etnaviv authors static void etnaviv_warn_if_non_sensitive(struct etna_validation_state *state,
90a8c21a54SThe etnaviv authors unsigned int buf_offset, unsigned int state_addr)
91a8c21a54SThe etnaviv authors {
92a8c21a54SThe etnaviv authors if (state->num_relocs && state->relocs->submit_offset < buf_offset) {
93a8c21a54SThe etnaviv authors dev_warn_once(state->gpu->dev,
94a8c21a54SThe etnaviv authors "%s: relocation for non-sensitive state 0x%x at offset %u\n",
95a8c21a54SThe etnaviv authors __func__, state_addr,
96a8c21a54SThe etnaviv authors state->relocs->submit_offset);
97a8c21a54SThe etnaviv authors while (state->num_relocs &&
98a8c21a54SThe etnaviv authors state->relocs->submit_offset < buf_offset) {
99a8c21a54SThe etnaviv authors state->relocs++;
100a8c21a54SThe etnaviv authors state->num_relocs--;
101a8c21a54SThe etnaviv authors }
102a8c21a54SThe etnaviv authors }
103a8c21a54SThe etnaviv authors }
104a8c21a54SThe etnaviv authors
etnaviv_validate_load_state(struct etna_validation_state * state,u32 * ptr,unsigned int state_offset,unsigned int num)105a8c21a54SThe etnaviv authors static bool etnaviv_validate_load_state(struct etna_validation_state *state,
106a8c21a54SThe etnaviv authors u32 *ptr, unsigned int state_offset, unsigned int num)
107a8c21a54SThe etnaviv authors {
108a8c21a54SThe etnaviv authors unsigned int size = min(ETNAVIV_STATES_SIZE, state_offset + num);
109a8c21a54SThe etnaviv authors unsigned int st_offset = state_offset, buf_offset;
110a8c21a54SThe etnaviv authors
111a8c21a54SThe etnaviv authors for_each_set_bit_from(st_offset, etnaviv_states, size) {
112a8c21a54SThe etnaviv authors buf_offset = (ptr - state->start +
113a8c21a54SThe etnaviv authors st_offset - state_offset) * 4;
114a8c21a54SThe etnaviv authors
115a8c21a54SThe etnaviv authors etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4);
116a8c21a54SThe etnaviv authors if (state->num_relocs &&
117a8c21a54SThe etnaviv authors state->relocs->submit_offset == buf_offset) {
118a8c21a54SThe etnaviv authors state->relocs++;
119a8c21a54SThe etnaviv authors state->num_relocs--;
120a8c21a54SThe etnaviv authors continue;
121a8c21a54SThe etnaviv authors }
122a8c21a54SThe etnaviv authors
123a8c21a54SThe etnaviv authors dev_warn_ratelimited(state->gpu->dev,
124a8c21a54SThe etnaviv authors "%s: load state touches restricted state 0x%x at offset %u\n",
125a8c21a54SThe etnaviv authors __func__, st_offset * 4, buf_offset);
126a8c21a54SThe etnaviv authors return false;
127a8c21a54SThe etnaviv authors }
128a8c21a54SThe etnaviv authors
129a8c21a54SThe etnaviv authors if (state->num_relocs) {
130a8c21a54SThe etnaviv authors buf_offset = (ptr - state->start + num) * 4;
131a8c21a54SThe etnaviv authors etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4 +
132a8c21a54SThe etnaviv authors state->relocs->submit_offset -
133a8c21a54SThe etnaviv authors buf_offset);
134a8c21a54SThe etnaviv authors }
135a8c21a54SThe etnaviv authors
136a8c21a54SThe etnaviv authors return true;
137a8c21a54SThe etnaviv authors }
138a8c21a54SThe etnaviv authors
139a8c21a54SThe etnaviv authors static uint8_t cmd_length[32] = {
140a8c21a54SThe etnaviv authors [FE_OPCODE_DRAW_PRIMITIVES] = 4,
141a8c21a54SThe etnaviv authors [FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6,
14255780053SWladimir J. van der Laan [FE_OPCODE_DRAW_INSTANCED] = 4,
143a8c21a54SThe etnaviv authors [FE_OPCODE_NOP] = 2,
144a8c21a54SThe etnaviv authors [FE_OPCODE_STALL] = 2,
145a8c21a54SThe etnaviv authors };
146a8c21a54SThe etnaviv authors
etnaviv_cmd_validate_one(struct etnaviv_gpu * gpu,u32 * stream,unsigned int size,struct drm_etnaviv_gem_submit_reloc * relocs,unsigned int reloc_size)147a8c21a54SThe etnaviv authors bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, u32 *stream,
148a8c21a54SThe etnaviv authors unsigned int size,
149a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_submit_reloc *relocs,
150a8c21a54SThe etnaviv authors unsigned int reloc_size)
151a8c21a54SThe etnaviv authors {
152a8c21a54SThe etnaviv authors struct etna_validation_state state;
153a8c21a54SThe etnaviv authors u32 *buf = stream;
154a8c21a54SThe etnaviv authors u32 *end = buf + size;
155a8c21a54SThe etnaviv authors
156a8c21a54SThe etnaviv authors state.gpu = gpu;
157a8c21a54SThe etnaviv authors state.relocs = relocs;
158a8c21a54SThe etnaviv authors state.num_relocs = reloc_size;
159a8c21a54SThe etnaviv authors state.start = stream;
160a8c21a54SThe etnaviv authors
161a8c21a54SThe etnaviv authors while (buf < end) {
162a8c21a54SThe etnaviv authors u32 cmd = *buf;
163a8c21a54SThe etnaviv authors unsigned int len, n, off;
164a8c21a54SThe etnaviv authors unsigned int op = cmd >> 27;
165a8c21a54SThe etnaviv authors
166a8c21a54SThe etnaviv authors switch (op) {
167a8c21a54SThe etnaviv authors case FE_OPCODE_LOAD_STATE:
168a8c21a54SThe etnaviv authors n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
169a8c21a54SThe etnaviv authors len = ALIGN(1 + n, 2);
170a8c21a54SThe etnaviv authors if (buf + len > end)
171a8c21a54SThe etnaviv authors break;
172a8c21a54SThe etnaviv authors
173a8c21a54SThe etnaviv authors off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET);
174a8c21a54SThe etnaviv authors if (!etnaviv_validate_load_state(&state, buf + 1,
175a8c21a54SThe etnaviv authors off, n))
176a8c21a54SThe etnaviv authors return false;
177a8c21a54SThe etnaviv authors break;
178a8c21a54SThe etnaviv authors
179a8c21a54SThe etnaviv authors case FE_OPCODE_DRAW_2D:
180a8c21a54SThe etnaviv authors n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT);
181a8c21a54SThe etnaviv authors if (n == 0)
182a8c21a54SThe etnaviv authors n = 256;
183a8c21a54SThe etnaviv authors len = 2 + n * 2;
184a8c21a54SThe etnaviv authors break;
185a8c21a54SThe etnaviv authors
186a8c21a54SThe etnaviv authors default:
187a8c21a54SThe etnaviv authors len = cmd_length[op];
188a8c21a54SThe etnaviv authors if (len == 0) {
189a8c21a54SThe etnaviv authors dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
190a8c21a54SThe etnaviv authors __func__, op, buf - state.start);
191a8c21a54SThe etnaviv authors return false;
192a8c21a54SThe etnaviv authors }
193a8c21a54SThe etnaviv authors break;
194a8c21a54SThe etnaviv authors }
195a8c21a54SThe etnaviv authors
196a8c21a54SThe etnaviv authors buf += len;
197a8c21a54SThe etnaviv authors }
198a8c21a54SThe etnaviv authors
199a8c21a54SThe etnaviv authors if (buf > end) {
200a8c21a54SThe etnaviv authors dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
201a8c21a54SThe etnaviv authors __func__, buf - state.start, size);
202a8c21a54SThe etnaviv authors return false;
203a8c21a54SThe etnaviv authors }
204a8c21a54SThe etnaviv authors
205a8c21a54SThe etnaviv authors return true;
206a8c21a54SThe etnaviv authors }
207