via_verifier.c 27.6 KB
Newer Older
Dave Airlie's avatar
Dave Airlie committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
/*
 * Copyright 2004 The Unichrome Project. All Rights Reserved.
 * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Author: Thomas Hellstrom 2004, 2005.
 * This code was written using docs obtained under NDA from VIA Inc.
 *
 * Don't run this code directly on an AGP buffer. Due to cache problems it will
 * be very slow.
 */

#include "via_3d_reg.h"
#include "drmP.h"
#include "drm.h"
#include "via_drm.h"
#include "via_verifier.h"
#include "via_drv.h"

38
typedef enum {
Dave Airlie's avatar
Dave Airlie committed
39 40 41 42 43 44 45 46
	state_command,
	state_header2,
	state_header1,
	state_vheader5,
	state_vheader6,
	state_error
} verifier_state_t;

47
typedef enum {
Dave Airlie's avatar
Dave Airlie committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
	no_check = 0,
	check_for_header2,
	check_for_header1,
	check_for_header2_err,
	check_for_header1_err,
	check_for_fire,
	check_z_buffer_addr0,
	check_z_buffer_addr1,
	check_z_buffer_addr_mode,
	check_destination_addr0,
	check_destination_addr1,
	check_destination_addr_mode,
	check_for_dummy,
	check_for_dd,
	check_texture_addr0,
	check_texture_addr1,
	check_texture_addr2,
	check_texture_addr3,
	check_texture_addr4,
	check_texture_addr5,
	check_texture_addr6,
	check_texture_addr7,
	check_texture_addr8,
	check_texture_addr_mode,
	check_for_vertex_count,
	check_number_texunits,
	forbidden_command
75
} hazard_t;
Dave Airlie's avatar
Dave Airlie committed
76 77 78 79

/*
 * Associates each hazard above with a possible multi-command
 * sequence. For example an address that is split over multiple
80
 * commands and that needs to be checked at the first command
Dave Airlie's avatar
Dave Airlie committed
81 82 83
 * that does not include any part of the address.
 */

84
static drm_via_sequence_t seqs[] = {
Dave Airlie's avatar
Dave Airlie committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	no_sequence,
	no_sequence,
	no_sequence,
	no_sequence,
	no_sequence,
	no_sequence,
	z_address,
	z_address,
	z_address,
	dest_address,
	dest_address,
	dest_address,
	no_sequence,
	no_sequence,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	tex_address,
	no_sequence
};
111 112

typedef struct {
Dave Airlie's avatar
Dave Airlie committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
	unsigned int code;
	hazard_t hz;
} hz_init_t;

static hz_init_t init_table1[] = {
	{0xf2, check_for_header2_err},
	{0xf0, check_for_header1_err},
	{0xee, check_for_fire},
	{0xcc, check_for_dummy},
	{0xdd, check_for_dd},
	{0x00, no_check},
	{0x10, check_z_buffer_addr0},
	{0x11, check_z_buffer_addr1},
	{0x12, check_z_buffer_addr_mode},
	{0x13, no_check},
	{0x14, no_check},
	{0x15, no_check},
	{0x23, no_check},
	{0x24, no_check},
	{0x33, no_check},
	{0x34, no_check},
	{0x35, no_check},
	{0x36, no_check},
	{0x37, no_check},
	{0x38, no_check},
	{0x39, no_check},
	{0x3A, no_check},
	{0x3B, no_check},
	{0x3C, no_check},
	{0x3D, no_check},
	{0x3E, no_check},
	{0x40, check_destination_addr0},
	{0x41, check_destination_addr1},
	{0x42, check_destination_addr_mode},
	{0x43, no_check},
	{0x44, no_check},
	{0x50, no_check},
	{0x51, no_check},
	{0x52, no_check},
	{0x53, no_check},
	{0x54, no_check},
	{0x55, no_check},
	{0x56, no_check},
	{0x57, no_check},
	{0x58, no_check},
	{0x70, no_check},
	{0x71, no_check},
	{0x78, no_check},
	{0x79, no_check},
	{0x7A, no_check},
	{0x7B, no_check},
	{0x7C, no_check},
	{0x7D, check_for_vertex_count}
};

