1/*
2 * Copyright 2004 The Unichrome Project. All Rights Reserved.
3 * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Author: Thomas Hellstrom 2004, 2005.
25 * This code was written using docs obtained under NDA from VIA Inc.
26 *
27 * Don't run this code directly on an AGP buffer. Due to cache problems it will
28 * be very slow.
29 */
30
31#include <drm/drm_device.h>
32#include <drm/drm_legacy.h>
33#include <drm/via_drm.h>
34
35#include "via_3d_reg.h"
36#include "via_drv.h"
37#include "via_verifier.h"
38
39typedef enum {
40	state_command,
41	state_header2,
42	state_header1,
43	state_vheader5,
44	state_vheader6,
45	state_error
46} verifier_state_t;
47
48typedef enum {
49	no_check = 0,
50	check_for_header2,
51	check_for_header1,
52	check_for_header2_err,
53	check_for_header1_err,
54	check_for_fire,
55	check_z_buffer_addr0,
56	check_z_buffer_addr1,
57	check_z_buffer_addr_mode,
58	check_destination_addr0,
59	check_destination_addr1,
60	check_destination_addr_mode,
61	check_for_dummy,
62	check_for_dd,
63	check_texture_addr0,
64	check_texture_addr1,
65	check_texture_addr2,
66	check_texture_addr3,
67	check_texture_addr4,
68	check_texture_addr5,
69	check_texture_addr6,
70	check_texture_addr7,
71	check_texture_addr8,
72	check_texture_addr_mode,
73	check_for_vertex_count,
74	check_number_texunits,
75	forbidden_command
76} hazard_t;
77
78/*
79 * Associates each hazard above with a possible multi-command
80 * sequence. For example an address that is split over multiple
81 * commands and that needs to be checked at the first command
82 * that does not include any part of the address.
83 */
84
85static drm_via_sequence_t seqs[] = {
86	no_sequence,
87	no_sequence,
88	no_sequence,
89	no_sequence,
90	no_sequence,
91	no_sequence,
92	z_address,
93	z_address,
94	z_address,
95	dest_address,
96	dest_address,
97	dest_address,
98	no_sequence,
99	no_sequence,
100	tex_address,
101	tex_address,
102	tex_address,
103	tex_address,
104	tex_address,
105	tex_address,
106	tex_address,
107	tex_address,
108	tex_address,
109	tex_address,
110	no_sequence
111};
112
113typedef struct {
114	unsigned int code;
115	hazard_t hz;
116} hz_init_t;
117
118static hz_init_t init_table1[] = {
119	{0xf2, check_for_header2_err},
120	{0xf0, check_for_header1_err},
121	{0xee, check_for_fire},
122	{0xcc, check_for_dummy},
123	{0xdd, check_for_dd},
124	{0x00, no_check},
125	{0x10, check_z_buffer_addr0},
126	{0x11, check_z_buffer_addr1},
127	{0x12, check_z_buffer_addr_mode},
128	{0x13, no_check},
129	{0x14, no_check},
130	{0x15, no_check},
131	{0x23, no_check},
132	{0x24, no_check},
133	{0x33, no_check},
134	{0x34, no_check},
135	{0x35, no_check},
136	{0x36, no_check},
137	{0x37, no_check},
138	{0x38, no_check},
139	{0x39, no_check},
140	{0x3A, no_check},
141	{0x3B, no_check},
142	{0x3C, no_check},
143	{0x3D, no_check},
144	{0x3E, no_check},
145	{0x40, check_destination_addr0},
146	{0x41, check_destination_addr1},
147	{0x42, check_destination_addr_mode},
148	{0x43, no_check},
149	{0x44, no_check},
150	{0x50, no_check},
151	{0x51, no_check},
152	{0x52, no_check},
153	{0x53, no_check},
154	{0x54, no_check},
155	{0x55, no_check},
156	{0x56, no_check},
157	{0x57, no_check},
158	{0x58, no_check},
159	{0x70, no_check},
160	{0x71, no_check},
161	{0x78, no_check},
162	{0x79, no_check},
163	{0x7A, no_check},
164	{0x7B, no_check},
165	{0x7C, no_check},
166	{0x7D, check_for_vertex_count}
167};
168
169static hz_init_t init_table2[] = {
170	{0xf2, check_for_header2_err},
171	{0xf0, check_for_header1_err},
172	{0xee, check_for_fire},
173	{0xcc, check_for_dummy},
174	{0x00, check_texture_addr0},
175	{0x01, check_texture_addr0},
176	{0x02, check_texture_addr0},
177	{0x03, check_texture_addr0},
178	{0x04, check_texture_addr0},
179	{0x05, check_texture_addr0},
180	{0x06, check_texture_addr0},
181	{0x07, check_texture_addr0},
182	{0x08, check_texture_addr0},
183	{0x09, check_texture_addr0},
184	{0x20, check_texture_addr1},
185	{0x21, check_texture_addr1},
186	{0x22, check_texture_addr1},
187	{0x23, check_texture_addr4},
188	{0x2B, check_texture_addr3},
189	{0x2C, check_texture_addr3},
190	{0x2D, check_texture_addr3},
191	{0x2E, check_texture_addr3},
192	{0x2F, check_texture_addr3},
193	{0x30, check_texture_addr3},
194	{0x31, check_texture_addr3},
195	{0x32, check_texture_addr3},
196	{0x33, check_texture_addr3},
197	{0x34, check_texture_addr3},
198	{0x4B, check_texture_addr5},
199	{0x4C, check_texture_addr6},
200	{0x51, check_texture_addr7},
201	{0x52, check_texture_addr8},
202	{0x77, check_texture_addr2},
203	{0x78, no_check},
204	{0x79, no_check},
205	{0x7A, no_check},
206	{0x7B, check_texture_addr_mode},
207	{0x7C, no_check},
208	{0x7D, no_check},
209	{0x7E, no_check},
210	{0x7F, no_check},
211	{0x80, no_check},
212	{0x81, no_check},
213	{0x82, no_check},
214	{0x83, no_check},
215	{0x85, no_check},
216	{0x86, no_check},
217	{0x87, no_check},
218	{0x88, no_check},
219	{0x89, no_check},
220	{0x8A, no_check},
221	{0x90, no_check},
222	{0x91, no_check},
223	{0x92, no_check},
224	{0x93, no_check}
225};
226
227static hz_init_t init_table3[] = {
228	{0xf2, check_for_header2_err},
229	{0xf0, check_for_header1_err},
230	{0xcc, check_for_dummy},
231	{0x00, check_number_texunits}
232};
233
234static hazard_t table1[256];
235static hazard_t table2[256];
236static hazard_t table3[256];
237
238static __inline__ int
239eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
240{
241	if ((buf_end - *buf) >= num_words) {
242		*buf += num_words;
243		return 0;
244	}
245	DRM_ERROR("Illegal termination of DMA command buffer\n");
246	return 1;
247}
248
249/*
250 * Partially stolen from drm_memory.h
251 */
252
253static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
254						    unsigned long offset,
255						    unsigned long size,
256						    struct drm_device *dev)
257{
258	struct drm_map_list *r_list;
259	drm_local_map_t *map = seq->map_cache;
260
261	if (map && map->offset <= offset
262	    && (offset + size) <= (map->offset + map->size)) {
263		return map;
264	}
265
266	list_for_each_entry(r_list, &dev->maplist, head) {
267		map = r_list->map;
268		if (!map)
269			continue;
270		if (map->offset <= offset
271		    && (offset + size) <= (map->offset + map->size)
272		    && !(map->flags & _DRM_RESTRICTED)
273		    && (map->type == _DRM_AGP)) {
274			seq->map_cache = map;
275			return map;
276		}
277	}
278	return NULL;
279}
280
281/*
282 * Require that all AGP texture levels reside in the same AGP map which should
283 * be mappable by the client. This is not a big restriction.
284 * FIXME: To actually enforce this security policy strictly, drm_rmmap
285 * would have to wait for dma quiescent before removing an AGP map.
286 * The via_drm_lookup_agp_map call in reality seems to take
287 * very little CPU time.
288 */
289
290static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
291{
292	switch (cur_seq->unfinished) {
293	case z_address:
294		DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
295		break;
296	case dest_address:
297		DRM_DEBUG("Destination start address is 0x%x\n",
298			  cur_seq->d_addr);
299		break;
300	case tex_address:
301		if (cur_seq->agp_texture) {
302			unsigned start =
303			    cur_seq->tex_level_lo[cur_seq->texture];
304			unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
305			unsigned long lo = ~0, hi = 0, tmp;
306			uint32_t *addr, *pitch, *height, tex;
307			unsigned i;
308			int npot;
309
310			if (end > 9)
311				end = 9;
312			if (start > 9)
313				start = 9;
314
315			addr =
316			    &(cur_seq->t_addr[tex = cur_seq->texture][start]);
317			pitch = &(cur_seq->pitch[tex][start]);
318			height = &(cur_seq->height[tex][start]);
319			npot = cur_seq->tex_npot[tex];
320			for (i = start; i <= end; ++i) {
321				tmp = *addr++;
322				if (tmp < lo)
323					lo = tmp;
324				if (i == 0 && npot)
325					tmp += (*height++ * *pitch++);
326				else
327					tmp += (*height++ << *pitch++);
328				if (tmp > hi)
329					hi = tmp;
330			}
331
332			if (!via_drm_lookup_agp_map
333			    (cur_seq, lo, hi - lo, cur_seq->dev)) {
334				DRM_ERROR
335				    ("AGP texture is not in allowed map\n");
336				return 2;
337			}
338		}
339		break;
340	default:
341		break;
342	}
343	cur_seq->unfinished = no_sequence;
344	return 0;
345}
346
347static __inline__ int
348investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
349{
350	register uint32_t tmp, *tmp_addr;
351
352	if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
353		int ret;
354		if ((ret = finish_current_sequence(cur_seq)))
355			return ret;
356	}
357
358	switch (hz) {
359	case check_for_header2:
360		if (cmd == HALCYON_HEADER2)
361			return 1;
362		return 0;
363	case check_for_header1:
364		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
365			return 1;
366		return 0;
367	case check_for_header2_err:
368		if (cmd == HALCYON_HEADER2)
369			return 1;
370		DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
371		break;
372	case check_for_header1_err:
373		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
374			return 1;
375		DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
376		break;
377	case check_for_fire:
378		if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD)
379			return 1;
380		DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
381		break;
382	case check_for_dummy:
383		if (HC_DUMMY == cmd)
384			return 0;
385		DRM_ERROR("Illegal DMA HC_DUMMY command\n");
386		break;
387	case check_for_dd:
388		if (0xdddddddd == cmd)
389			return 0;
390		DRM_ERROR("Illegal DMA 0xdddddddd command\n");
391		break;
392	case check_z_buffer_addr0:
393		cur_seq->unfinished = z_address;
394		cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
395		    (cmd & 0x00FFFFFF);
396		return 0;
397	case check_z_buffer_addr1:
398		cur_seq->unfinished = z_address;
399		cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
400		    ((cmd & 0xFF) << 24);
401		return 0;
402	case check_z_buffer_addr_mode:
403		cur_seq->unfinished = z_address;
404		if ((cmd & 0x0000C000) == 0)
405			return 0;
406		DRM_ERROR("Attempt to place Z buffer in system memory\n");
407		return 2;
408	case check_destination_addr0:
409		cur_seq->unfinished = dest_address;
410		cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
411		    (cmd & 0x00FFFFFF);
412		return 0;
413	case check_destination_addr1:
414		cur_seq->unfinished = dest_address;
415		cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
416		    ((cmd & 0xFF) << 24);
417		return 0;
418	case check_destination_addr_mode:
419		cur_seq->unfinished = dest_address;
420		if ((cmd & 0x0000C000) == 0)
421			return 0;
422		DRM_ERROR
423		    ("Attempt to place 3D drawing buffer in system memory\n");
424		return 2;
425	case check_texture_addr0:
426		cur_seq->unfinished = tex_address;
427		tmp = (cmd >> 24);
428		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
429		*tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
430		return 0;
431	case check_texture_addr1:
432		cur_seq->unfinished = tex_address;
433		tmp = ((cmd >> 24) - 0x20);
434		tmp += tmp << 1;
435		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
436		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
437		tmp_addr++;
438		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
439		tmp_addr++;
440		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
441		return 0;
442	case check_texture_addr2:
443		cur_seq->unfinished = tex_address;
444		cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
445		cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
446		return 0;
447	case check_texture_addr3:
448		cur_seq->unfinished = tex_address;
449		tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
450		if (tmp == 0 &&
451		    (cmd & HC_HTXnEnPit_MASK)) {
452			cur_seq->pitch[cur_seq->texture][tmp] =
453				(cmd & HC_HTXnLnPit_MASK);
454			cur_seq->tex_npot[cur_seq->texture] = 1;
455		} else {
456			cur_seq->pitch[cur_seq->texture][tmp] =
457				(cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
458			cur_seq->tex_npot[cur_seq->texture] = 0;
459			if (cmd & 0x000FFFFF) {
460				DRM_ERROR
461					("Unimplemented texture level 0 pitch mode.\n");
462				return 2;
463			}
464		}
465		return 0;
466	case check_texture_addr4:
467		cur_seq->unfinished = tex_address;
468		tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
469		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
470		return 0;
471	case check_texture_addr5:
472	case check_texture_addr6:
473		cur_seq->unfinished = tex_address;
474		/*
475		 * Texture width. We don't care since we have the pitch.
476		 */
477		return 0;
478	case check_texture_addr7:
479		cur_seq->unfinished = tex_address;
480		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
481		tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
482		tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
483		tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
484		tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
485		tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
486		tmp_addr[0] = 1 << (cmd & 0x0000000F);
487		return 0;
488	case check_texture_addr8:
489		cur_seq->unfinished = tex_address;
490		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
491		tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
492		tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
493		tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
494		tmp_addr[6] = 1 << (cmd & 0x0000000F);
495		return 0;
496	case check_texture_addr_mode:
497		cur_seq->unfinished = tex_address;
498		if (2 == (tmp = cmd & 0x00000003)) {
499			DRM_ERROR
500			    ("Attempt to fetch texture from system memory.\n");
501			return 2;
502		}
503		cur_seq->agp_texture = (tmp == 3);
504		cur_seq->tex_palette_size[cur_seq->texture] =
505		    (cmd >> 16) & 0x000000007;
506		return 0;
507	case check_for_vertex_count:
508		cur_seq->vertex_count = cmd & 0x0000FFFF;
509		return 0;
510	case check_number_texunits:
511		cur_seq->multitex = (cmd >> 3) & 1;
512		return 0;
513	default:
514		DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
515		return 2;
516	}
517	return 2;
518}
519
520static __inline__ int
521via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
522		    drm_via_state_t *cur_seq)
523{
524	drm_via_private_t *dev_priv =
525	    (drm_via_private_t *) cur_seq->dev->dev_private;
526	uint32_t a_fire, bcmd, dw_count;
527	int ret = 0;
528	int have_fire;
529	const uint32_t *buf = *buffer;
530
531	while (buf < buf_end) {
532		have_fire = 0;
533		if ((buf_end - buf) < 2) {
534			DRM_ERROR
535			    ("Unexpected termination of primitive list.\n");
536			ret = 1;
537			break;
538		}
539		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB)
540			break;
541		bcmd = *buf++;
542		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
543			DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
544				  *buf);
545			ret = 1;
546			break;
547		}
548		a_fire =
549		    *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK |
550		    HC_HE3Fire_MASK;
551
552		/*
553		 * How many dwords per vertex ?
554		 */
555
556		if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
557			DRM_ERROR("Illegal B command vertex data for AGP.\n");
558			ret = 1;
559			break;
560		}
561
562		dw_count = 0;
563		if (bcmd & (1 << 7))
564			dw_count += (cur_seq->multitex) ? 2 : 1;
565		if (bcmd & (1 << 8))
566			dw_count += (cur_seq->multitex) ? 2 : 1;
567		if (bcmd & (1 << 9))
568			dw_count++;
569		if (bcmd & (1 << 10))
570			dw_count++;
571		if (bcmd & (1 << 11))
572			dw_count++;
573		if (bcmd & (1 << 12))
574			dw_count++;
575		if (bcmd & (1 << 13))
576			dw_count++;
577		if (bcmd & (1 << 14))
578			dw_count++;
579
580		while (buf < buf_end) {
581			if (*buf == a_fire) {
582				if (dev_priv->num_fire_offsets >=
583				    VIA_FIRE_BUF_SIZE) {
584					DRM_ERROR("Fire offset buffer full.\n");
585					ret = 1;
586					break;
587				}
588				dev_priv->fire_offsets[dev_priv->
589						       num_fire_offsets++] =
590				    buf;
591				have_fire = 1;
592				buf++;
593				if (buf < buf_end && *buf == a_fire)
594					buf++;
595				break;
596			}
597			if ((*buf == HALCYON_HEADER2) ||
598			    ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
599				DRM_ERROR("Missing Vertex Fire command, "
600					  "Stray Vertex Fire command  or verifier "
601					  "lost sync.\n");
602				ret = 1;
603				break;
604			}
605			if ((ret = eat_words(&buf, buf_end, dw_count)))
606				break;
607		}
608		if (buf >= buf_end && !have_fire) {
609			DRM_ERROR("Missing Vertex Fire command or verifier "
610				  "lost sync.\n");
611			ret = 1;
612			break;
613		}
614		if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
615			DRM_ERROR("AGP Primitive list end misaligned.\n");
616			ret = 1;
617			break;
618		}
619	}
620	*buffer = buf;
621	return ret;
622}
623
624static __inline__ verifier_state_t
625via_check_header2(uint32_t const **buffer, const uint32_t *buf_end,
626		  drm_via_state_t *hc_state)
627{
628	uint32_t cmd;
629	int hz_mode;
630	hazard_t hz;
631	const uint32_t *buf = *buffer;
632	const hazard_t *hz_table;
633
634	if ((buf_end - buf) < 2) {
635		DRM_ERROR
636		    ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
637		return state_error;
638	}
639	buf++;
640	cmd = (*buf++ & 0xFFFF0000) >> 16;
641
642	switch (cmd) {
643	case HC_ParaType_CmdVdata:
644		if (via_check_prim_list(&buf, buf_end, hc_state))
645			return state_error;
646		*buffer = buf;
647		return state_command;
648	case HC_ParaType_NotTex:
649		hz_table = table1;
650		break;
651	case HC_ParaType_Tex:
652		hc_state->texture = 0;
653		hz_table = table2;
654		break;
655	case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
656		hc_state->texture = 1;
657		hz_table = table2;
658		break;
659	case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
660		hz_table = table3;
661		break;
662	case HC_ParaType_Auto:
663		if (eat_words(&buf, buf_end, 2))
664			return state_error;
665		*buffer = buf;
666		return state_command;
667	case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
668		if (eat_words(&buf, buf_end, 32))
669			return state_error;
670		*buffer = buf;
671		return state_command;
672	case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
673	case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
674		DRM_ERROR("Texture palettes are rejected because of "
675			  "lack of info how to determine their size.\n");
676		return state_error;
677	case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
678		DRM_ERROR("Fog factor palettes are rejected because of "
679			  "lack of info how to determine their size.\n");
680		return state_error;
681	default:
682
683		/*
684		 * There are some unimplemented HC_ParaTypes here, that
685		 * need to be implemented if the Mesa driver is extended.
686		 */
687
688		DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
689			  "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
690			  cmd, *(buf - 2));
691		*buffer = buf;
692		return state_error;
693	}
694
695	while (buf < buf_end) {
696		cmd = *buf++;
697		if ((hz = hz_table[cmd >> 24])) {
698			if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
699				if (hz_mode == 1) {
700					buf--;
701					break;
702				}
703				return state_error;
704			}
705		} else if (hc_state->unfinished &&
706			   finish_current_sequence(hc_state)) {
707			return state_error;
708		}
709	}
710	if (hc_state->unfinished && finish_current_sequence(hc_state))
711		return state_error;
712	*buffer = buf;
713	return state_command;
714}
715
716static __inline__ verifier_state_t
717via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer,
718		  const uint32_t *buf_end, int *fire_count)
719{
720	uint32_t cmd;
721	const uint32_t *buf = *buffer;
722	const uint32_t *next_fire;
723	int burst = 0;
724
725	next_fire = dev_priv->fire_offsets[*fire_count];
726	buf++;
727	cmd = (*buf & 0xFFFF0000) >> 16;
728	via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
729	switch (cmd) {
730	case HC_ParaType_CmdVdata:
731		while ((buf < buf_end) &&
732		       (*fire_count < dev_priv->num_fire_offsets) &&
733		       (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) {
734			while (buf <= next_fire) {
735				via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
736					  (burst & 63), *buf++);
737				burst += 4;
738			}
739			if ((buf < buf_end)
740			    && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
741				buf++;
742
743			if (++(*fire_count) < dev_priv->num_fire_offsets)
744				next_fire = dev_priv->fire_offsets[*fire_count];
745		}
746		break;
747	default:
748		while (buf < buf_end) {
749
750			if (*buf == HC_HEADER2 ||
751			    (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
752			    (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
753			    (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
754				break;
755
756			via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
757				  (burst & 63), *buf++);
758			burst += 4;
759		}
760	}
761	*buffer = buf;
762	return state_command;
763}
764
765static __inline__ int verify_mmio_address(uint32_t address)
766{
767	if ((address > 0x3FF) && (address < 0xC00)) {
768		DRM_ERROR("Invalid VIDEO DMA command. "
769			  "Attempt to access 3D- or command burst area.\n");
770		return 1;
771	} else if ((address > 0xCFF) && (address < 0x1300)) {
772		DRM_ERROR("Invalid VIDEO DMA command. "
773			  "Attempt to access PCI DMA area.\n");
774		return 1;
775	} else if (address > 0x13FF) {
776		DRM_ERROR("Invalid VIDEO DMA command. "
777			  "Attempt to access VGA registers.\n");
778		return 1;
779	}
780	return 0;
781}
782
783static __inline__ int
784verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end,
785		  uint32_t dwords)
786{
787	const uint32_t *buf = *buffer;
788
789	if (buf_end - buf < dwords) {
790		DRM_ERROR("Illegal termination of video command.\n");
791		return 1;
792	}
793	while (dwords--) {
794		if (*buf++) {
795			DRM_ERROR("Illegal video command tail.\n");
796			return 1;
797		}
798	}
799	*buffer = buf;
800	return 0;
801}
802
803static __inline__ verifier_state_t
804via_check_header1(uint32_t const **buffer, const uint32_t * buf_end)
805{
806	uint32_t cmd;
807	const uint32_t *buf = *buffer;
808	verifier_state_t ret = state_command;
809
810	while (buf < buf_end) {
811		cmd = *buf;
812		if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
813		    (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {
814			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
815				break;
816			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
817				  "Attempt to access 3D- or command burst area.\n");
818			ret = state_error;
819			break;
820		} else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
821			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
822				break;
823			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
824				  "Attempt to access VGA registers.\n");
825			ret = state_error;
826			break;
827		} else {
828			buf += 2;
829		}
830	}
831	*buffer = buf;
832	return ret;
833}
834
835static __inline__ verifier_state_t
836via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer,
837		  const uint32_t *buf_end)
838{
839	register uint32_t cmd;
840	const uint32_t *buf = *buffer;
841
842	while (buf < buf_end) {
843		cmd = *buf;
844		if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
845			break;
846		via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
847		buf++;
848	}
849	*buffer = buf;
850	return state_command;
851}
852
853static __inline__ verifier_state_t
854via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end)
855{
856	uint32_t data;
857	const uint32_t *buf = *buffer;
858
859	if (buf_end - buf < 4) {
860		DRM_ERROR("Illegal termination of video header5 command\n");
861		return state_error;
862	}
863
864	data = *buf++ & ~VIA_VIDEOMASK;
865	if (verify_mmio_address(data))
866		return state_error;
867
868	data = *buf++;
869	if (*buf++ != 0x00F50000) {
870		DRM_ERROR("Illegal header5 header data\n");
871		return state_error;
872	}
873	if (*buf++ != 0x00000000) {
874		DRM_ERROR("Illegal header5 header data\n");
875		return state_error;
876	}
877	if (eat_words(&buf, buf_end, data))
878		return state_error;
879	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
880		return state_error;
881	*buffer = buf;
882	return state_command;
883
884}
885
886static __inline__ verifier_state_t
887via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer,
888		   const uint32_t *buf_end)
889{
890	uint32_t addr, count, i;
891	const uint32_t *buf = *buffer;
892
893	addr = *buf++ & ~VIA_VIDEOMASK;
894	i = count = *buf;
895	buf += 3;
896	while (i--)
897		via_write(dev_priv, addr, *buf++);
898	if (count & 3)
899		buf += 4 - (count & 3);
900	*buffer = buf;
901	return state_command;
902}
903
904static __inline__ verifier_state_t
905via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end)
906{
907	uint32_t data;
908	const uint32_t *buf = *buffer;
909	uint32_t i;
910
911	if (buf_end - buf < 4) {
912		DRM_ERROR("Illegal termination of video header6 command\n");
913		return state_error;
914	}
915	buf++;
916	data = *buf++;
917	if (*buf++ != 0x00F60000) {
918		DRM_ERROR("Illegal header6 header data\n");
919		return state_error;
920	}
921	if (*buf++ != 0x00000000) {
922		DRM_ERROR("Illegal header6 header data\n");
923		return state_error;
924	}
925	if ((buf_end - buf) < (data << 1)) {
926		DRM_ERROR("Illegal termination of video header6 command\n");
927		return state_error;
928	}
929	for (i = 0; i < data; ++i) {
930		if (verify_mmio_address(*buf++))
931			return state_error;
932		buf++;
933	}
934	data <<= 1;
935	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
936		return state_error;
937	*buffer = buf;
938	return state_command;
939}
940
941static __inline__ verifier_state_t
942via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer,
943		   const uint32_t *buf_end)
944{
945
946	uint32_t addr, count, i;
947	const uint32_t *buf = *buffer;
948
949	i = count = *++buf;
950	buf += 3;
951	while (i--) {
952		addr = *buf++;
953		via_write(dev_priv, addr, *buf++);
954	}
955	count <<= 1;
956	if (count & 3)
957		buf += 4 - (count & 3);
958	*buffer = buf;
959	return state_command;
960}
961
962int
963via_verify_command_stream(const uint32_t * buf, unsigned int size,
964			  struct drm_device * dev, int agp)
965{
966
967	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
968	drm_via_state_t *hc_state = &dev_priv->hc_state;
969	drm_via_state_t saved_state = *hc_state;
970	uint32_t cmd;
971	const uint32_t *buf_end = buf + (size >> 2);
972	verifier_state_t state = state_command;
973	int cme_video;
974	int supported_3d;
975
976	cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
977		     dev_priv->chipset == VIA_DX9_0);
978
979	supported_3d = dev_priv->chipset != VIA_DX9_0;
980
981	hc_state->dev = dev;
982	hc_state->unfinished = no_sequence;
983	hc_state->map_cache = NULL;
984	hc_state->agp = agp;
985	hc_state->buf_start = buf;
986	dev_priv->num_fire_offsets = 0;
987
988	while (buf < buf_end) {
989
990		switch (state) {
991		case state_header2:
992			state = via_check_header2(&buf, buf_end, hc_state);
993			break;
994		case state_header1:
995			state = via_check_header1(&buf, buf_end);
996			break;
997		case state_vheader5:
998			state = via_check_vheader5(&buf, buf_end);
999			break;
1000		case state_vheader6:
1001			state = via_check_vheader6(&buf, buf_end);
1002			break;
1003		case state_command:
1004			if ((HALCYON_HEADER2 == (cmd = *buf)) &&
1005			    supported_3d)
1006				state = state_header2;
1007			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
1008				state = state_header1;
1009			else if (cme_video
1010				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
1011				state = state_vheader5;
1012			else if (cme_video
1013				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
1014				state = state_vheader6;
1015			else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
1016				DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
1017				state = state_error;
1018			} else {
1019				DRM_ERROR
1020				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
1021				     cmd);
1022				state = state_error;
1023			}
1024			break;
1025		case state_error:
1026		default:
1027			*hc_state = saved_state;
1028			return -EINVAL;
1029		}
1030	}
1031	if (state == state_error) {
1032		*hc_state = saved_state;
1033		return -EINVAL;
1034	}
1035	return 0;
1036}
1037
1038int
1039via_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
1040			 unsigned int size)
1041{
1042
1043	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
1044	uint32_t cmd;
1045	const uint32_t *buf_end = buf + (size >> 2);
1046	verifier_state_t state = state_command;
1047	int fire_count = 0;
1048
1049	while (buf < buf_end) {
1050
1051		switch (state) {
1052		case state_header2:
1053			state =
1054			    via_parse_header2(dev_priv, &buf, buf_end,
1055					      &fire_count);
1056			break;
1057		case state_header1:
1058			state = via_parse_header1(dev_priv, &buf, buf_end);
1059			break;
1060		case state_vheader5:
1061			state = via_parse_vheader5(dev_priv, &buf, buf_end);
1062			break;
1063		case state_vheader6:
1064			state = via_parse_vheader6(dev_priv, &buf, buf_end);
1065			break;
1066		case state_command:
1067			if (HALCYON_HEADER2 == (cmd = *buf))
1068				state = state_header2;
1069			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
1070				state = state_header1;
1071			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
1072				state = state_vheader5;
1073			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
1074				state = state_vheader6;
1075			else {
1076				DRM_ERROR
1077				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
1078				     cmd);
1079				state = state_error;
1080			}
1081			break;
1082		case state_error:
1083		default:
1084			return -EINVAL;
1085		}
1086	}
1087	if (state == state_error)
1088		return -EINVAL;
1089	return 0;
1090}
1091
1092static void
1093setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
1094{
1095	int i;
1096
1097	for (i = 0; i < 256; ++i)
1098		table[i] = forbidden_command;
1099
1100	for (i = 0; i < size; ++i)
1101		table[init_table[i].code] = init_table[i].hz;
1102}
1103
1104void via_init_command_verifier(void)
1105{
1106	setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1));
1107	setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2));
1108	setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3));
1109}
1110