Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2004 The Unichrome Project. All Rights Reserved.
0003  * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the "Software"),
0007  * to deal in the Software without restriction, including without limitation
0008  * the rights to use, copy, modify, merge, publish, distribute, sub license,
0009  * and/or sell copies of the Software, and to permit persons to whom the
0010  * Software is furnished to do so, subject to the following conditions:
0011  *
0012  * The above copyright notice and this permission notice (including the
0013  * next paragraph) shall be included in all copies or substantial portions
0014  * of the Software.
0015  *
0016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0018  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
0019  * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0020  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0021  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0022  * DEALINGS IN THE SOFTWARE.
0023  *
0024  * Author: Thomas Hellstrom 2004, 2005.
0025  * This code was written using docs obtained under NDA from VIA Inc.
0026  *
0027  * Don't run this code directly on an AGP buffer. Due to cache problems it will
0028  * be very slow.
0029  */
0030 
0031 #include <drm/drm_device.h>
0032 #include <drm/drm_legacy.h>
0033 #include <drm/via_drm.h>
0034 
0035 #include "via_3d_reg.h"
0036 #include "via_drv.h"
0037 #include "via_verifier.h"
0038 
0039 typedef enum {
0040     state_command,
0041     state_header2,
0042     state_header1,
0043     state_vheader5,
0044     state_vheader6,
0045     state_error
0046 } verifier_state_t;
0047 
0048 typedef enum {
0049     no_check = 0,
0050     check_for_header2,
0051     check_for_header1,
0052     check_for_header2_err,
0053     check_for_header1_err,
0054     check_for_fire,
0055     check_z_buffer_addr0,
0056     check_z_buffer_addr1,
0057     check_z_buffer_addr_mode,
0058     check_destination_addr0,
0059     check_destination_addr1,
0060     check_destination_addr_mode,
0061     check_for_dummy,
0062     check_for_dd,
0063     check_texture_addr0,
0064     check_texture_addr1,
0065     check_texture_addr2,
0066     check_texture_addr3,
0067     check_texture_addr4,
0068     check_texture_addr5,
0069     check_texture_addr6,
0070     check_texture_addr7,
0071     check_texture_addr8,
0072     check_texture_addr_mode,
0073     check_for_vertex_count,
0074     check_number_texunits,
0075     forbidden_command
0076 } hazard_t;
0077 
0078 /*
0079  * Associates each hazard above with a possible multi-command
0080  * sequence. For example an address that is split over multiple
0081  * commands and that needs to be checked at the first command
0082  * that does not include any part of the address.
0083  */
0084 
0085 static drm_via_sequence_t seqs[] = {
0086     no_sequence,
0087     no_sequence,
0088     no_sequence,
0089     no_sequence,
0090     no_sequence,
0091     no_sequence,
0092     z_address,
0093     z_address,
0094     z_address,
0095     dest_address,
0096     dest_address,
0097     dest_address,
0098     no_sequence,
0099     no_sequence,
0100     tex_address,
0101     tex_address,
0102     tex_address,
0103     tex_address,
0104     tex_address,
0105     tex_address,
0106     tex_address,
0107     tex_address,
0108     tex_address,
0109     tex_address,
0110     no_sequence
0111 };
0112 
0113 typedef struct {
0114     unsigned int code;
0115     hazard_t hz;
0116 } hz_init_t;
0117 
0118 static hz_init_t init_table1[] = {
0119     {0xf2, check_for_header2_err},
0120     {0xf0, check_for_header1_err},
0121     {0xee, check_for_fire},
0122     {0xcc, check_for_dummy},
0123     {0xdd, check_for_dd},
0124     {0x00, no_check},
0125     {0x10, check_z_buffer_addr0},
0126     {0x11, check_z_buffer_addr1},
0127     {0x12, check_z_buffer_addr_mode},
0128     {0x13, no_check},
0129     {0x14, no_check},
0130     {0x15, no_check},
0131     {0x23, no_check},
0132     {0x24, no_check},
0133     {0x33, no_check},
0134     {0x34, no_check},
0135     {0x35, no_check},
0136     {0x36, no_check},
0137     {0x37, no_check},
0138     {0x38, no_check},
0139     {0x39, no_check},
0140     {0x3A, no_check},
0141     {0x3B, no_check},
0142     {0x3C, no_check},
0143     {0x3D, no_check},
0144     {0x3E, no_check},
0145     {0x40, check_destination_addr0},
0146     {0x41, check_destination_addr1},
0147     {0x42, check_destination_addr_mode},
0148     {0x43, no_check},
0149     {0x44, no_check},
0150     {0x50, no_check},
0151     {0x51, no_check},
0152     {0x52, no_check},
0153     {0x53, no_check},
0154     {0x54, no_check},
0155     {0x55, no_check},
0156     {0x56, no_check},
0157     {0x57, no_check},
0158     {0x58, no_check},
0159     {0x70, no_check},
0160     {0x71, no_check},
0161     {0x78, no_check},
0162     {0x79, no_check},
0163     {0x7A, no_check},
0164     {0x7B, no_check},
0165     {0x7C, no_check},
0166     {0x7D, check_for_vertex_count}
0167 };
0168 
0169 static hz_init_t init_table2[] = {
0170     {0xf2, check_for_header2_err},
0171     {0xf0, check_for_header1_err},
0172     {0xee, check_for_fire},
0173     {0xcc, check_for_dummy},
0174     {0x00, check_texture_addr0},
0175     {0x01, check_texture_addr0},
0176     {0x02, check_texture_addr0},
0177     {0x03, check_texture_addr0},
0178     {0x04, check_texture_addr0},
0179     {0x05, check_texture_addr0},
0180     {0x06, check_texture_addr0},
0181     {0x07, check_texture_addr0},
0182     {0x08, check_texture_addr0},
0183     {0x09, check_texture_addr0},
0184     {0x20, check_texture_addr1},
0185     {0x21, check_texture_addr1},
0186     {0x22, check_texture_addr1},
0187     {0x23, check_texture_addr4},
0188     {0x2B, check_texture_addr3},
0189     {0x2C, check_texture_addr3},
0190     {0x2D, check_texture_addr3},
0191     {0x2E, check_texture_addr3},
0192     {0x2F, check_texture_addr3},
0193     {0x30, check_texture_addr3},
0194     {0x31, check_texture_addr3},
0195     {0x32, check_texture_addr3},
0196     {0x33, check_texture_addr3},
0197     {0x34, check_texture_addr3},
0198     {0x4B, check_texture_addr5},
0199     {0x4C, check_texture_addr6},
0200     {0x51, check_texture_addr7},
0201     {0x52, check_texture_addr8},
0202     {0x77, check_texture_addr2},
0203     {0x78, no_check},
0204     {0x79, no_check},
0205     {0x7A, no_check},
0206     {0x7B, check_texture_addr_mode},
0207     {0x7C, no_check},
0208     {0x7D, no_check},
0209     {0x7E, no_check},
0210     {0x7F, no_check},
0211     {0x80, no_check},
0212     {0x81, no_check},
0213     {0x82, no_check},
0214     {0x83, no_check},
0215     {0x85, no_check},
0216     {0x86, no_check},
0217     {0x87, no_check},
0218     {0x88, no_check},
0219     {0x89, no_check},
0220     {0x8A, no_check},
0221     {0x90, no_check},
0222     {0x91, no_check},
0223     {0x92, no_check},
0224     {0x93, no_check}
0225 };
0226 
0227 static hz_init_t init_table3[] = {
0228     {0xf2, check_for_header2_err},
0229     {0xf0, check_for_header1_err},
0230     {0xcc, check_for_dummy},
0231     {0x00, check_number_texunits}
0232 };
0233 
0234 static hazard_t table1[256];
0235 static hazard_t table2[256];
0236 static hazard_t table3[256];
0237 
0238 static __inline__ int
0239 eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
0240 {
0241     if ((buf_end - *buf) >= num_words) {
0242         *buf += num_words;
0243         return 0;
0244     }
0245     DRM_ERROR("Illegal termination of DMA command buffer\n");
0246     return 1;
0247 }
0248 
0249 /*
0250  * Partially stolen from drm_memory.h
0251  */
0252 
0253 static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
0254                             unsigned long offset,
0255                             unsigned long size,
0256                             struct drm_device *dev)
0257 {
0258     struct drm_map_list *r_list;
0259     drm_local_map_t *map = seq->map_cache;
0260 
0261     if (map && map->offset <= offset
0262         && (offset + size) <= (map->offset + map->size)) {
0263         return map;
0264     }
0265 
0266     list_for_each_entry(r_list, &dev->maplist, head) {
0267         map = r_list->map;
0268         if (!map)
0269             continue;
0270         if (map->offset <= offset
0271             && (offset + size) <= (map->offset + map->size)
0272             && !(map->flags & _DRM_RESTRICTED)
0273             && (map->type == _DRM_AGP)) {
0274             seq->map_cache = map;
0275             return map;
0276         }
0277     }
0278     return NULL;
0279 }
0280 
0281 /*
0282  * Require that all AGP texture levels reside in the same AGP map which should
0283  * be mappable by the client. This is not a big restriction.
0284  * FIXME: To actually enforce this security policy strictly, drm_rmmap
0285  * would have to wait for dma quiescent before removing an AGP map.
0286  * The via_drm_lookup_agp_map call in reality seems to take
0287  * very little CPU time.
0288  */
0289 
0290 static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
0291 {
0292     switch (cur_seq->unfinished) {
0293     case z_address:
0294         DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
0295         break;
0296     case dest_address:
0297         DRM_DEBUG("Destination start address is 0x%x\n",
0298               cur_seq->d_addr);
0299         break;
0300     case tex_address:
0301         if (cur_seq->agp_texture) {
0302             unsigned start =
0303                 cur_seq->tex_level_lo[cur_seq->texture];
0304             unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
0305             unsigned long lo = ~0, hi = 0, tmp;
0306             uint32_t *addr, *pitch, *height, tex;
0307             unsigned i;
0308             int npot;
0309 
0310             if (end > 9)
0311                 end = 9;
0312             if (start > 9)
0313                 start = 9;
0314 
0315             addr =
0316                 &(cur_seq->t_addr[tex = cur_seq->texture][start]);
0317             pitch = &(cur_seq->pitch[tex][start]);
0318             height = &(cur_seq->height[tex][start]);
0319             npot = cur_seq->tex_npot[tex];
0320             for (i = start; i <= end; ++i) {
0321                 tmp = *addr++;
0322                 if (tmp < lo)
0323                     lo = tmp;
0324                 if (i == 0 && npot)
0325                     tmp += (*height++ * *pitch++);
0326                 else
0327                     tmp += (*height++ << *pitch++);
0328                 if (tmp > hi)
0329                     hi = tmp;
0330             }
0331 
0332             if (!via_drm_lookup_agp_map
0333                 (cur_seq, lo, hi - lo, cur_seq->dev)) {
0334                 DRM_ERROR
0335                     ("AGP texture is not in allowed map\n");
0336                 return 2;
0337             }
0338         }
0339         break;
0340     default:
0341         break;
0342     }
0343     cur_seq->unfinished = no_sequence;
0344     return 0;
0345 }
0346 
0347 static __inline__ int
0348 investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
0349 {
0350     register uint32_t tmp, *tmp_addr;
0351 
0352     if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
0353         int ret;
0354         if ((ret = finish_current_sequence(cur_seq)))
0355             return ret;
0356     }
0357 
0358     switch (hz) {
0359     case check_for_header2:
0360         if (cmd == HALCYON_HEADER2)
0361             return 1;
0362         return 0;
0363     case check_for_header1:
0364         if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
0365             return 1;
0366         return 0;
0367     case check_for_header2_err:
0368         if (cmd == HALCYON_HEADER2)
0369             return 1;
0370         DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
0371         break;
0372     case check_for_header1_err:
0373         if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
0374             return 1;
0375         DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
0376         break;
0377     case check_for_fire:
0378         if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD)
0379             return 1;
0380         DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
0381         break;
0382     case check_for_dummy:
0383         if (HC_DUMMY == cmd)
0384             return 0;
0385         DRM_ERROR("Illegal DMA HC_DUMMY command\n");
0386         break;
0387     case check_for_dd:
0388         if (0xdddddddd == cmd)
0389             return 0;
0390         DRM_ERROR("Illegal DMA 0xdddddddd command\n");
0391         break;
0392     case check_z_buffer_addr0:
0393         cur_seq->unfinished = z_address;
0394         cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
0395             (cmd & 0x00FFFFFF);
0396         return 0;
0397     case check_z_buffer_addr1:
0398         cur_seq->unfinished = z_address;
0399         cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
0400             ((cmd & 0xFF) << 24);
0401         return 0;
0402     case check_z_buffer_addr_mode:
0403         cur_seq->unfinished = z_address;
0404         if ((cmd & 0x0000C000) == 0)
0405             return 0;
0406         DRM_ERROR("Attempt to place Z buffer in system memory\n");
0407         return 2;
0408     case check_destination_addr0:
0409         cur_seq->unfinished = dest_address;
0410         cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
0411             (cmd & 0x00FFFFFF);
0412         return 0;
0413     case check_destination_addr1:
0414         cur_seq->unfinished = dest_address;
0415         cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
0416             ((cmd & 0xFF) << 24);
0417         return 0;
0418     case check_destination_addr_mode:
0419         cur_seq->unfinished = dest_address;
0420         if ((cmd & 0x0000C000) == 0)
0421             return 0;
0422         DRM_ERROR
0423             ("Attempt to place 3D drawing buffer in system memory\n");
0424         return 2;
0425     case check_texture_addr0:
0426         cur_seq->unfinished = tex_address;
0427         tmp = (cmd >> 24);
0428         tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
0429         *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
0430         return 0;
0431     case check_texture_addr1:
0432         cur_seq->unfinished = tex_address;
0433         tmp = ((cmd >> 24) - 0x20);
0434         tmp += tmp << 1;
0435         tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
0436         *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
0437         tmp_addr++;
0438         *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
0439         tmp_addr++;
0440         *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
0441         return 0;
0442     case check_texture_addr2:
0443         cur_seq->unfinished = tex_address;
0444         cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
0445         cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
0446         return 0;
0447     case check_texture_addr3:
0448         cur_seq->unfinished = tex_address;
0449         tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
0450         if (tmp == 0 &&
0451             (cmd & HC_HTXnEnPit_MASK)) {
0452             cur_seq->pitch[cur_seq->texture][tmp] =
0453                 (cmd & HC_HTXnLnPit_MASK);
0454             cur_seq->tex_npot[cur_seq->texture] = 1;
0455         } else {
0456             cur_seq->pitch[cur_seq->texture][tmp] =
0457                 (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
0458             cur_seq->tex_npot[cur_seq->texture] = 0;
0459             if (cmd & 0x000FFFFF) {
0460                 DRM_ERROR
0461                     ("Unimplemented texture level 0 pitch mode.\n");
0462                 return 2;
0463             }
0464         }
0465         return 0;
0466     case check_texture_addr4:
0467         cur_seq->unfinished = tex_address;
0468         tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
0469         *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
0470         return 0;
0471     case check_texture_addr5:
0472     case check_texture_addr6:
0473         cur_seq->unfinished = tex_address;
0474         /*
0475          * Texture width. We don't care since we have the pitch.
0476          */
0477         return 0;
0478     case check_texture_addr7:
0479         cur_seq->unfinished = tex_address;
0480         tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
0481         tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
0482         tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
0483         tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
0484         tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
0485         tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
0486         tmp_addr[0] = 1 << (cmd & 0x0000000F);
0487         return 0;
0488     case check_texture_addr8:
0489         cur_seq->unfinished = tex_address;
0490         tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
0491         tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
0492         tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
0493         tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
0494         tmp_addr[6] = 1 << (cmd & 0x0000000F);
0495         return 0;
0496     case check_texture_addr_mode:
0497         cur_seq->unfinished = tex_address;
0498         if (2 == (tmp = cmd & 0x00000003)) {
0499             DRM_ERROR
0500                 ("Attempt to fetch texture from system memory.\n");
0501             return 2;
0502         }
0503         cur_seq->agp_texture = (tmp == 3);
0504         cur_seq->tex_palette_size[cur_seq->texture] =
0505             (cmd >> 16) & 0x000000007;
0506         return 0;
0507     case check_for_vertex_count:
0508         cur_seq->vertex_count = cmd & 0x0000FFFF;
0509         return 0;
0510     case check_number_texunits:
0511         cur_seq->multitex = (cmd >> 3) & 1;
0512         return 0;
0513     default:
0514         DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
0515         return 2;
0516     }
0517     return 2;
0518 }
0519 
0520 static __inline__ int
0521 via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
0522             drm_via_state_t *cur_seq)
0523 {
0524     drm_via_private_t *dev_priv =
0525         (drm_via_private_t *) cur_seq->dev->dev_private;
0526     uint32_t a_fire, bcmd, dw_count;
0527     int ret = 0;
0528     int have_fire;
0529     const uint32_t *buf = *buffer;
0530 
0531     while (buf < buf_end) {
0532         have_fire = 0;
0533         if ((buf_end - buf) < 2) {
0534             DRM_ERROR
0535                 ("Unexpected termination of primitive list.\n");
0536             ret = 1;
0537             break;
0538         }
0539         if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB)
0540             break;
0541         bcmd = *buf++;
0542         if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
0543             DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
0544                   *buf);
0545             ret = 1;
0546             break;
0547         }
0548         a_fire =
0549             *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK |
0550             HC_HE3Fire_MASK;
0551 
0552         /*
0553          * How many dwords per vertex ?
0554          */
0555 
0556         if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
0557             DRM_ERROR("Illegal B command vertex data for AGP.\n");
0558             ret = 1;
0559             break;
0560         }
0561 
0562         dw_count = 0;
0563         if (bcmd & (1 << 7))
0564             dw_count += (cur_seq->multitex) ? 2 : 1;
0565         if (bcmd & (1 << 8))
0566             dw_count += (cur_seq->multitex) ? 2 : 1;
0567         if (bcmd & (1 << 9))
0568             dw_count++;
0569         if (bcmd & (1 << 10))
0570             dw_count++;
0571         if (bcmd & (1 << 11))
0572             dw_count++;
0573         if (bcmd & (1 << 12))
0574             dw_count++;
0575         if (bcmd & (1 << 13))
0576             dw_count++;
0577         if (bcmd & (1 << 14))
0578             dw_count++;
0579 
0580         while (buf < buf_end) {
0581             if (*buf == a_fire) {
0582                 if (dev_priv->num_fire_offsets >=
0583                     VIA_FIRE_BUF_SIZE) {
0584                     DRM_ERROR("Fire offset buffer full.\n");
0585                     ret = 1;
0586                     break;
0587                 }
0588                 dev_priv->fire_offsets[dev_priv->
0589                                num_fire_offsets++] =
0590                     buf;
0591                 have_fire = 1;
0592                 buf++;
0593                 if (buf < buf_end && *buf == a_fire)
0594                     buf++;
0595                 break;
0596             }
0597             if ((*buf == HALCYON_HEADER2) ||
0598                 ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
0599                 DRM_ERROR("Missing Vertex Fire command, "
0600                       "Stray Vertex Fire command  or verifier "
0601                       "lost sync.\n");
0602                 ret = 1;
0603                 break;
0604             }
0605             if ((ret = eat_words(&buf, buf_end, dw_count)))
0606                 break;
0607         }
0608         if (buf >= buf_end && !have_fire) {
0609             DRM_ERROR("Missing Vertex Fire command or verifier "
0610                   "lost sync.\n");
0611             ret = 1;
0612             break;
0613         }
0614         if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
0615             DRM_ERROR("AGP Primitive list end misaligned.\n");
0616             ret = 1;
0617             break;
0618         }
0619     }
0620     *buffer = buf;
0621     return ret;
0622 }
0623 
0624 static __inline__ verifier_state_t
0625 via_check_header2(uint32_t const **buffer, const uint32_t *buf_end,
0626           drm_via_state_t *hc_state)
0627 {
0628     uint32_t cmd;
0629     int hz_mode;
0630     hazard_t hz;
0631     const uint32_t *buf = *buffer;
0632     const hazard_t *hz_table;
0633 
0634     if ((buf_end - buf) < 2) {
0635         DRM_ERROR
0636             ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
0637         return state_error;
0638     }
0639     buf++;
0640     cmd = (*buf++ & 0xFFFF0000) >> 16;
0641 
0642     switch (cmd) {
0643     case HC_ParaType_CmdVdata:
0644         if (via_check_prim_list(&buf, buf_end, hc_state))
0645             return state_error;
0646         *buffer = buf;
0647         return state_command;
0648     case HC_ParaType_NotTex:
0649         hz_table = table1;
0650         break;
0651     case HC_ParaType_Tex:
0652         hc_state->texture = 0;
0653         hz_table = table2;
0654         break;
0655     case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
0656         hc_state->texture = 1;
0657         hz_table = table2;
0658         break;
0659     case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
0660         hz_table = table3;
0661         break;
0662     case HC_ParaType_Auto:
0663         if (eat_words(&buf, buf_end, 2))
0664             return state_error;
0665         *buffer = buf;
0666         return state_command;
0667     case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
0668         if (eat_words(&buf, buf_end, 32))
0669             return state_error;
0670         *buffer = buf;
0671         return state_command;
0672     case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
0673     case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
0674         DRM_ERROR("Texture palettes are rejected because of "
0675               "lack of info how to determine their size.\n");
0676         return state_error;
0677     case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
0678         DRM_ERROR("Fog factor palettes are rejected because of "
0679               "lack of info how to determine their size.\n");
0680         return state_error;
0681     default:
0682 
0683         /*
0684          * There are some unimplemented HC_ParaTypes here, that
0685          * need to be implemented if the Mesa driver is extended.
0686          */
0687 
0688         DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
0689               "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
0690               cmd, *(buf - 2));
0691         *buffer = buf;
0692         return state_error;
0693     }
0694 
0695     while (buf < buf_end) {
0696         cmd = *buf++;
0697         if ((hz = hz_table[cmd >> 24])) {
0698             if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
0699                 if (hz_mode == 1) {
0700                     buf--;
0701                     break;
0702                 }
0703                 return state_error;
0704             }
0705         } else if (hc_state->unfinished &&
0706                finish_current_sequence(hc_state)) {
0707             return state_error;
0708         }
0709     }
0710     if (hc_state->unfinished && finish_current_sequence(hc_state))
0711         return state_error;
0712     *buffer = buf;
0713     return state_command;
0714 }
0715 
0716 static __inline__ verifier_state_t
0717 via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer,
0718           const uint32_t *buf_end, int *fire_count)
0719 {
0720     uint32_t cmd;
0721     const uint32_t *buf = *buffer;
0722     const uint32_t *next_fire;
0723     int burst = 0;
0724 
0725     next_fire = dev_priv->fire_offsets[*fire_count];
0726     buf++;
0727     cmd = (*buf & 0xFFFF0000) >> 16;
0728     via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
0729     switch (cmd) {
0730     case HC_ParaType_CmdVdata:
0731         while ((buf < buf_end) &&
0732                (*fire_count < dev_priv->num_fire_offsets) &&
0733                (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) {
0734             while (buf <= next_fire) {
0735                 via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
0736                       (burst & 63), *buf++);
0737                 burst += 4;
0738             }
0739             if ((buf < buf_end)
0740                 && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
0741                 buf++;
0742 
0743             if (++(*fire_count) < dev_priv->num_fire_offsets)
0744                 next_fire = dev_priv->fire_offsets[*fire_count];
0745         }
0746         break;
0747     default:
0748         while (buf < buf_end) {
0749 
0750             if (*buf == HC_HEADER2 ||
0751                 (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
0752                 (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
0753                 (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
0754                 break;
0755 
0756             via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
0757                   (burst & 63), *buf++);
0758             burst += 4;
0759         }
0760     }
0761     *buffer = buf;
0762     return state_command;
0763 }
0764 
0765 static __inline__ int verify_mmio_address(uint32_t address)
0766 {
0767     if ((address > 0x3FF) && (address < 0xC00)) {
0768         DRM_ERROR("Invalid VIDEO DMA command. "
0769               "Attempt to access 3D- or command burst area.\n");
0770         return 1;
0771     } else if ((address > 0xCFF) && (address < 0x1300)) {
0772         DRM_ERROR("Invalid VIDEO DMA command. "
0773               "Attempt to access PCI DMA area.\n");
0774         return 1;
0775     } else if (address > 0x13FF) {
0776         DRM_ERROR("Invalid VIDEO DMA command. "
0777               "Attempt to access VGA registers.\n");
0778         return 1;
0779     }
0780     return 0;
0781 }
0782 
0783 static __inline__ int
0784 verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end,
0785           uint32_t dwords)
0786 {
0787     const uint32_t *buf = *buffer;
0788 
0789     if (buf_end - buf < dwords) {
0790         DRM_ERROR("Illegal termination of video command.\n");
0791         return 1;
0792     }
0793     while (dwords--) {
0794         if (*buf++) {
0795             DRM_ERROR("Illegal video command tail.\n");
0796             return 1;
0797         }
0798     }
0799     *buffer = buf;
0800     return 0;
0801 }
0802 
0803 static __inline__ verifier_state_t
0804 via_check_header1(uint32_t const **buffer, const uint32_t * buf_end)
0805 {
0806     uint32_t cmd;
0807     const uint32_t *buf = *buffer;
0808     verifier_state_t ret = state_command;
0809 
0810     while (buf < buf_end) {
0811         cmd = *buf;
0812         if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
0813             (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {
0814             if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
0815                 break;
0816             DRM_ERROR("Invalid HALCYON_HEADER1 command. "
0817                   "Attempt to access 3D- or command burst area.\n");
0818             ret = state_error;
0819             break;
0820         } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
0821             if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
0822                 break;
0823             DRM_ERROR("Invalid HALCYON_HEADER1 command. "
0824                   "Attempt to access VGA registers.\n");
0825             ret = state_error;
0826             break;
0827         } else {
0828             buf += 2;
0829         }
0830     }
0831     *buffer = buf;
0832     return ret;
0833 }
0834 
0835 static __inline__ verifier_state_t
0836 via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer,
0837           const uint32_t *buf_end)
0838 {
0839     register uint32_t cmd;
0840     const uint32_t *buf = *buffer;
0841 
0842     while (buf < buf_end) {
0843         cmd = *buf;
0844         if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
0845             break;
0846         via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
0847         buf++;
0848     }
0849     *buffer = buf;
0850     return state_command;
0851 }
0852 
0853 static __inline__ verifier_state_t
0854 via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end)
0855 {
0856     uint32_t data;
0857     const uint32_t *buf = *buffer;
0858 
0859     if (buf_end - buf < 4) {
0860         DRM_ERROR("Illegal termination of video header5 command\n");
0861         return state_error;
0862     }
0863 
0864     data = *buf++ & ~VIA_VIDEOMASK;
0865     if (verify_mmio_address(data))
0866         return state_error;
0867 
0868     data = *buf++;
0869     if (*buf++ != 0x00F50000) {
0870         DRM_ERROR("Illegal header5 header data\n");
0871         return state_error;
0872     }
0873     if (*buf++ != 0x00000000) {
0874         DRM_ERROR("Illegal header5 header data\n");
0875         return state_error;
0876     }
0877     if (eat_words(&buf, buf_end, data))
0878         return state_error;
0879     if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
0880         return state_error;
0881     *buffer = buf;
0882     return state_command;
0883 
0884 }
0885 
0886 static __inline__ verifier_state_t
0887 via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer,
0888            const uint32_t *buf_end)
0889 {
0890     uint32_t addr, count, i;
0891     const uint32_t *buf = *buffer;
0892 
0893     addr = *buf++ & ~VIA_VIDEOMASK;
0894     i = count = *buf;
0895     buf += 3;
0896     while (i--)
0897         via_write(dev_priv, addr, *buf++);
0898     if (count & 3)
0899         buf += 4 - (count & 3);
0900     *buffer = buf;
0901     return state_command;
0902 }
0903 
0904 static __inline__ verifier_state_t
0905 via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end)
0906 {
0907     uint32_t data;
0908     const uint32_t *buf = *buffer;
0909     uint32_t i;
0910 
0911     if (buf_end - buf < 4) {
0912         DRM_ERROR("Illegal termination of video header6 command\n");
0913         return state_error;
0914     }
0915     buf++;
0916     data = *buf++;
0917     if (*buf++ != 0x00F60000) {
0918         DRM_ERROR("Illegal header6 header data\n");
0919         return state_error;
0920     }
0921     if (*buf++ != 0x00000000) {
0922         DRM_ERROR("Illegal header6 header data\n");
0923         return state_error;
0924     }
0925     if ((buf_end - buf) < (data << 1)) {
0926         DRM_ERROR("Illegal termination of video header6 command\n");
0927         return state_error;
0928     }
0929     for (i = 0; i < data; ++i) {
0930         if (verify_mmio_address(*buf++))
0931             return state_error;
0932         buf++;
0933     }
0934     data <<= 1;
0935     if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
0936         return state_error;
0937     *buffer = buf;
0938     return state_command;
0939 }
0940 
0941 static __inline__ verifier_state_t
0942 via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer,
0943            const uint32_t *buf_end)
0944 {
0945 
0946     uint32_t addr, count, i;
0947     const uint32_t *buf = *buffer;
0948 
0949     i = count = *++buf;
0950     buf += 3;
0951     while (i--) {
0952         addr = *buf++;
0953         via_write(dev_priv, addr, *buf++);
0954     }
0955     count <<= 1;
0956     if (count & 3)
0957         buf += 4 - (count & 3);
0958     *buffer = buf;
0959     return state_command;
0960 }
0961 
0962 int
0963 via_verify_command_stream(const uint32_t * buf, unsigned int size,
0964               struct drm_device * dev, int agp)
0965 {
0966 
0967     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0968     drm_via_state_t *hc_state = &dev_priv->hc_state;
0969     drm_via_state_t saved_state = *hc_state;
0970     uint32_t cmd;
0971     const uint32_t *buf_end = buf + (size >> 2);
0972     verifier_state_t state = state_command;
0973     int cme_video;
0974     int supported_3d;
0975 
0976     cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
0977              dev_priv->chipset == VIA_DX9_0);
0978 
0979     supported_3d = dev_priv->chipset != VIA_DX9_0;
0980 
0981     hc_state->dev = dev;
0982     hc_state->unfinished = no_sequence;
0983     hc_state->map_cache = NULL;
0984     hc_state->agp = agp;
0985     hc_state->buf_start = buf;
0986     dev_priv->num_fire_offsets = 0;
0987 
0988     while (buf < buf_end) {
0989 
0990         switch (state) {
0991         case state_header2:
0992             state = via_check_header2(&buf, buf_end, hc_state);
0993             break;
0994         case state_header1:
0995             state = via_check_header1(&buf, buf_end);
0996             break;
0997         case state_vheader5:
0998             state = via_check_vheader5(&buf, buf_end);
0999             break;
1000         case state_vheader6:
1001             state = via_check_vheader6(&buf, buf_end);
1002             break;
1003         case state_command:
1004             cmd = *buf;
1005             if ((cmd == HALCYON_HEADER2) && supported_3d)
1006                 state = state_header2;
1007             else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
1008                 state = state_header1;
1009             else if (cme_video
1010                  && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
1011                 state = state_vheader5;
1012             else if (cme_video
1013                  && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
1014                 state = state_vheader6;
1015             else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
1016                 DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
1017                 state = state_error;
1018             } else {
1019                 DRM_ERROR
1020                     ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
1021                      cmd);
1022                 state = state_error;
1023             }
1024             break;
1025         case state_error:
1026         default:
1027             *hc_state = saved_state;
1028             return -EINVAL;
1029         }
1030     }
1031     if (state == state_error) {
1032         *hc_state = saved_state;
1033         return -EINVAL;
1034     }
1035     return 0;
1036 }
1037 
1038 int
1039 via_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
1040              unsigned int size)
1041 {
1042 
1043     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
1044     uint32_t cmd;
1045     const uint32_t *buf_end = buf + (size >> 2);
1046     verifier_state_t state = state_command;
1047     int fire_count = 0;
1048 
1049     while (buf < buf_end) {
1050 
1051         switch (state) {
1052         case state_header2:
1053             state =
1054                 via_parse_header2(dev_priv, &buf, buf_end,
1055                           &fire_count);
1056             break;
1057         case state_header1:
1058             state = via_parse_header1(dev_priv, &buf, buf_end);
1059             break;
1060         case state_vheader5:
1061             state = via_parse_vheader5(dev_priv, &buf, buf_end);
1062             break;
1063         case state_vheader6:
1064             state = via_parse_vheader6(dev_priv, &buf, buf_end);
1065             break;
1066         case state_command:
1067             cmd = *buf;
1068             if (cmd == HALCYON_HEADER2)
1069                 state = state_header2;
1070             else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
1071                 state = state_header1;
1072             else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
1073                 state = state_vheader5;
1074             else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
1075                 state = state_vheader6;
1076             else {
1077                 DRM_ERROR
1078                     ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
1079                      cmd);
1080                 state = state_error;
1081             }
1082             break;
1083         case state_error:
1084         default:
1085             return -EINVAL;
1086         }
1087     }
1088     if (state == state_error)
1089         return -EINVAL;
1090     return 0;
1091 }
1092 
1093 static void
1094 setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
1095 {
1096     int i;
1097 
1098     for (i = 0; i < 256; ++i)
1099         table[i] = forbidden_command;
1100 
1101     for (i = 0; i < size; ++i)
1102         table[init_table[i].code] = init_table[i].hz;
1103 }
1104 
1105 void via_init_command_verifier(void)
1106 {
1107     setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1));
1108     setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2));
1109     setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3));
1110 }