static hz_init_t init_table2[] = {
	{0xf2, check_for_header2_err},
	{0xf0, check_for_header1_err},
	{0xee, check_for_fire},
	{0xcc, check_for_dummy},
	{0x00, check_texture_addr0},
	{0x01, check_texture_addr0},
	{0x02, check_texture_addr0},
	{0x03, check_texture_addr0},
	{0x04, check_texture_addr0},
	{0x05, check_texture_addr0},
	{0x06, check_texture_addr0},
	{0x07, check_texture_addr0},
	{0x08, check_texture_addr0},
	{0x09, check_texture_addr0},
	{0x20, check_texture_addr1},
	{0x21, check_texture_addr1},
	{0x22, check_texture_addr1},
	{0x23, check_texture_addr4},
	{0x2B, check_texture_addr3},
	{0x2C, check_texture_addr3},
	{0x2D, check_texture_addr3},
	{0x2E, check_texture_addr3},
	{0x2F, check_texture_addr3},
	{0x30, check_texture_addr3},
	{0x31, check_texture_addr3},
	{0x32, check_texture_addr3},
	{0x33, check_texture_addr3},
	{0x34, check_texture_addr3},
	{0x4B, check_texture_addr5},
	{0x4C, check_texture_addr6},
	{0x51, check_texture_addr7},
	{0x52, check_texture_addr8},
	{0x77, check_texture_addr2},
	{0x78, no_check},
	{0x79, no_check},
	{0x7A, no_check},
	{0x7B, check_texture_addr_mode},
	{0x7C, no_check},
	{0x7D, no_check},
	{0x7E, no_check},
	{0x7F, no_check},
	{0x80, no_check},
	{0x81, no_check},
	{0x82, no_check},
	{0x83, no_check},
	{0x85, no_check},
	{0x86, no_check},
	{0x87, no_check},
	{0x88, no_check},
	{0x89, no_check},
	{0x8A, no_check},
	{0x90, no_check},
	{0x91, no_check},
	{0x92, no_check},
	{0x93, no_check}
};

static hz_init_t init_table3[] = {
	{0xf2, check_for_header2_err},
	{0xf0, check_for_header1_err},
	{0xcc, check_for_dummy},
	{0x00, check_number_texunits}
};

233 234 235
static hazard_t table1[256];
static hazard_t table2[256];
static hazard_t table3[256];
Dave Airlie's avatar
Dave Airlie committed
236 237

static __inline__ int
238
eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words)
Dave Airlie's avatar
Dave Airlie committed
239
{
240
	if ((buf_end - *buf) >= num_words) {
Dave Airlie's avatar
Dave Airlie committed
241 242
		*buf += num_words;
		return 0;
243
	}
Dave Airlie's avatar
Dave Airlie committed
244 245 246 247 248 249 250 251
	DRM_ERROR("Illegal termination of DMA command buffer\n");
	return 1;
}

/*
 * Partially stolen from drm_memory.h
 */

252
static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
253 254
						    unsigned long offset,
						    unsigned long size,
255
						    struct drm_device * dev)
Dave Airlie's avatar
Dave Airlie committed
256
{
257
	struct drm_map_list *r_list;
258
	drm_local_map_t *map = seq->map_cache;
Dave Airlie's avatar
Dave Airlie committed
259

260 261
	if (map && map->offset <= offset
	    && (offset + size) <= (map->offset + map->size)) {
Dave Airlie's avatar
Dave Airlie committed
262 263
		return map;
	}
264

265
	list_for_each_entry(r_list, &dev->maplist, head) {
Dave Airlie's avatar
Dave Airlie committed
266 267 268
		map = r_list->map;
		if (!map)
			continue;
269 270 271 272
		if (map->offset <= offset
		    && (offset + size) <= (map->offset + map->size)
		    && !(map->flags & _DRM_RESTRICTED)
		    && (map->type == _DRM_AGP)) {
Dave Airlie's avatar
Dave Airlie committed
273 274 275 276 277 278 279 280
			seq->map_cache = map;
			return map;
		}
	}
	return NULL;
}

/*
281
 * Require that all AGP texture levels reside in the same AGP map which should
Dave Airlie's avatar
Dave Airlie committed
282
 * be mappable by the client. This is not a big restriction.
283 284
 * FIXME: To actually enforce this security policy strictly, drm_rmmap
 * would have to wait for dma quiescent before removing an AGP map.
Dave Airlie's avatar
Dave Airlie committed
285 286 287 288
 * The via_drm_lookup_agp_map call in reality seems to take
 * very little CPU time.
 */

289
static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
Dave Airlie's avatar
Dave Airlie committed
290
{
291
	switch (cur_seq->unfinished) {
Dave Airlie's avatar
Dave Airlie committed
292 293 294 295
	case z_address:
		DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
		break;
	case dest_address:
296 297
		DRM_DEBUG("Destination start address is 0x%x\n",
			  cur_seq->d_addr);
Dave Airlie's avatar
Dave Airlie committed
298 299
		break;
	case tex_address:
300 301 302
		if (cur_seq->agp_texture) {
			unsigned start =
			    cur_seq->tex_level_lo[cur_seq->texture];
Dave Airlie's avatar
Dave Airlie committed
303
			unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
304
			unsigned long lo = ~0, hi = 0, tmp;
Dave Airlie's avatar
Dave Airlie committed
305 306
			uint32_t *addr, *pitch, *height, tex;
			unsigned i;
307
			int npot;
Dave Airlie's avatar
Dave Airlie committed
308

309 310 311 312
			if (end > 9)
				end = 9;
			if (start > 9)
				start = 9;
Dave Airlie's avatar
Dave Airlie committed
313

314 315
			addr =
			    &(cur_seq->t_addr[tex = cur_seq->texture][start]);
Dave Airlie's avatar
Dave Airlie committed
316 317
			pitch = &(cur_seq->pitch[tex][start]);
			height = &(cur_seq->height[tex][start]);
318
			npot = cur_seq->tex_npot[tex];
319
			for (i = start; i <= end; ++i) {
Dave Airlie's avatar
Dave Airlie committed
320
				tmp = *addr++;
321 322
				if (tmp < lo)
					lo = tmp;
323 324 325 326
				if (i == 0 && npot)
					tmp += (*height++ * *pitch++);
				else
					tmp += (*height++ << *pitch++);
327 328
				if (tmp > hi)
					hi = tmp;
Dave Airlie's avatar
Dave Airlie committed
329 330
			}

331 332 333 334
			if (!via_drm_lookup_agp_map
			    (cur_seq, lo, hi - lo, cur_seq->dev)) {
				DRM_ERROR
				    ("AGP texture is not in allowed map\n");
Dave Airlie's avatar
Dave Airlie committed
335 336
				return 2;
			}
337
		}
Dave Airlie's avatar
Dave Airlie committed
338 339 340 341 342 343 344 345
		break;
	default:
		break;
	}
	cur_seq->unfinished = no_sequence;
	return 0;
}

