From 50a6ffa8789ca12029da1db86ad8c90ce62cd241 Mon Sep 17 00:00:00 2001
From: Thomas Hellstrom <unichrome@shipmail.org>
Date: Thu, 6 Jan 2005 15:53:38 +0000
Subject: 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.

---
 shared-core/via_drv.h      |   4 +-
 shared-core/via_verifier.c | 125 +++++++++++++++++++++++++++++++++++----------
 2 files changed, 100 insertions(+), 29 deletions(-)

(limited to 'shared-core')

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 );
-- 
cgit v1.2.3