summaryrefslogtreecommitdiff
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
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.
-rw-r--r--shared-core/via_drv.h4
-rw-r--r--shared-core/via_verifier.c125
2 files changed, 100 insertions, 29 deletions
diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h
index d085179a..eb75f1ed 100644
--- a/shared-core/via_drv.h
+++ b/shared-core/via_drv.h
@@ -28,11 +28,11 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome"
-#define DRIVER_DATE "20050105"
+#define DRIVER_DATE "20050106"
#define DRIVER_MAJOR 2
#define DRIVER_MINOR 4
-#define DRIVER_PATCHLEVEL 0
+#define DRIVER_PATCHLEVEL 1
typedef struct drm_via_ring_buffer {
drm_map_t map;
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 );