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