346 347
static __inline__ int
investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
Dave Airlie's avatar
Dave Airlie committed
348 349 350 351 352
{
	register uint32_t tmp, *tmp_addr;

	if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
		int ret;
353 354
		if ((ret = finish_current_sequence(cur_seq)))
			return ret;
Dave Airlie's avatar
Dave Airlie committed
355 356
	}

357
	switch (hz) {
Dave Airlie's avatar
Dave Airlie committed
358
	case check_for_header2:
359 360
		if (cmd == HALCYON_HEADER2)
			return 1;
Dave Airlie's avatar
Dave Airlie committed
361 362
		return 0;
	case check_for_header1:
363 364
		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
			return 1;
Dave Airlie's avatar
Dave Airlie committed
365 366
		return 0;
	case check_for_header2_err:
367 368
		if (cmd == HALCYON_HEADER2)
			return 1;
Dave Airlie's avatar
Dave Airlie committed
369 370 371
		DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
		break;
	case check_for_header1_err:
372 373
		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
			return 1;
Dave Airlie's avatar
Dave Airlie committed
374 375 376
		DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
		break;
	case check_for_fire:
377 378
		if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD)
			return 1;
Dave Airlie's avatar
Dave Airlie committed
379 380 381
		DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
		break;
	case check_for_dummy:
382 383
		if (HC_DUMMY == cmd)
			return 0;
Dave Airlie's avatar
Dave Airlie committed
384 385 386
		DRM_ERROR("Illegal DMA HC_DUMMY command\n");
		break;
	case check_for_dd:
387 388
		if (0xdddddddd == cmd)
			return 0;
Dave Airlie's avatar
Dave Airlie committed
389 390 391 392 393
		DRM_ERROR("Illegal DMA 0xdddddddd command\n");
		break;
	case check_z_buffer_addr0:
		cur_seq->unfinished = z_address;
		cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
394
		    (cmd & 0x00FFFFFF);
Dave Airlie's avatar
Dave Airlie committed
395 396 397 398
		return 0;
	case check_z_buffer_addr1:
		cur_seq->unfinished = z_address;
		cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
399
		    ((cmd & 0xFF) << 24);
Dave Airlie's avatar
Dave Airlie committed
400 401 402
		return 0;
	case check_z_buffer_addr_mode:
		cur_seq->unfinished = z_address;
403 404
		if ((cmd & 0x0000C000) == 0)
			return 0;
Dave Airlie's avatar
Dave Airlie committed
405 406 407 408 409
		DRM_ERROR("Attempt to place Z buffer in system memory\n");
		return 2;
	case check_destination_addr0:
		cur_seq->unfinished = dest_address;
		cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
410
		    (cmd & 0x00FFFFFF);
Dave Airlie's avatar
Dave Airlie committed
411 412 413 414
		return 0;
	case check_destination_addr1:
		cur_seq->unfinished = dest_address;
		cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
415
		    ((cmd & 0xFF) << 24);
Dave Airlie's avatar
Dave Airlie committed
416 417 418
		return 0;
	case check_destination_addr_mode:
		cur_seq->unfinished = dest_address;
419 420 421 422 423
		if ((cmd & 0x0000C000) == 0)
			return 0;
		DRM_ERROR
		    ("Attempt to place 3D drawing buffer in system memory\n");
		return 2;
