diff options
Diffstat (limited to 'shared-core/via_verifier.c')
-rw-r--r-- | shared-core/via_verifier.c | 125 |
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 ); |