summaryrefslogtreecommitdiff
path: root/shared-core/via_verifier.c
diff options
context:
space:
mode:
authorThomas Hellstrom <unichrome@shipmail.org>2005-01-06 15:53:38 +0000
committerThomas Hellstrom <unichrome@shipmail.org>2005-01-06 15:53:38 +0000
commit50a6ffa8789ca12029da1db86ad8c90ce62cd241 (patch)
treec2fad8add60c4f83ef8b2aca223a245dcf86e7cf /shared-core/via_verifier.c
parentae1bc4a6da92ab31c933baa0b3f6c17c9bd16eb5 (diff)
via DRM: Updated the verifier to check the vertex lists more thorough. This
should hopefully stop it from getting out of sync. The PCI command parser is still not updated.
Diffstat (limited to 'shared-core/via_verifier.c')
-rw-r--r--shared-core/via_verifier.c125
1 files changed, 98 insertions, 27 deletions
diff --git a/shared-core/via_verifier.c b/shared-core/via_verifier.c
index 7a772588..534f2604 100644
--- a/shared-core/via_verifier.c
+++ b/shared-core/via_verifier.c
@@ -73,6 +73,8 @@ typedef enum{
check_texture_addr7,
check_texture_addr8,
check_texture_addr_mode,
+ check_for_vertex_count,
+ check_number_texunits,
forbidden_command
}hazard_t;
@@ -166,7 +168,7 @@ static hz_init_t init_table1[] = {
{0x7A, no_check},
{0x7B, no_check},
{0x7C, no_check},
- {0x7D, no_check}
+ {0x7D, check_for_vertex_count}
};
@@ -233,7 +235,7 @@ static hz_init_t init_table3[] = {
{0xf2, check_for_header2_err},
{0xf0, check_for_header1_err},
{0xcc, check_for_dummy},
- {0x00, no_check}
+ {0x00, check_number_texunits}
};
@@ -255,8 +257,10 @@ typedef struct{
uint32_t tex_palette_size[2];
sequence_t unfinished;
int agp_texture;
+ int multitex;
drm_device_t *dev;
drm_map_t *map_cache;
+ uint32_t vertex_count;
} sequence_context_t;
static sequence_context_t hc_sequence;
@@ -498,6 +502,12 @@ investigate_hazard( uint32_t cmd, hazard_t hz, sequence_context_t *cur_seq)
cur_seq->tex_palette_size[cur_seq->texture] =
(cmd >> 16) & 0x000000007;
return 0;
+ case check_for_vertex_count:
+ cur_seq->vertex_count = cmd & 0x0000FFFF;
+ return 0;
+ case check_number_texunits:
+ cur_seq->multitex = (cmd >> 3) & 1;
+ return 0;
default:
DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
return 2;
@@ -506,6 +516,84 @@ investigate_hazard( uint32_t cmd, hazard_t hz, sequence_context_t *cur_seq)
}
+static __inline__ int
+via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end,
+ sequence_context_t *cur_seq)
+{
+ uint32_t a_fire, bcmd , dw_count;
+ int ret = 0;
+ int have_fire;
+ const uint32_t *buf = *buffer;
+
+ while(buf < buf_end) {
+ have_fire = 0;
+ if ((buf_end - buf) < 2) {
+ DRM_ERROR("Unexpected termination of primitive list.\n");
+ ret = 1;
+ break;
+ }
+ if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break;
+ bcmd = *buf++;
+ if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
+ DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
+ *buf);
+ ret = 1;
+ break;
+ }
+ a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
+
+ /*
+ * How many dwords per vertex ?
+ */
+
+ if ((bcmd & (0xF << 11)) == 0) {
+ DRM_ERROR("Illegal B command vertex data for AGP.\n");
+ ret = 1;
+ break;
+ }
+
+ dw_count = 0;
+ if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1;
+ if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1;
+ if (bcmd & (1 << 9)) dw_count++;
+ if (bcmd & (1 << 10)) dw_count++;
+ if (bcmd & (1 << 11)) dw_count++;
+ if (bcmd & (1 << 12)) dw_count++;
+ if (bcmd & (1 << 13)) dw_count++;
+ if (bcmd & (1 << 14)) dw_count++;
+
+ while(buf < buf_end) {
+ if (*buf == HALCYON_HEADER2) {
+ DRM_ERROR("Missing Vertex Fire command or verifier "
+ "lost sync.\n");
+ ret = 1;
+ break;
+ }
+ if (*buf == a_fire) {
+ have_fire = 1;
+ buf++;
+ if (buf < buf_end && *buf == a_fire)
+ buf++;
+ break;
+ }
+ if ((ret = eat_words(&buf, buf_end, dw_count)))
+ break;
+ }
+ if (buf >= buf_end && !have_fire) {
+ DRM_ERROR("Missing Vertex Fire command or verifier "
+ "lost sync.\n");
+ ret = 1;
+ break;
+ }
+ }
+ *buffer = buf;
+ return ret;
+}
+
+
+
+
+
static __inline__ verifier_state_t
via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
{
@@ -515,6 +603,7 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
const uint32_t *buf = *buffer;
const hazard_t *hz_table;
+
if ((buf_end - buf) < 2) {
DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
return state_error;
@@ -524,32 +613,10 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
switch(cmd) {
case HC_ParaType_CmdVdata:
-
- /*
- * Command vertex data.
- * It is assumed that the command regulator remains in this state
- * until it encounters a possibly double fire command or a header2 data.
- * FIXME: Vertex data can accidently be header2 or fire.
- * CHECK: What does the regulator do if it encounters a header1
- * cmd?
- */
-
- while (buf < buf_end) {
- if (*buf == HALCYON_HEADER2) break;
- if ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD) {
- buf++;
- if ((buf < buf_end) &&
- ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
- buf++;
- if ((buf < buf_end) &&
- ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
- break;
- }
- buf++;
- }
+ if (via_check_prim_list(&buf, buf_end, &hc_sequence ))
+ return state_error;
*buffer = buf;
return state_command;
-
case HC_ParaType_NotTex:
hz_table = table1;
break;
@@ -591,7 +658,8 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
*/
DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
- "DMA subcommand: 0x%x\n", cmd);
+ "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
+ cmd, *(buf -2));
*buffer = buf;
return state_error;
}
@@ -726,6 +794,8 @@ via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
const uint32_t *buf = *buffer;
uint32_t i;
+ DRM_ERROR("H6\n");
+
if (buf_end - buf < 4) {
DRM_ERROR("Illegal termination of video header6 command\n");
return state_error;
@@ -768,6 +838,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
hc_sequence.map_cache = NULL;
while (buf < buf_end) {
+
switch (state) {
case state_header2:
state = via_check_header2( &buf, buf_end );