Dave Airlie's avatar
Dave Airlie committed
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	case check_texture_addr0:
		cur_seq->unfinished = tex_address;
		tmp = (cmd >> 24);
		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
		*tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
		return 0;
	case check_texture_addr1:
		cur_seq->unfinished = tex_address;
		tmp = ((cmd >> 24) - 0x20);
		tmp += tmp << 1;
		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
		tmp_addr++;
		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
		tmp_addr++;
		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
		return 0;
	case check_texture_addr2:
		cur_seq->unfinished = tex_address;
		cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
		cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
		return 0;
	case check_texture_addr3:
		cur_seq->unfinished = tex_address;
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
		tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
		if (tmp == 0 &&
		    (cmd & HC_HTXnEnPit_MASK)) {
			cur_seq->pitch[cur_seq->texture][tmp] =
				(cmd & HC_HTXnLnPit_MASK);
			cur_seq->tex_npot[cur_seq->texture] = 1;
		} else {
			cur_seq->pitch[cur_seq->texture][tmp] =
				(cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
			cur_seq->tex_npot[cur_seq->texture] = 0;
			if (cmd & 0x000FFFFF) {
				DRM_ERROR
					("Unimplemented texture level 0 pitch mode.\n");
				return 2;
			}
Dave Airlie's avatar
Dave Airlie committed
463 464 465 466 467 468 469 470 471 472 473 474
		}
		return 0;
	case check_texture_addr4:
		cur_seq->unfinished = tex_address;
		tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
		return 0;
	case check_texture_addr5:
	case check_texture_addr6:
		cur_seq->unfinished = tex_address;
		/*
		 * Texture width. We don't care since we have the pitch.
475
		 */
Dave Airlie's avatar
Dave Airlie committed
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
		return 0;
	case check_texture_addr7:
		cur_seq->unfinished = tex_address;
		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
		tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
		tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
		tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
		tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
		tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
		tmp_addr[0] = 1 << (cmd & 0x0000000F);
		return 0;
	case check_texture_addr8:
		cur_seq->unfinished = tex_address;
		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
		tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
491
		tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
Dave Airlie's avatar
Dave Airlie committed
492 493 494 495 496
		tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
		tmp_addr[6] = 1 << (cmd & 0x0000000F);
		return 0;
	case check_texture_addr_mode:
		cur_seq->unfinished = tex_address;
497 498 499
		if (2 == (tmp = cmd & 0x00000003)) {
			DRM_ERROR
			    ("Attempt to fetch texture from system memory.\n");
Dave Airlie's avatar
Dave Airlie committed
500 501 502
			return 2;
		}
		cur_seq->agp_texture = (tmp == 3);
503 504
		cur_seq->tex_palette_size[cur_seq->texture] =
		    (cmd >> 16) & 0x000000007;
Dave Airlie's avatar
Dave Airlie committed
505 506 507 508 509
		return 0;
	case check_for_vertex_count:
		cur_seq->vertex_count = cmd & 0x0000FFFF;
		return 0;
	case check_number_texunits:
510
		cur_seq->multitex = (cmd >> 3) & 1;
Dave Airlie's avatar
Dave Airlie committed
511 512 513 514 515 516 517 518 519
		return 0;
	default:
		DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
		return 2;
	}
	return 2;
}

static __inline__ int
520 521
via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
		    drm_via_state_t * cur_seq)
Dave Airlie's avatar
Dave Airlie committed
522
{
523 524 525
	drm_via_private_t *dev_priv =
	    (drm_via_private_t *) cur_seq->dev->dev_private;
	uint32_t a_fire, bcmd, dw_count;
Dave Airlie's avatar
Dave Airlie committed
526 527 528 529
	int ret = 0;
	int have_fire;
	const uint32_t *buf = *buffer;

530 531
	while (buf < buf_end) {
		have_fire = 0;
Dave Airlie's avatar
Dave Airlie committed
532
		if ((buf_end - buf) < 2) {
533 534
			DRM_ERROR
			    ("Unexpected termination of primitive list.\n");
Dave Airlie's avatar
Dave Airlie committed
535 536 537
			ret = 1;
			break;
		}
538 539
		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB)
			break;
Dave Airlie's avatar
Dave Airlie committed
540 541 542 543 544 545 546
		bcmd = *buf++;
		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
			DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
				  *buf);
			ret = 1;
			break;
		}
547 548 549 550
		a_fire =
		    *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK |
		    HC_HE3Fire_MASK;

Dave Airlie's avatar
Dave Airlie committed
551 552
		/*
		 * How many dwords per vertex ?
553 554
		 */

Dave Airlie's avatar
Dave Airlie committed
555 556 557 558
		if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
			DRM_ERROR("Illegal B command vertex data for AGP.\n");
			ret = 1;
			break;
559
		}
