xref: /openbmc/linux/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
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