2 * Copyright (C) 2015 Etnaviv Project
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program. If not, see <http://www.gnu.org/licenses/>.
17 #include <linux/kernel.h>
19 #include "etnaviv_gem.h"
20 #include "etnaviv_gpu.h"
22 #include "cmdstream.xml.h"
24 #define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
26 struct etna_validation_state
{
27 struct etnaviv_gpu
*gpu
;
28 const struct drm_etnaviv_gem_submit_reloc
*relocs
;
29 unsigned int num_relocs
;
36 } etnaviv_sensitive_states
[] __initconst
= {
37 #define ST(start, num) { (start) >> 2, (num) }
88 #define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
89 static DECLARE_BITMAP(etnaviv_states
, ETNAVIV_STATES_SIZE
);
91 void __init
etnaviv_validate_init(void)
95 for (i
= 0; i
< ARRAY_SIZE(etnaviv_sensitive_states
); i
++)
96 bitmap_set(etnaviv_states
, etnaviv_sensitive_states
[i
].offset
,
97 etnaviv_sensitive_states
[i
].size
);
100 static void etnaviv_warn_if_non_sensitive(struct etna_validation_state
*state
,
101 unsigned int buf_offset
, unsigned int state_addr
)
103 if (state
->num_relocs
&& state
->relocs
->submit_offset
< buf_offset
) {
104 dev_warn_once(state
->gpu
->dev
,
105 "%s: relocation for non-sensitive state 0x%x at offset %u\n",
106 __func__
, state_addr
,
107 state
->relocs
->submit_offset
);
108 while (state
->num_relocs
&&
109 state
->relocs
->submit_offset
< buf_offset
) {
116 static bool etnaviv_validate_load_state(struct etna_validation_state
*state
,
117 u32
*ptr
, unsigned int state_offset
, unsigned int num
)
119 unsigned int size
= min(ETNAVIV_STATES_SIZE
, state_offset
+ num
);
120 unsigned int st_offset
= state_offset
, buf_offset
;
122 for_each_set_bit_from(st_offset
, etnaviv_states
, size
) {
123 buf_offset
= (ptr
- state
->start
+
124 st_offset
- state_offset
) * 4;
126 etnaviv_warn_if_non_sensitive(state
, buf_offset
, st_offset
* 4);
127 if (state
->num_relocs
&&
128 state
->relocs
->submit_offset
== buf_offset
) {
134 dev_warn_ratelimited(state
->gpu
->dev
,
135 "%s: load state touches restricted state 0x%x at offset %u\n",
136 __func__
, st_offset
* 4, buf_offset
);
140 if (state
->num_relocs
) {
141 buf_offset
= (ptr
- state
->start
+ num
) * 4;
142 etnaviv_warn_if_non_sensitive(state
, buf_offset
, st_offset
* 4 +
143 state
->relocs
->submit_offset
-
150 static uint8_t cmd_length
[32] = {
151 [FE_OPCODE_DRAW_PRIMITIVES
] = 4,
152 [FE_OPCODE_DRAW_INDEXED_PRIMITIVES
] = 6,
153 [FE_OPCODE_DRAW_INSTANCED
] = 4,
155 [FE_OPCODE_STALL
] = 2,
158 bool etnaviv_cmd_validate_one(struct etnaviv_gpu
*gpu
, u32
*stream
,
160 struct drm_etnaviv_gem_submit_reloc
*relocs
,
161 unsigned int reloc_size
)
163 struct etna_validation_state state
;
165 u32
*end
= buf
+ size
;
168 state
.relocs
= relocs
;
169 state
.num_relocs
= reloc_size
;
170 state
.start
= stream
;
174 unsigned int len
, n
, off
;
175 unsigned int op
= cmd
>> 27;
178 case FE_OPCODE_LOAD_STATE
:
179 n
= EXTRACT(cmd
, VIV_FE_LOAD_STATE_HEADER_COUNT
);
180 len
= ALIGN(1 + n
, 2);
184 off
= EXTRACT(cmd
, VIV_FE_LOAD_STATE_HEADER_OFFSET
);
185 if (!etnaviv_validate_load_state(&state
, buf
+ 1,
190 case FE_OPCODE_DRAW_2D
:
191 n
= EXTRACT(cmd
, VIV_FE_DRAW_2D_HEADER_COUNT
);
198 len
= cmd_length
[op
];
200 dev_err(gpu
->dev
, "%s: op %u not permitted at offset %tu\n",
201 __func__
, op
, buf
- state
.start
);
211 dev_err(gpu
->dev
, "%s: commands overflow end of buffer: %tu > %u\n",
212 __func__
, buf
- state
.start
, size
);