Dave Airlie's avatar
Dave Airlie committed
560 561

		dw_count = 0;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
		if (bcmd & (1 << 7))
			dw_count += (cur_seq->multitex) ? 2 : 1;
		if (bcmd & (1 << 8))
			dw_count += (cur_seq->multitex) ? 2 : 1;
		if (bcmd & (1 << 9))
			dw_count++;
		if (bcmd & (1 << 10))
			dw_count++;
		if (bcmd & (1 << 11))
			dw_count++;
		if (bcmd & (1 << 12))
			dw_count++;
		if (bcmd & (1 << 13))
			dw_count++;
		if (bcmd & (1 << 14))
			dw_count++;

		while (buf < buf_end) {
Dave Airlie's avatar
Dave Airlie committed
580
			if (*buf == a_fire) {
581 582
				if (dev_priv->num_fire_offsets >=
				    VIA_FIRE_BUF_SIZE) {
Dave Airlie's avatar
Dave Airlie committed
583 584 585 586
					DRM_ERROR("Fire offset buffer full.\n");
					ret = 1;
					break;
				}
587 588 589 590
				dev_priv->fire_offsets[dev_priv->
						       num_fire_offsets++] =
				    buf;
				have_fire = 1;
Dave Airlie's avatar
Dave Airlie committed
591
				buf++;
592
				if (buf < buf_end && *buf == a_fire)
Dave Airlie's avatar
Dave Airlie committed
593 594 595
					buf++;
				break;
			}
596
			if ((*buf == HALCYON_HEADER2) ||
Dave Airlie's avatar
Dave Airlie committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
			    ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
				DRM_ERROR("Missing Vertex Fire command, "
					  "Stray Vertex Fire command  or verifier "
					  "lost sync.\n");
				ret = 1;
				break;
			}
			if ((ret = eat_words(&buf, buf_end, dw_count)))
				break;
		}
		if (buf >= buf_end && !have_fire) {
			DRM_ERROR("Missing Vertex Fire command or verifier "
				  "lost sync.\n");
			ret = 1;
			break;
		}
		if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
			DRM_ERROR("AGP Primitive list end misaligned.\n");
			ret = 1;
			break;
		}
618
	}
Dave Airlie's avatar
Dave Airlie committed
619 620 621 622 623
	*buffer = buf;
	return ret;
}

static __inline__ verifier_state_t
624 625
via_check_header2(uint32_t const **buffer, const uint32_t * buf_end,
		  drm_via_state_t * hc_state)
Dave Airlie's avatar
Dave Airlie committed
626 627 628 629 630 631 632 633
{
	uint32_t cmd;
	int hz_mode;
	hazard_t hz;
	const uint32_t *buf = *buffer;
	const hazard_t *hz_table;

	if ((buf_end - buf) < 2) {
634 635
		DRM_ERROR
		    ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
Dave Airlie's avatar
Dave Airlie committed
636 637 638 639 640
		return state_error;
	}
	buf++;
	cmd = (*buf++ & 0xFFFF0000) >> 16;

641
	switch (cmd) {
Dave Airlie's avatar
Dave Airlie committed
642
	case HC_ParaType_CmdVdata:
643
		if (via_check_prim_list(&buf, buf_end, hc_state))
Dave Airlie's avatar
Dave Airlie committed
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
			return state_error;
		*buffer = buf;
		return state_command;
	case HC_ParaType_NotTex:
		hz_table = table1;
		break;
	case HC_ParaType_Tex:
		hc_state->texture = 0;
		hz_table = table2;
		break;
	case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
		hc_state->texture = 1;
		hz_table = table2;
		break;
	case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
		hz_table = table3;
		break;
	case HC_ParaType_Auto:
		if (eat_words(&buf, buf_end, 2))
			return state_error;
		*buffer = buf;
		return state_command;
	case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
		if (eat_words(&buf, buf_end, 32))
			return state_error;
		*buffer = buf;
		return state_command;
	case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
	case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
		DRM_ERROR("Texture palettes are rejected because of "
			  "lack of info how to determine their size.\n");
		return state_error;
	case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
		DRM_ERROR("Fog factor palettes are rejected because of "
			  "lack of info how to determine their size.\n");
		return state_error;
	default:

		/*
		 * There are some unimplemented HC_ParaTypes here, that
		 * need to be implemented if the Mesa driver is extended.
		 */

		DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
688 689
			  "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
			  cmd, *(buf - 2));
Dave Airlie's avatar
Dave Airlie committed
690 691 692 693
		*buffer = buf;
		return state_error;
	}

694
	while (buf < buf_end) {
Dave Airlie's avatar
Dave Airlie committed
695 696 697 698 699 700 701 702 703
		cmd = *buf++;
		if ((hz = hz_table[cmd >> 24])) {
			if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
				if (hz_mode == 1) {
					buf--;
					break;
				}
				return state_error;
			}
704
		} else if (hc_state->unfinished &&
Dave Airlie's avatar
Dave Airlie committed
705 706 707 708 709 710 711 712 713 714 715 716
			   finish_current_sequence(hc_state)) {
			return state_error;
		}
	}
	if (hc_state->unfinished && finish_current_sequence(hc_state)) {
		return state_error;
	}
	*buffer = buf;
	return state_command;
}

static __inline__ verifier_state_t
717 718
via_parse_header2(drm_via_private_t * dev_priv, uint32_t const **buffer,
		  const uint32_t * buf_end, int *fire_count)
