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