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) }
81 #define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
82 static DECLARE_BITMAP(etnaviv_states
, ETNAVIV_STATES_SIZE
);
84 void __init
etnaviv_validate_init(void)
88 for (i
= 0; i
< ARRAY_SIZE(etnaviv_sensitive_states
); i
++)
89 bitmap_set(etnaviv_states
, etnaviv_sensitive_states
[i
].offset
,
90 etnaviv_sensitive_states
[i
].size
);
93 static void etnaviv_warn_if_non_sensitive(struct etna_validation_state
*state
,
94 unsigned int buf_offset
, unsigned int state_addr
)
96 if (state
->num_relocs
&& state
->relocs
->submit_offset
< buf_offset
) {
97 dev_warn_once(state
->gpu
->dev
,
98 "%s: relocation for non-sensitive state 0x%x at offset %u\n",
100 state
->relocs
->submit_offset
);
101 while (state
->num_relocs
&&
102 state
->relocs
->submit_offset
< buf_offset
) {
109 static bool etnaviv_validate_load_state(struct etna_validation_state
*state
,
110 u32
*ptr
, unsigned int state_offset
, unsigned int num
)
112 unsigned int size
= min(ETNAVIV_STATES_SIZE
, state_offset
+ num
);
113 unsigned int st_offset
= state_offset
, buf_offset
;
115 for_each_set_bit_from(st_offset
, etnaviv_states
, size
) {
116 buf_offset
= (ptr
- state
->start
+
117 st_offset
- state_offset
) * 4;
119 etnaviv_warn_if_non_sensitive(state
, buf_offset
, st_offset
* 4);
120 if (state
->num_relocs
&&
121 state
->relocs
->submit_offset
== buf_offset
) {
127 dev_warn_ratelimited(state
->gpu
->dev
,
128 "%s: load state touches restricted state 0x%x at offset %u\n",
129 __func__
, st_offset
* 4, buf_offset
);
133 if (state
->num_relocs
) {
134 buf_offset
= (ptr
- state
->start
+ num
) * 4;
135 etnaviv_warn_if_non_sensitive(state
, buf_offset
, st_offset
* 4 +
136 state
->relocs
->submit_offset
-
143 static uint8_t cmd_length
[32] = {
144 [FE_OPCODE_DRAW_PRIMITIVES
] = 4,
145 [FE_OPCODE_DRAW_INDEXED_PRIMITIVES
] = 6,
146 [FE_OPCODE_DRAW_INSTANCED
] = 4,
148 [FE_OPCODE_STALL
] = 2,
151 bool etnaviv_cmd_validate_one(struct etnaviv_gpu
*gpu
, u32
*stream
,
153 struct drm_etnaviv_gem_submit_reloc
*relocs
,
154 unsigned int reloc_size
)
156 struct etna_validation_state state
;
158 u32
*end
= buf
+ size
;
161 state
.relocs
= relocs
;
162 state
.num_relocs
= reloc_size
;
163 state
.start
= stream
;
167 unsigned int len
, n
, off
;
168 unsigned int op
= cmd
>> 27;
171 case FE_OPCODE_LOAD_STATE
:
172 n
= EXTRACT(cmd
, VIV_FE_LOAD_STATE_HEADER_COUNT
);
173 len
= ALIGN(1 + n
, 2);
177 off
= EXTRACT(cmd
, VIV_FE_LOAD_STATE_HEADER_OFFSET
);
178 if (!etnaviv_validate_load_state(&state
, buf
+ 1,
183 case FE_OPCODE_DRAW_2D
:
184 n
= EXTRACT(cmd
, VIV_FE_DRAW_2D_HEADER_COUNT
);
191 len
= cmd_length
[op
];
193 dev_err(gpu
->dev
, "%s: op %u not permitted at offset %tu\n",
194 __func__
, op
, buf
- state
.start
);
204 dev_err(gpu
->dev
, "%s: commands overflow end of buffer: %tu > %u\n",
205 __func__
, buf
- state
.start
, size
);