Dave Airlie's avatar
Dave Airlie committed
719 720 721
{
	uint32_t cmd;
	const uint32_t *buf = *buffer;
722
	const uint32_t *next_fire;
Dave Airlie's avatar
Dave Airlie committed
723 724 725 726 727 728
	int burst = 0;

	next_fire = dev_priv->fire_offsets[*fire_count];
	buf++;
	cmd = (*buf & 0xFFFF0000) >> 16;
	VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
729
	switch (cmd) {
Dave Airlie's avatar
Dave Airlie committed
730 731
	case HC_ParaType_CmdVdata:
		while ((buf < buf_end) &&
732 733 734 735 736
		       (*fire_count < dev_priv->num_fire_offsets) &&
		       (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) {
			while (buf <= next_fire) {
				VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE +
					  (burst & 63), *buf++);
Dave Airlie's avatar
Dave Airlie committed
737 738
				burst += 4;
			}
739 740
			if ((buf < buf_end)
			    && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
Dave Airlie's avatar
Dave Airlie committed
741 742
				buf++;

743
			if (++(*fire_count) < dev_priv->num_fire_offsets)
Dave Airlie's avatar
Dave Airlie committed
744 745 746 747
				next_fire = dev_priv->fire_offsets[*fire_count];
		}
		break;
	default:
748 749 750 751 752 753 754 755 756 757 758
		while (buf < buf_end) {

			if (*buf == HC_HEADER2 ||
			    (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
			    (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
			    (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
				break;

			VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE +
				  (burst & 63), *buf++);
			burst += 4;
Dave Airlie's avatar
Dave Airlie committed
759 760 761 762 763 764
		}
	}
	*buffer = buf;
	return state_command;
}

765
static __inline__ int verify_mmio_address(uint32_t address)
Dave Airlie's avatar
Dave Airlie committed
766
{
767
	if ((address > 0x3FF) && (address < 0xC00)) {
Dave Airlie's avatar
Dave Airlie committed
768 769 770 771 772 773
		DRM_ERROR("Invalid VIDEO DMA command. "
			  "Attempt to access 3D- or command burst area.\n");
		return 1;
	} else if ((address > 0xCFF) && (address < 0x1300)) {
		DRM_ERROR("Invalid VIDEO DMA command. "
			  "Attempt to access PCI DMA area.\n");
774 775
		return 1;
	} else if (address > 0x13FF) {
Dave Airlie's avatar
Dave Airlie committed
776 777 778 779 780 781 782 783
		DRM_ERROR("Invalid VIDEO DMA command. "
			  "Attempt to access VGA registers.\n");
		return 1;
	}
	return 0;
}

static __inline__ int
784 785
verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end,
		  uint32_t dwords)
Dave Airlie's avatar
Dave Airlie committed
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
{
	const uint32_t *buf = *buffer;

	if (buf_end - buf < dwords) {
		DRM_ERROR("Illegal termination of video command.\n");
		return 1;
	}
	while (dwords--) {
		if (*buf++) {
			DRM_ERROR("Illegal video command tail.\n");
			return 1;
		}
	}
	*buffer = buf;
	return 0;
}

static __inline__ verifier_state_t
804
via_check_header1(uint32_t const **buffer, const uint32_t * buf_end)
Dave Airlie's avatar
Dave Airlie committed
805 806 807 808 809 810 811 812
{
	uint32_t cmd;
	const uint32_t *buf = *buffer;
	verifier_state_t ret = state_command;

	while (buf < buf_end) {
		cmd = *buf;
		if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
813 814
		    (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {
			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
Dave Airlie's avatar
Dave Airlie committed
815 816 817 818 819 820
				break;
			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
				  "Attempt to access 3D- or command burst area.\n");
			ret = state_error;
			break;
		} else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
821
			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
Dave Airlie's avatar
Dave Airlie committed
822 823 824 825
				break;
			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
				  "Attempt to access VGA registers.\n");
			ret = state_error;
826 827
			break;
		} else {
Dave Airlie's avatar
Dave Airlie committed
828 829 830 831 832 833 834 835
			buf += 2;
		}
	}
	*buffer = buf;
	return ret;
}

static __inline__ verifier_state_t
836 837
via_parse_header1(drm_via_private_t * dev_priv, uint32_t const **buffer,
		  const uint32_t * buf_end)
Dave Airlie's avatar
Dave Airlie committed
838 839 840 841 842 843
{
	register uint32_t cmd;
	const uint32_t *buf = *buffer;

	while (buf < buf_end) {
		cmd = *buf;
844 845 846
		if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
			break;
		VIA_WRITE((cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
Dave Airlie's avatar
Dave Airlie committed
847 848 849 850 851 852 853
		buf++;
	}
	*buffer = buf;
	return state_command;
}

static __inline__ verifier_state_t
854
via_check_vheader5(uint32_t const **buffer, const uint32_t * buf_end)
Dave Airlie's avatar
Dave Airlie committed
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
{
	uint32_t data;
	const uint32_t *buf = *buffer;

	if (buf_end - buf < 4) {
		DRM_ERROR("Illegal termination of video header5 command\n");
		return state_error;
	}

	data = *buf++ & ~VIA_VIDEOMASK;
	if (verify_mmio_address(data))
		return state_error;

	data = *buf++;
	if (*buf++ != 0x00F50000) {
		DRM_ERROR("Illegal header5 header data\n");
		return state_error;
	}
	if (*buf++ != 0x00000000) {
		DRM_ERROR("Illegal header5 header data\n");
		return state_error;
	}
877
	if (eat_words(&buf, buf_end, data))
Dave Airlie's avatar
Dave Airlie committed
878
		return state_error;
879
	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
Dave Airlie's avatar
Dave Airlie committed
880 881 882
		return state_error;
	*buffer = buf;
	return state_command;
883 884

}
Dave Airlie's avatar
Dave Airlie committed
885 886

static __inline__ verifier_state_t
887 888
via_parse_vheader5(drm_via_private_t * dev_priv, uint32_t const **buffer,
		   const uint32_t * buf_end)
Dave Airlie's avatar
Dave Airlie committed
889
{
890
	uint32_t addr, count, i;
Dave Airlie's avatar
Dave Airlie committed
891
	const uint32_t *buf = *buffer;
892

Dave Airlie's avatar
Dave Airlie committed
893 894 895
	addr = *buf++ & ~VIA_VIDEOMASK;
	i = count = *buf;
	buf += 3;
896
	while (i--) {
Dave Airlie's avatar
Dave Airlie committed
897 898
		VIA_WRITE(addr, *buf++);
	}
899 900
	if (count & 3)
		buf += 4 - (count & 3);
Dave Airlie's avatar
Dave Airlie committed
901
	*buffer = buf;
902 903
	return state_command;
}
Dave Airlie's avatar
Dave Airlie committed
904 905

static __inline__ verifier_state_t
906
via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end)
Dave Airlie's avatar
Dave Airlie committed
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
{
	uint32_t data;
	const uint32_t *buf = *buffer;
	uint32_t i;

	if (buf_end - buf < 4) {
		DRM_ERROR("Illegal termination of video header6 command\n");
		return state_error;
	}
	buf++;
	data = *buf++;
	if (*buf++ != 0x00F60000) {
		DRM_ERROR("Illegal header6 header data\n");
		return state_error;
	}
	if (*buf++ != 0x00000000) {
		DRM_ERROR("Illegal header6 header data\n");
		return state_error;
	}
	if ((buf_end - buf) < (data << 1)) {
		DRM_ERROR("Illegal termination of video header6 command\n");
		return state_error;
	}
930
	for (i = 0; i < data; ++i) {
Dave Airlie's avatar
Dave Airlie committed
931 932 933 934 935 936 937 938 939
		if (verify_mmio_address(*buf++))
			return state_error;
		buf++;
	}
	data <<= 1;
	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
		return state_error;
	*buffer = buf;
	return state_command;
940
}
Dave Airlie's avatar
Dave Airlie committed
941 942

static __inline__ verifier_state_t
943 944
via_parse_vheader6(drm_via_private_t * dev_priv, uint32_t const **buffer,
		   const uint32_t * buf_end)
Dave Airlie's avatar
Dave Airlie committed
945 946
{

947
	uint32_t addr, count, i;
Dave Airlie's avatar
Dave Airlie committed
948 949 950 951
	const uint32_t *buf = *buffer;

	i = count = *++buf;
	buf += 3;
952
	while (i--) {
Dave Airlie's avatar
Dave Airlie committed
953 954 955 956
		addr = *buf++;
		VIA_WRITE(addr, *buf++);
	}
	count <<= 1;
957 958
	if (count & 3)
		buf += 4 - (count & 3);
Dave Airlie's avatar
Dave Airlie committed
959 960
	*buffer = buf;
	return state_command;
961
}
Dave Airlie's avatar
Dave Airlie committed
962

963 964
int
via_verify_command_stream(const uint32_t * buf, unsigned int size,
965
			  struct drm_device * dev, int agp)
Dave Airlie's avatar
Dave Airlie committed
966 967 968 969 970 971
{

	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
	drm_via_state_t *hc_state = &dev_priv->hc_state;
	drm_via_state_t saved_state = *hc_state;
	uint32_t cmd;
972
	const uint32_t *buf_end = buf + (size >> 2);
Dave Airlie's avatar
Dave Airlie committed
973
	verifier_state_t state = state_command;
974 975 976 977 978 979 980
	int cme_video;
	int supported_3d;

	cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
		     dev_priv->chipset == VIA_DX9_0);

	supported_3d = dev_priv->chipset != VIA_DX9_0;
981

Dave Airlie's avatar
Dave Airlie committed
982 983 984 985 986 987 988 989 990 991 992
	hc_state->dev = dev;
	hc_state->unfinished = no_sequence;
	hc_state->map_cache = NULL;
	hc_state->agp = agp;
	hc_state->buf_start = buf;
	dev_priv->num_fire_offsets = 0;

	while (buf < buf_end) {

		switch (state) {
		case state_header2:
993
			state = via_check_header2(&buf, buf_end, hc_state);
Dave Airlie's avatar
Dave Airlie committed
994 995
			break;
		case state_header1:
996
			state = via_check_header1(&buf, buf_end);
Dave Airlie's avatar
Dave Airlie committed
997 998
			break;
		case state_vheader5:
999
			state = via_check_vheader5(&buf, buf_end);
Dave Airlie's avatar
Dave Airlie committed
1000 1001
			break;
		case state_vheader6:
1002
			state = via_check_vheader6(&buf, buf_end);
Dave Airlie's avatar
Dave Airlie committed
1003 1004
			break;
		case state_command:
1005 1006
			if ((HALCYON_HEADER2 == (cmd = *buf)) &&
			    supported_3d)
Dave Airlie's avatar
Dave Airlie committed
1007
				state = state_header2;
1008
			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
Dave Airlie's avatar
Dave Airlie committed
1009
				state = state_header1;
1010
			else if (cme_video
1011
				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
Dave Airlie's avatar
Dave Airlie committed
1012
				state = state_vheader5;
1013
			else if (cme_video
1014
				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
Dave Airlie's avatar
Dave Airlie committed
1015
				state = state_vheader6;
1016 1017 1018 1019
			else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
				DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
				state = state_error;
			} else {
1020 1021 1022
				DRM_ERROR
				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
				     cmd);
Dave Airlie's avatar
Dave Airlie committed
1023 1024 1025 1026 1027 1028
				state = state_error;
			}
			break;
		case state_error:
		default:
			*hc_state = saved_state;
Eric Anholt's avatar
Eric Anholt committed
1029
			return -EINVAL;
Dave Airlie's avatar
Dave Airlie committed
1030
		}
1031
	}
Dave Airlie's avatar
Dave Airlie committed
1032 1033
	if (state == state_error) {
		*hc_state = saved_state;
Eric Anholt's avatar
Eric Anholt committed
1034
		return -EINVAL;
Dave Airlie's avatar
Dave Airlie committed
1035 1036 1037 1038
	}
	return 0;
}

1039
int
1040
via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
1041
			 unsigned int size)
