2 * Copyright 2004 The Unichrome Project. All Rights Reserved.
3 * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
24 * Author: Thomas Hellstrom 2004, 2005.
25 * This code was written using docs obtained under NDA from VIA Inc.
27 * Don't run this code directly on an AGP buffer. Due to cache problems it will
32 #include "via_3d_reg.h"
36 #include "via_verifier.h"
53 check_for_header2_err
,
54 check_for_header1_err
,
58 check_z_buffer_addr_mode
,
59 check_destination_addr0
,
60 check_destination_addr1
,
61 check_destination_addr_mode
,
73 check_texture_addr_mode
,
74 check_for_vertex_count
,
75 check_number_texunits
,
80 * Associates each hazard above with a possible multi-command
81 * sequence. For example an address that is split over multiple
82 * commands and that needs to be checked at the first command
83 * that does not include any part of the address.
86 static drm_via_sequence_t seqs
[] = {
121 static hz_init_t init_table1
[] = {
122 {0xf2, check_for_header2_err
},
123 {0xf0, check_for_header1_err
},
124 {0xee, check_for_fire
},
125 {0xcc, check_for_dummy
},
126 {0xdd, check_for_dd
},
128 {0x10, check_z_buffer_addr0
},
129 {0x11, check_z_buffer_addr1
},
130 {0x12, check_z_buffer_addr_mode
},
148 {0x40, check_destination_addr0
},
149 {0x41, check_destination_addr1
},
150 {0x42, check_destination_addr_mode
},
169 {0x7D, check_for_vertex_count
}
174 static hz_init_t init_table2
[] = {
175 {0xf2, check_for_header2_err
},
176 {0xf0, check_for_header1_err
},
177 {0xee, check_for_fire
},
178 {0xcc, check_for_dummy
},
179 {0x00, check_texture_addr0
},
180 {0x01, check_texture_addr0
},
181 {0x02, check_texture_addr0
},
182 {0x03, check_texture_addr0
},
183 {0x04, check_texture_addr0
},
184 {0x05, check_texture_addr0
},
185 {0x06, check_texture_addr0
},
186 {0x07, check_texture_addr0
},
187 {0x08, check_texture_addr0
},
188 {0x09, check_texture_addr0
},
189 {0x20, check_texture_addr1
},
190 {0x21, check_texture_addr1
},
191 {0x22, check_texture_addr1
},
192 {0x23, check_texture_addr4
},
193 {0x2B, check_texture_addr3
},
194 {0x2C, check_texture_addr3
},
195 {0x2D, check_texture_addr3
},
196 {0x2E, check_texture_addr3
},
197 {0x2F, check_texture_addr3
},
198 {0x30, check_texture_addr3
},
199 {0x31, check_texture_addr3
},
200 {0x32, check_texture_addr3
},
201 {0x33, check_texture_addr3
},
202 {0x34, check_texture_addr3
},
203 {0x4B, check_texture_addr5
},
204 {0x4C, check_texture_addr6
},
205 {0x51, check_texture_addr7
},
206 {0x52, check_texture_addr8
},
207 {0x77, check_texture_addr2
},
211 {0x7B, check_texture_addr_mode
},
232 static hz_init_t init_table3
[] = {
233 {0xf2, check_for_header2_err
},
234 {0xf0, check_for_header1_err
},
235 {0xcc, check_for_dummy
},
236 {0x00, check_number_texunits
}
240 static hazard_t table1
[256];
241 static hazard_t table2
[256];
242 static hazard_t table3
[256];
246 static __inline__
int
247 eat_words(const uint32_t **buf
, const uint32_t *buf_end
, unsigned num_words
)
249 if ((*buf
- buf_end
) >= num_words
) {
253 DRM_ERROR("Illegal termination of DMA command buffer\n");
259 * Partially stolen from drm_memory.h
262 static __inline__ drm_map_t
*
263 via_drm_lookup_agp_map (drm_via_state_t
*seq
, unsigned long offset
, unsigned long size
,
266 struct list_head
*list
;
267 drm_map_list_t
*r_list
;
268 drm_map_t
*map
= seq
->map_cache
;
270 if (map
&& map
->offset
<= offset
&& (offset
+ size
) <= (map
->offset
+ map
->size
)) {
274 list_for_each(list
, &dev
->maplist
->head
) {
275 r_list
= (drm_map_list_t
*) list
;
279 if (map
->offset
<= offset
&& (offset
+ size
) <= (map
->offset
+ map
->size
) &&
280 !(map
->flags
& _DRM_RESTRICTED
) && (map
->type
== _DRM_AGP
)) {
281 seq
->map_cache
= map
;
290 * Require that all AGP texture levels reside in the same AGP map which should
291 * be mappable by the client. This is not a big restriction.
292 * FIXME: To actually enforce this security policy strictly, drm_rmmap
293 * would have to wait for dma quiescent before removing an AGP map.
294 * The via_drm_lookup_agp_map call in reality seems to take
295 * very little CPU time.
299 static __inline__
int
300 finish_current_sequence(drm_via_state_t
*cur_seq
)
302 switch(cur_seq
->unfinished
) {
304 DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq
->z_addr
);
307 DRM_DEBUG("Destination start address is 0x%x\n", cur_seq
->d_addr
);
310 if (cur_seq
->agp_texture
) {
311 unsigned start
= cur_seq
->tex_level_lo
[cur_seq
->texture
];
312 unsigned end
= cur_seq
->tex_level_hi
[cur_seq
->texture
];
313 unsigned long lo
=~0, hi
=0, tmp
;
314 uint32_t *addr
, *pitch
, *height
, tex
;
317 if (end
> 9) end
= 9;
318 if (start
> 9) start
= 9;
320 addr
=&(cur_seq
->t_addr
[tex
= cur_seq
->texture
][start
]);
321 pitch
= &(cur_seq
->pitch
[tex
][start
]);
322 height
= &(cur_seq
->height
[tex
][start
]);
324 for (i
=start
; i
<= end
; ++i
) {
326 if (tmp
< lo
) lo
= tmp
;
327 tmp
+= (*height
++ << *pitch
++);
328 if (tmp
> hi
) hi
= tmp
;
331 if (! via_drm_lookup_agp_map (cur_seq
, lo
, hi
- lo
, cur_seq
->dev
)) {
332 DRM_ERROR("AGP texture is not in allowed map\n");
340 cur_seq
->unfinished
= no_sequence
;
344 static __inline__
int
345 investigate_hazard( uint32_t cmd
, hazard_t hz
, drm_via_state_t
*cur_seq
)
347 register uint32_t tmp
, *tmp_addr
;
349 if (cur_seq
->unfinished
&& (cur_seq
->unfinished
!= seqs
[hz
])) {
351 if ((ret
= finish_current_sequence(cur_seq
))) return ret
;
355 case check_for_header2
:
356 if (cmd
== HALCYON_HEADER2
) return 1;
358 case check_for_header1
:
359 if ((cmd
& HALCYON_HEADER1MASK
) == HALCYON_HEADER1
) return 1;
361 case check_for_header2_err
:
362 if (cmd
== HALCYON_HEADER2
) return 1;
363 DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
365 case check_for_header1_err
:
366 if ((cmd
& HALCYON_HEADER1MASK
) == HALCYON_HEADER1
) return 1;
367 DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
370 if ((cmd
& HALCYON_FIREMASK
) == HALCYON_FIRECMD
) return 1;
371 DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
373 case check_for_dummy
:
374 if (HC_DUMMY
== cmd
) return 0;
375 DRM_ERROR("Illegal DMA HC_DUMMY command\n");
378 if (0xdddddddd == cmd
) return 0;
379 DRM_ERROR("Illegal DMA 0xdddddddd command\n");
381 case check_z_buffer_addr0
:
382 cur_seq
->unfinished
= z_address
;
383 cur_seq
->z_addr
= (cur_seq
->z_addr
& 0xFF000000) |
386 case check_z_buffer_addr1
:
387 cur_seq
->unfinished
= z_address
;
388 cur_seq
->z_addr
= (cur_seq
->z_addr
& 0x00FFFFFF) |
389 ((cmd
& 0xFF) << 24);
391 case check_z_buffer_addr_mode
:
392 cur_seq
->unfinished
= z_address
;
393 if ((cmd
& 0x0000C000) == 0) return 0;
394 DRM_ERROR("Attempt to place Z buffer in system memory\n");
396 case check_destination_addr0
:
397 cur_seq
->unfinished
= dest_address
;
398 cur_seq
->d_addr
= (cur_seq
->d_addr
& 0xFF000000) |
401 case check_destination_addr1
:
402 cur_seq
->unfinished
= dest_address
;
403 cur_seq
->d_addr
= (cur_seq
->d_addr
& 0x00FFFFFF) |
404 ((cmd
& 0xFF) << 24);
406 case check_destination_addr_mode
:
407 cur_seq
->unfinished
= dest_address
;
408 if ((cmd
& 0x0000C000) == 0) return 0;
409 DRM_ERROR("Attempt to place 3D drawing buffer in system memory\n");
411 case check_texture_addr0
:
412 cur_seq
->unfinished
= tex_address
;
414 tmp_addr
= &cur_seq
->t_addr
[cur_seq
->texture
][tmp
];
415 *tmp_addr
= (*tmp_addr
& 0xFF000000) | (cmd
& 0x00FFFFFF);
417 case check_texture_addr1
:
418 cur_seq
->unfinished
= tex_address
;
419 tmp
= ((cmd
>> 24) - 0x20);
421 tmp_addr
= &cur_seq
->t_addr
[cur_seq
->texture
][tmp
];
422 *tmp_addr
= (*tmp_addr
& 0x00FFFFFF) | ((cmd
& 0xFF) << 24);
424 *tmp_addr
= (*tmp_addr
& 0x00FFFFFF) | ((cmd
& 0xFF00) << 16);
426 *tmp_addr
= (*tmp_addr
& 0x00FFFFFF) | ((cmd
& 0xFF0000) << 8);
428 case check_texture_addr2
:
429 cur_seq
->unfinished
= tex_address
;
430 cur_seq
->tex_level_lo
[tmp
= cur_seq
->texture
] = cmd
& 0x3F;
431 cur_seq
->tex_level_hi
[tmp
] = (cmd
& 0xFC0) >> 6;
433 case check_texture_addr3
:
434 cur_seq
->unfinished
= tex_address
;
435 tmp
= ((cmd
>> 24) - 0x2B);
436 cur_seq
->pitch
[cur_seq
->texture
][tmp
] = (cmd
& 0x00F00000) >> 20;
437 if (!tmp
&& (cmd
& 0x000FFFFF)) {
438 DRM_ERROR("Unimplemented texture level 0 pitch mode.\n");
442 case check_texture_addr4
:
443 cur_seq
->unfinished
= tex_address
;
444 tmp_addr
= &cur_seq
->t_addr
[cur_seq
->texture
][9];
445 *tmp_addr
= (*tmp_addr
& 0x00FFFFFF) | ((cmd
& 0xFF) << 24);
447 case check_texture_addr5
:
448 case check_texture_addr6
:
449 cur_seq
->unfinished
= tex_address
;
451 * Texture width. We don't care since we have the pitch.
454 case check_texture_addr7
:
455 cur_seq
->unfinished
= tex_address
;
456 tmp_addr
= &(cur_seq
->height
[cur_seq
->texture
][0]);
457 tmp_addr
[5] = 1 << ((cmd
& 0x00F00000) >> 20);
458 tmp_addr
[4] = 1 << ((cmd
& 0x000F0000) >> 16);
459 tmp_addr
[3] = 1 << ((cmd
& 0x0000F000) >> 12);
460 tmp_addr
[2] = 1 << ((cmd
& 0x00000F00) >> 8);
461 tmp_addr
[1] = 1 << ((cmd
& 0x000000F0) >> 4);
462 tmp_addr
[0] = 1 << (cmd
& 0x0000000F);
464 case check_texture_addr8
:
465 cur_seq
->unfinished
= tex_address
;
466 tmp_addr
= &(cur_seq
->height
[cur_seq
->texture
][0]);
467 tmp_addr
[9] = 1 << ((cmd
& 0x0000F000) >> 12);
468 tmp_addr
[8] = 1 << ((cmd
& 0x00000F00) >> 8);
469 tmp_addr
[7] = 1 << ((cmd
& 0x000000F0) >> 4);
470 tmp_addr
[6] = 1 << (cmd
& 0x0000000F);
472 case check_texture_addr_mode
:
473 cur_seq
->unfinished
= tex_address
;
474 if ( 2 == (tmp
= cmd
& 0x00000003)) {
475 DRM_ERROR("Attempt to fetch texture from system memory.\n");
478 cur_seq
->agp_texture
= (tmp
== 3);
479 cur_seq
->tex_palette_size
[cur_seq
->texture
] =
480 (cmd
>> 16) & 0x000000007;
482 case check_for_vertex_count
:
483 cur_seq
->vertex_count
= cmd
& 0x0000FFFF;
485 case check_number_texunits
:
486 cur_seq
->multitex
= (cmd
>> 3) & 1;
489 DRM_ERROR("Illegal DMA data: 0x%x\n", cmd
);
496 static __inline__
int
497 via_check_prim_list(uint32_t const **buffer
, const uint32_t *buf_end
,
498 drm_via_state_t
*cur_seq
)
500 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) cur_seq
->dev
->dev_private
;
501 uint32_t a_fire
, bcmd
, dw_count
;
504 const uint32_t *buf
= *buffer
;
506 while(buf
< buf_end
) {
508 if ((buf_end
- buf
) < 2) {
509 DRM_ERROR("Unexpected termination of primitive list.\n");
513 if ((*buf
& HC_ACMD_MASK
) != HC_ACMD_HCmdB
) break;
515 if ((*buf
& HC_ACMD_MASK
) != HC_ACMD_HCmdA
) {
516 DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
521 a_fire
= *buf
++ | HC_HPLEND_MASK
| HC_HPMValidN_MASK
| HC_HE3Fire_MASK
;
524 * How many dwords per vertex ?
527 if (cur_seq
->agp
&& ((bcmd
& (0xF << 11)) == 0)) {
528 DRM_ERROR("Illegal B command vertex data for AGP.\n");
534 if (bcmd
& (1 << 7)) dw_count
+= (cur_seq
->multitex
) ? 2:1;
535 if (bcmd
& (1 << 8)) dw_count
+= (cur_seq
->multitex
) ? 2:1;
536 if (bcmd
& (1 << 9)) dw_count
++;
537 if (bcmd
& (1 << 10)) dw_count
++;
538 if (bcmd
& (1 << 11)) dw_count
++;
539 if (bcmd
& (1 << 12)) dw_count
++;
540 if (bcmd
& (1 << 13)) dw_count
++;
541 if (bcmd
& (1 << 14)) dw_count
++;
543 while(buf
< buf_end
) {
544 if (*buf
== a_fire
) {
545 if (dev_priv
->num_fire_offsets
>= VIA_FIRE_BUF_SIZE
) {
546 DRM_ERROR("Fire offset buffer full.\n");
550 dev_priv
->fire_offsets
[dev_priv
->num_fire_offsets
++] = buf
;
553 if (buf
< buf_end
&& *buf
== a_fire
)
557 if ((*buf
== HALCYON_HEADER2
) ||
558 ((*buf
& HALCYON_FIREMASK
) == HALCYON_FIRECMD
)) {
559 DRM_ERROR("Missing Vertex Fire command, "
560 "Stray Vertex Fire command or verifier "
565 if ((ret
= eat_words(&buf
, buf_end
, dw_count
)))
568 if (buf
>= buf_end
&& !have_fire
) {
569 DRM_ERROR("Missing Vertex Fire command or verifier "
574 if (cur_seq
->agp
&& ((buf
- cur_seq
->buf_start
) & 0x01)) {
575 DRM_ERROR("AGP Primitive list end misaligned.\n");
588 static __inline__ verifier_state_t
589 via_check_header2( uint32_t const **buffer
, const uint32_t *buf_end
,
590 drm_via_state_t
*hc_state
)
595 const uint32_t *buf
= *buffer
;
596 const hazard_t
*hz_table
;
599 if ((buf_end
- buf
) < 2) {
600 DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
604 cmd
= (*buf
++ & 0xFFFF0000) >> 16;
607 case HC_ParaType_CmdVdata
:
608 if (via_check_prim_list(&buf
, buf_end
, hc_state
))
611 return state_command
;
612 case HC_ParaType_NotTex
:
615 case HC_ParaType_Tex
:
616 hc_state
->texture
= 0;
619 case (HC_ParaType_Tex
| (HC_SubType_Tex1
<< 8)):
620 hc_state
->texture
= 1;
623 case (HC_ParaType_Tex
| (HC_SubType_TexGeneral
<< 8)):
626 case HC_ParaType_Auto
:
627 if (eat_words(&buf
, buf_end
, 2))
630 return state_command
;
631 case (HC_ParaType_Palette
| (HC_SubType_Stipple
<< 8)):
632 if (eat_words(&buf
, buf_end
, 32))
635 return state_command
;
636 case (HC_ParaType_Palette
| (HC_SubType_TexPalette0
<< 8)):
637 case (HC_ParaType_Palette
| (HC_SubType_TexPalette1
<< 8)):
638 DRM_ERROR("Texture palettes are rejected because of "
639 "lack of info how to determine their size.\n");
641 case (HC_ParaType_Palette
| (HC_SubType_FogTable
<< 8)):
642 DRM_ERROR("Fog factor palettes are rejected because of "
643 "lack of info how to determine their size.\n");
648 * There are some unimplemented HC_ParaTypes here, that
649 * need to be implemented if the Mesa driver is extended.
652 DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
653 "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
659 while(buf
< buf_end
) {
661 if ((hz
= hz_table
[cmd
>> 24])) {
662 if ((hz_mode
= investigate_hazard(cmd
, hz
, hc_state
))) {
669 } else if (hc_state
->unfinished
&&
670 finish_current_sequence(hc_state
)) {
674 if (hc_state
->unfinished
&& finish_current_sequence(hc_state
)) {
678 return state_command
;
681 static __inline__ verifier_state_t
682 via_parse_header2( drm_via_private_t
*dev_priv
, uint32_t const **buffer
, const uint32_t *buf_end
,
686 const uint32_t *buf
= *buffer
;
687 const uint32_t *next_fire
;
690 next_fire
= dev_priv
->fire_offsets
[*fire_count
];
692 cmd
= (*buf
& 0xFFFF0000) >> 16;
693 VIA_WRITE(HC_REG_TRANS_SET
+ HC_REG_BASE
, *buf
++);
695 case HC_ParaType_CmdVdata
:
696 while ((buf
< buf_end
) &&
697 (*fire_count
< dev_priv
->num_fire_offsets
) &&
698 (*buf
& HC_ACMD_MASK
) == HC_ACMD_HCmdB
) {
699 while(buf
<= next_fire
) {
700 VIA_WRITE(HC_REG_TRANS_SPACE
+ HC_REG_BASE
+ (burst
& 63), *buf
++);
703 if ( ( buf
< buf_end
) && ((*buf
& HALCYON_FIREMASK
) == HALCYON_FIRECMD
))
706 if (++(*fire_count
) < dev_priv
->num_fire_offsets
)
707 next_fire
= dev_priv
->fire_offsets
[*fire_count
];
711 while(buf
< buf_end
) {
713 if ( *buf
== HC_HEADER2
||
714 (*buf
& HALCYON_HEADER1MASK
) == HALCYON_HEADER1
||
715 (*buf
& VIA_VIDEOMASK
) == VIA_VIDEO_HEADER5
||
716 (*buf
& VIA_VIDEOMASK
) == VIA_VIDEO_HEADER6
) break;
718 VIA_WRITE(HC_REG_TRANS_SPACE
+ HC_REG_BASE
+ (burst
& 63), *buf
++);
723 return state_command
;
728 static __inline__
int
729 verify_mmio_address( uint32_t address
)
731 if ((address
> 0x3FF) && (address
< 0xC00 )) {
732 DRM_ERROR("Invalid VIDEO DMA command. "
733 "Attempt to access 3D- or command burst area.\n");
735 } else if ((address
> 0xCFF) && (address
< 0x1300)) {
736 DRM_ERROR("Invalid VIDEO DMA command. "
737 "Attempt to access PCI DMA area.\n");
739 } else if (address
> 0x13FF ) {
740 DRM_ERROR("Invalid VIDEO DMA command. "
741 "Attempt to access VGA registers.\n");
747 static __inline__
int
748 verify_video_tail( uint32_t const **buffer
, const uint32_t *buf_end
, uint32_t dwords
)
750 const uint32_t *buf
= *buffer
;
752 if (buf_end
- buf
< dwords
) {
753 DRM_ERROR("Illegal termination of video command.\n");
758 DRM_ERROR("Illegal video command tail.\n");
767 static __inline__ verifier_state_t
768 via_check_header1( uint32_t const **buffer
, const uint32_t *buf_end
)
771 const uint32_t *buf
= *buffer
;
772 verifier_state_t ret
= state_command
;
774 while (buf
< buf_end
) {
776 if ((cmd
> ((0x3FF >> 2) | HALCYON_HEADER1
)) &&
777 (cmd
< ((0xC00 >> 2) | HALCYON_HEADER1
))) {
778 if ((cmd
& HALCYON_HEADER1MASK
) != HALCYON_HEADER1
)
780 DRM_ERROR("Invalid HALCYON_HEADER1 command. "
781 "Attempt to access 3D- or command burst area.\n");
784 } else if (cmd
> ((0xCFF >> 2) | HALCYON_HEADER1
)) {
785 if ((cmd
& HALCYON_HEADER1MASK
) != HALCYON_HEADER1
)
787 DRM_ERROR("Invalid HALCYON_HEADER1 command. "
788 "Attempt to access VGA registers.\n");
799 static __inline__ verifier_state_t
800 via_parse_header1( drm_via_private_t
*dev_priv
, uint32_t const **buffer
, const uint32_t *buf_end
)
802 register uint32_t cmd
;
803 const uint32_t *buf
= *buffer
;
805 while (buf
< buf_end
) {
807 if ((cmd
& HALCYON_HEADER1MASK
) != HALCYON_HEADER1
) break;
808 VIA_WRITE( (cmd
& ~HALCYON_HEADER1MASK
) << 2, *++buf
);
812 return state_command
;
815 static __inline__ verifier_state_t
816 via_check_vheader5( uint32_t const **buffer
, const uint32_t *buf_end
)
819 const uint32_t *buf
= *buffer
;
821 if (buf_end
- buf
< 4) {
822 DRM_ERROR("Illegal termination of video header5 command\n");
826 data
= *buf
++ & ~VIA_VIDEOMASK
;
827 if (verify_mmio_address(data
))
831 if (*buf
++ != 0x00F50000) {
832 DRM_ERROR("Illegal header5 header data\n");
835 if (*buf
++ != 0x00000000) {
836 DRM_ERROR("Illegal header5 header data\n");
839 if (eat_words(&buf
, buf_end
, data
))
841 if ((data
& 3) && verify_video_tail(&buf
, buf_end
, 4 - (data
& 3)))
844 return state_command
;
848 static __inline__ verifier_state_t
849 via_parse_vheader5( drm_via_private_t
*dev_priv
, uint32_t const **buffer
, const uint32_t *buf_end
)
851 uint32_t addr
, count
, i
;
852 const uint32_t *buf
= *buffer
;
854 addr
= *buf
++ & ~VIA_VIDEOMASK
;
858 VIA_WRITE(addr
, *buf
++);
860 if (count
& 3) buf
+= 4 - (count
& 3);
862 return state_command
;
866 static __inline__ verifier_state_t
867 via_check_vheader6( uint32_t const **buffer
, const uint32_t *buf_end
)
870 const uint32_t *buf
= *buffer
;
874 if (buf_end
- buf
< 4) {
875 DRM_ERROR("Illegal termination of video header6 command\n");
880 if (*buf
++ != 0x00F60000) {
881 DRM_ERROR("Illegal header6 header data\n");
884 if (*buf
++ != 0x00000000) {
885 DRM_ERROR("Illegal header6 header data\n");
888 if ((buf_end
- buf
) < (data
<< 1)) {
889 DRM_ERROR("Illegal termination of video header6 command\n");
892 for (i
=0; i
<data
; ++i
) {
893 if (verify_mmio_address(*buf
++))
898 if ((data
& 3) && verify_video_tail(&buf
, buf_end
, 4 - (data
& 3)))
901 return state_command
;
904 static __inline__ verifier_state_t
905 via_parse_vheader6( drm_via_private_t
*dev_priv
, uint32_t const **buffer
, const uint32_t *buf_end
)
908 uint32_t addr
, count
, i
;
909 const uint32_t *buf
= *buffer
;
915 VIA_WRITE(addr
, *buf
++);
918 if (count
& 3) buf
+= 4 - (count
& 3);
920 return state_command
;
926 via_verify_command_stream(const uint32_t * buf
, unsigned int size
, drm_device_t
*dev
,
930 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
931 drm_via_state_t
*hc_state
= &dev_priv
->hc_state
;
932 drm_via_state_t saved_state
= *hc_state
;
934 const uint32_t *buf_end
= buf
+ ( size
>> 2 );
935 verifier_state_t state
= state_command
;
936 int pro_group_a
= dev_priv
->pro_group_a
;
939 hc_state
->unfinished
= no_sequence
;
940 hc_state
->map_cache
= NULL
;
942 hc_state
->buf_start
= buf
;
943 dev_priv
->num_fire_offsets
= 0;
945 while (buf
< buf_end
) {
949 state
= via_check_header2( &buf
, buf_end
, hc_state
);
952 state
= via_check_header1( &buf
, buf_end
);
955 state
= via_check_vheader5( &buf
, buf_end
);
958 state
= via_check_vheader6( &buf
, buf_end
);
961 if (HALCYON_HEADER2
== (cmd
= *buf
))
962 state
= state_header2
;
963 else if ((cmd
& HALCYON_HEADER1MASK
) == HALCYON_HEADER1
)
964 state
= state_header1
;
965 else if (pro_group_a
&& (cmd
& VIA_VIDEOMASK
) == VIA_VIDEO_HEADER5
)
966 state
= state_vheader5
;
967 else if (pro_group_a
&& (cmd
& VIA_VIDEOMASK
) == VIA_VIDEO_HEADER6
)
968 state
= state_vheader6
;
970 DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
977 *hc_state
= saved_state
;
978 return DRM_ERR(EINVAL
);
981 if (state
== state_error
) {
982 *hc_state
= saved_state
;
983 return DRM_ERR(EINVAL
);
989 via_parse_command_stream(drm_device_t
*dev
, const uint32_t * buf
, unsigned int size
)
992 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
994 const uint32_t *buf_end
= buf
+ ( size
>> 2 );
995 verifier_state_t state
= state_command
;
998 while (buf
< buf_end
) {
1002 state
= via_parse_header2( dev_priv
, &buf
, buf_end
, &fire_count
);
1005 state
= via_parse_header1( dev_priv
, &buf
, buf_end
);
1007 case state_vheader5
:
1008 state
= via_parse_vheader5( dev_priv
, &buf
, buf_end
);
1010 case state_vheader6
:
1011 state
= via_parse_vheader6( dev_priv
, &buf
, buf_end
);
1014 if (HALCYON_HEADER2
== (cmd
= *buf
))
1015 state
= state_header2
;
1016 else if ((cmd
& HALCYON_HEADER1MASK
) == HALCYON_HEADER1
)
1017 state
= state_header1
;
1018 else if ((cmd
& VIA_VIDEOMASK
) == VIA_VIDEO_HEADER5
)
1019 state
= state_vheader5
;
1020 else if ((cmd
& VIA_VIDEOMASK
) == VIA_VIDEO_HEADER6
)
1021 state
= state_vheader6
;
1023 DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
1025 state
= state_error
;
1030 return DRM_ERR(EINVAL
);
1033 if (state
== state_error
) {
1034 return DRM_ERR(EINVAL
);
1042 setup_hazard_table(hz_init_t init_table
[], hazard_t table
[], int size
)
1046 for(i
=0; i
<256; ++i
) {
1047 table
[i
] = forbidden_command
;
1050 for(i
=0; i
<size
; ++i
) {
1051 table
[init_table
[i
].code
] = init_table
[i
].hz
;
1056 via_init_command_verifier( void )
1058 setup_hazard_table(init_table1
, table1
, sizeof(init_table1
) / sizeof(hz_init_t
));
1059 setup_hazard_table(init_table2
, table2
, sizeof(init_table2
) / sizeof(hz_init_t
));
1060 setup_hazard_table(init_table3
, table3
, sizeof(init_table3
) / sizeof(hz_init_t
));