Dave Airlie's avatar
Dave Airlie committed
1042 1043 1044 1045
{

	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
	uint32_t cmd;
1046
	const uint32_t *buf_end = buf + (size >> 2);
Dave Airlie's avatar
Dave Airlie committed
1047 1048
	verifier_state_t state = state_command;
	int fire_count = 0;
1049

Dave Airlie's avatar
Dave Airlie committed
1050 1051 1052 1053
	while (buf < buf_end) {

		switch (state) {
		case state_header2:
1054 1055 1056
			state =
			    via_parse_header2(dev_priv, &buf, buf_end,
					      &fire_count);
Dave Airlie's avatar
Dave Airlie committed
1057 1058
			break;
		case state_header1:
1059
			state = via_parse_header1(dev_priv, &buf, buf_end);
Dave Airlie's avatar
Dave Airlie committed
1060 1061
			break;
		case state_vheader5:
1062
			state = via_parse_vheader5(dev_priv, &buf, buf_end);
Dave Airlie's avatar
Dave Airlie committed
1063 1064
			break;
		case state_vheader6:
1065
			state = via_parse_vheader6(dev_priv, &buf, buf_end);
Dave Airlie's avatar
Dave Airlie committed
1066 1067
			break;
		case state_command:
1068
			if (HALCYON_HEADER2 == (cmd = *buf))
Dave Airlie's avatar
Dave Airlie committed
1069
				state = state_header2;
1070
			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
Dave Airlie's avatar
Dave Airlie committed
1071 1072 1073 1074 1075 1076
				state = state_header1;
			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
				state = state_vheader5;
			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
				state = state_vheader6;
			else {
1077 1078 1079
				DRM_ERROR
				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
				     cmd);
Dave Airlie's avatar
Dave Airlie committed
1080 1081 1082 1083 1084
				state = state_error;
			}
			break;
		case state_error:
		default:
Eric Anholt's avatar
Eric Anholt committed
1085
			return -EINVAL;
Dave Airlie's avatar
Dave Airlie committed
1086
		}
1087
	}
Dave Airlie's avatar
Dave Airlie committed
1088
	if (state == state_error) {
Eric Anholt's avatar
Eric Anholt committed
1089
		return -EINVAL;
Dave Airlie's avatar
Dave Airlie committed
1090 1091 1092 1093
	}
	return 0;
}

1094
static void
Dave Airlie's avatar
Dave Airlie committed
1095 1096 1097 1098
setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
{
	int i;

1099
	for (i = 0; i < 256; ++i) {
Dave Airlie's avatar
Dave Airlie committed
1100 1101 1102
		table[i] = forbidden_command;
	}

1103
	for (i = 0; i < size; ++i) {
Dave Airlie's avatar
Dave Airlie committed
1104 1105 1106 1107
		table[init_table[i].code] = init_table[i].hz;
	}
}

1108
void via_init_command_verifier(void)
Dave Airlie's avatar
Dave Airlie committed
1109
{
1110 1111 1112 1113 1114 1115
	setup_hazard_table(init_table1, table1,
			   sizeof(init_table1) / sizeof(hz_init_t));
	setup_hazard_table(init_table2, table2,
			   sizeof(init_table2) / sizeof(hz_init_t));
	setup_hazard_table(init_table3, table3,
			   sizeof(init_table3) / sizeof(hz_init_t));
Dave Airlie's avatar
Dave Airlie committed
1116
}