2006-06-02 05:36:31 -05:00
/***************************************************************************
* Copyright ( C ) 2005 by Dominic Rath *
* Dominic . Rath @ gmx . de *
* *
2008-09-20 05:50:53 -05:00
* Copyright ( C ) 2008 by Spencer Oliver *
* spen @ spen - soft . co . uk *
* *
2008-10-03 08:25:33 -05:00
* Copyright ( C ) 2008 by Oyvind Harboe *
* oyvind . harboe @ zylin . com *
* *
2006-06-02 05:36:31 -05:00
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the *
* Free Software Foundation , Inc . , *
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-17 09:13:27 -05:00
# ifdef HAVE_CONFIG_H
2006-06-02 05:36:31 -05:00
# include "config.h"
2006-07-17 09:13:27 -05:00
# endif
2006-06-02 05:36:31 -05:00
# include "armv4_5.h"
2009-05-10 23:46:21 -05:00
# include "arm_disassembler.h"
2006-06-02 05:36:31 -05:00
# include "binarybuffer.h"
2009-11-13 10:43:51 -06:00
struct bitfield_desc armv4_5_psr_bitfield_desc [ ] =
2006-06-02 05:36:31 -05:00
{
{ " M[4:0] " , 5 } ,
{ " T " , 1 } ,
{ " F " , 1 } ,
{ " I " , 1 } ,
{ " reserved " , 16 } ,
{ " J " , 1 } ,
{ " reserved " , 2 } ,
{ " Q " , 1 } ,
{ " V " , 1 } ,
{ " C " , 1 } ,
{ " Z " , 1 } ,
{ " N " , 1 } ,
} ;
char * armv4_5_core_reg_list [ ] =
{
" r0 " , " r1 " , " r2 " , " r3 " , " r4 " , " r5 " , " r6 " , " r7 " , " r8 " , " r9 " , " r10 " , " r11 " , " r12 " , " r13_usr " , " lr_usr " , " pc " ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
" r8_fiq " , " r9_fiq " , " r10_fiq " , " r11_fiq " , " r12_fiq " , " r13_fiq " , " lr_fiq " ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
" r13_irq " , " lr_irq " ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
" r13_svc " , " lr_svc " ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
" r13_abt " , " lr_abt " ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
" r13_und " , " lr_und " ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
" cpsr " , " spsr_fiq " , " spsr_irq " , " spsr_svc " , " spsr_abt " , " spsr_und "
} ;
2008-05-19 07:39:06 -05:00
char * armv4_5_mode_strings_list [ ] =
2006-06-02 05:36:31 -05:00
{
2008-05-19 07:39:06 -05:00
" Illegal mode value " , " User " , " FIQ " , " IRQ " , " Supervisor " , " Abort " , " Undefined " , " System "
2006-06-02 05:36:31 -05:00
} ;
2008-05-19 07:39:06 -05:00
/* Hack! Yuk! allow -1 index, which simplifies codepaths elsewhere in the code */
2009-06-23 17:44:17 -05:00
char * * armv4_5_mode_strings = armv4_5_mode_strings_list + 1 ;
2008-05-19 07:39:06 -05:00
2006-06-02 05:36:31 -05:00
char * armv4_5_state_strings [ ] =
{
" ARM " , " Thumb " , " Jazelle "
} ;
int armv4_5_core_reg_arch_type = - 1 ;
2009-11-13 10:41:14 -06:00
struct armv4_5_core_reg armv4_5_core_reg_list_arch_info [ ] =
2006-06-02 05:36:31 -05:00
{
{ 0 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 1 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 2 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 3 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 4 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 5 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 6 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 7 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 8 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 9 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 10 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 11 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 12 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 13 , ARMV4_5_MODE_USR , NULL , NULL } ,
{ 14 , ARMV4_5_MODE_USR , NULL , NULL } ,
{ 15 , ARMV4_5_MODE_ANY , NULL , NULL } ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
{ 8 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 9 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 10 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 11 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 12 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 13 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 14 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
{ 13 , ARMV4_5_MODE_IRQ , NULL , NULL } ,
{ 14 , ARMV4_5_MODE_IRQ , NULL , NULL } ,
{ 13 , ARMV4_5_MODE_SVC , NULL , NULL } ,
{ 14 , ARMV4_5_MODE_SVC , NULL , NULL } ,
{ 13 , ARMV4_5_MODE_ABT , NULL , NULL } ,
{ 14 , ARMV4_5_MODE_ABT , NULL , NULL } ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
{ 13 , ARMV4_5_MODE_UND , NULL , NULL } ,
{ 14 , ARMV4_5_MODE_UND , NULL , NULL } ,
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
{ 16 , ARMV4_5_MODE_ANY , NULL , NULL } ,
{ 16 , ARMV4_5_MODE_FIQ , NULL , NULL } ,
{ 16 , ARMV4_5_MODE_IRQ , NULL , NULL } ,
{ 16 , ARMV4_5_MODE_SVC , NULL , NULL } ,
{ 16 , ARMV4_5_MODE_ABT , NULL , NULL } ,
{ 16 , ARMV4_5_MODE_UND , NULL , NULL }
} ;
/* map core mode (USR, FIQ, ...) and register number to indizes into the register cache */
int armv4_5_core_reg_map [ 7 ] [ 17 ] =
{
{ /* USR */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 31
} ,
{ /* FIQ */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 15 , 32
} ,
{ /* IRQ */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 23 , 24 , 15 , 33
} ,
{ /* SVC */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 25 , 26 , 15 , 34
} ,
{ /* ABT */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 27 , 28 , 15 , 35
} ,
{ /* UND */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 29 , 30 , 15 , 36
} ,
{ /* SYS */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 31
}
} ;
2009-06-18 02:04:08 -05:00
uint8_t armv4_5_gdb_dummy_fp_value [ ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2006-06-02 05:36:31 -05:00
reg_t armv4_5_gdb_dummy_fp_reg =
{
" GDB dummy floating-point register " , armv4_5_gdb_dummy_fp_value , 0 , 1 , 96 , NULL , 0 , NULL , 0
} ;
2009-06-18 02:04:08 -05:00
uint8_t armv4_5_gdb_dummy_fps_value [ ] = { 0 , 0 , 0 , 0 } ;
2006-06-02 05:36:31 -05:00
reg_t armv4_5_gdb_dummy_fps_reg =
{
" GDB dummy floating-point status register " , armv4_5_gdb_dummy_fps_value , 0 , 1 , 32 , NULL , 0 , NULL , 0
} ;
int armv4_5_get_core_reg ( reg_t * reg )
{
int retval ;
2009-11-13 10:41:14 -06:00
struct armv4_5_core_reg * armv4_5 = reg - > arch_info ;
2006-06-02 05:36:31 -05:00
target_t * target = armv4_5 - > target ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( target - > state ! = TARGET_HALTED )
{
2008-08-17 14:40:17 -05:00
LOG_ERROR ( " Target not halted " ) ;
2006-06-02 05:36:31 -05:00
return ERROR_TARGET_NOT_HALTED ;
}
2008-10-03 08:25:33 -05:00
2008-03-02 02:39:02 -06:00
/* retval = armv4_5->armv4_5_common->full_context(target); */
2006-06-02 05:36:31 -05:00
retval = armv4_5 - > armv4_5_common - > read_core_reg ( target , armv4_5 - > num , armv4_5 - > mode ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return retval ;
}
2009-06-18 02:04:08 -05:00
int armv4_5_set_core_reg ( reg_t * reg , uint8_t * buf )
2006-06-02 05:36:31 -05:00
{
2009-11-13 10:41:14 -06:00
struct armv4_5_core_reg * armv4_5 = reg - > arch_info ;
2006-06-02 05:36:31 -05:00
target_t * target = armv4_5 - > target ;
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5_target = target_to_armv4_5 ( target ) ;
2009-06-18 02:08:52 -05:00
uint32_t value = buf_get_u32 ( buf , 0 , 32 ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( target - > state ! = TARGET_HALTED )
{
return ERROR_TARGET_NOT_HALTED ;
}
2008-10-03 08:25:33 -05:00
2006-09-28 05:41:43 -05:00
if ( reg = = & armv4_5_target - > core_cache - > reg_list [ ARMV4_5_CPSR ] )
{
if ( value & 0x20 )
{
/* T bit should be set */
if ( armv4_5_target - > core_state = = ARMV4_5_STATE_ARM )
{
/* change state to Thumb */
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " changing to Thumb state " ) ;
2008-10-03 08:25:33 -05:00
armv4_5_target - > core_state = ARMV4_5_STATE_THUMB ;
2006-09-28 05:41:43 -05:00
}
}
else
{
/* T bit should be cleared */
if ( armv4_5_target - > core_state = = ARMV4_5_STATE_THUMB )
{
/* change state to ARM */
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " changing to ARM state " ) ;
2008-10-03 08:25:33 -05:00
armv4_5_target - > core_state = ARMV4_5_STATE_ARM ;
2006-09-28 05:41:43 -05:00
}
}
2008-10-03 08:25:33 -05:00
2009-04-19 15:51:16 -05:00
if ( armv4_5_target - > core_mode ! = ( enum armv4_5_mode ) ( value & 0x1f ) )
2007-04-11 09:25:12 -05:00
{
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " changing ARM core mode to '%s' " , armv4_5_mode_strings [ armv4_5_mode_to_number ( value & 0x1f ) ] ) ;
2007-04-11 09:25:12 -05:00
armv4_5_target - > core_mode = value & 0x1f ;
armv4_5_target - > write_core_reg ( target , 16 , ARMV4_5_MODE_ANY , value ) ;
}
2006-09-28 05:41:43 -05:00
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
buf_set_u32 ( reg - > value , 0 , 32 , value ) ;
reg - > dirty = 1 ;
reg - > valid = 1 ;
return ERROR_OK ;
}
int armv4_5_invalidate_core_regs ( target_t * target )
{
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2006-06-02 05:36:31 -05:00
int i ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < 37 ; i + + )
{
armv4_5 - > core_cache - > reg_list [ i ] . valid = 0 ;
armv4_5 - > core_cache - > reg_list [ i ] . dirty = 0 ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2009-11-13 10:44:08 -06:00
struct reg_cache * armv4_5_build_reg_cache ( target_t * target , armv4_5_common_t * armv4_5_common )
2006-06-02 05:36:31 -05:00
{
int num_regs = 37 ;
2009-11-13 10:44:08 -06:00
struct reg_cache * cache = malloc ( sizeof ( struct reg_cache ) ) ;
2006-06-02 05:36:31 -05:00
reg_t * reg_list = malloc ( sizeof ( reg_t ) * num_regs ) ;
2009-11-13 10:41:14 -06:00
struct armv4_5_core_reg * arch_info = malloc ( sizeof ( struct armv4_5_core_reg ) * num_regs ) ;
2006-06-02 05:36:31 -05:00
int i ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
cache - > name = " arm v4/5 registers " ;
cache - > next = NULL ;
cache - > reg_list = reg_list ;
cache - > num_regs = num_regs ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( armv4_5_core_reg_arch_type = = - 1 )
armv4_5_core_reg_arch_type = register_reg_arch_type ( armv4_5_get_core_reg , armv4_5_set_core_reg ) ;
2008-10-03 08:25:33 -05:00
2008-10-07 13:04:14 -05:00
register_init_dummy ( & armv4_5_gdb_dummy_fp_reg ) ;
register_init_dummy ( & armv4_5_gdb_dummy_fps_reg ) ;
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < 37 ; i + + )
{
arch_info [ i ] = armv4_5_core_reg_list_arch_info [ i ] ;
arch_info [ i ] . target = target ;
arch_info [ i ] . armv4_5_common = armv4_5_common ;
reg_list [ i ] . name = armv4_5_core_reg_list [ i ] ;
reg_list [ i ] . size = 32 ;
reg_list [ i ] . value = calloc ( 1 , 4 ) ;
reg_list [ i ] . dirty = 0 ;
reg_list [ i ] . valid = 0 ;
reg_list [ i ] . bitfield_desc = NULL ;
reg_list [ i ] . num_bitfields = 0 ;
reg_list [ i ] . arch_type = armv4_5_core_reg_arch_type ;
reg_list [ i ] . arch_info = & arch_info [ i ] ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return cache ;
}
2008-02-24 12:52:45 -06:00
int armv4_5_arch_state ( struct target_s * target )
2006-06-02 05:36:31 -05:00
{
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( armv4_5 - > common_magic ! = ARMV4_5_COMMON_MAGIC )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: called for a non-ARMv4/5 target " ) ;
2006-06-02 05:36:31 -05:00
exit ( - 1 ) ;
}
2008-10-03 08:25:33 -05:00
2009-06-20 22:15:51 -05:00
LOG_USER ( " target halted in %s state due to %s, current mode: %s \n cpsr: 0x%8.8 " PRIx32 " pc: 0x%8.8 " PRIx32 " " ,
2006-06-02 05:36:31 -05:00
armv4_5_state_strings [ armv4_5 - > core_state ] ,
2009-06-23 17:47:42 -05:00
Jim_Nvp_value2name_simple ( nvp_target_debug_reason , target - > debug_reason ) - > name ,
2006-06-02 05:36:31 -05:00
armv4_5_mode_strings [ armv4_5_mode_to_number ( armv4_5 - > core_mode ) ] ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . value , 0 , 32 ) ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ 15 ] . value , 0 , 32 ) ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_armv4_5_reg_command )
2006-06-02 05:36:31 -05:00
{
char output [ 128 ] ;
int output_len ;
int mode , num ;
target_t * target = get_current_target ( cmd_ctx ) ;
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( armv4_5 - > common_magic ! = ARMV4_5_COMMON_MAGIC )
{
command_print ( cmd_ctx , " current target isn't an ARMV4/5 target " ) ;
return ERROR_OK ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( target - > state ! = TARGET_HALTED )
{
command_print ( cmd_ctx , " error: target must be halted for register accesses " ) ;
return ERROR_OK ;
}
2008-10-03 08:25:33 -05:00
2008-05-19 14:02:36 -05:00
if ( armv4_5_mode_to_number ( armv4_5 - > core_mode ) = = - 1 )
return ERROR_FAIL ;
2006-06-02 05:36:31 -05:00
for ( num = 0 ; num < = 15 ; num + + )
{
output_len = 0 ;
for ( mode = 0 ; mode < 6 ; mode + + )
{
if ( ! ARMV4_5_CORE_REG_MODENUM ( armv4_5 - > core_cache , mode , num ) . valid )
{
armv4_5 - > full_context ( target ) ;
}
2009-06-23 17:49:23 -05:00
output_len + = snprintf ( output + output_len ,
128 - output_len ,
" %8s: %8.8 " PRIx32 " " ,
2009-06-20 22:15:51 -05:00
ARMV4_5_CORE_REG_MODENUM ( armv4_5 - > core_cache , mode , num ) . name ,
buf_get_u32 ( ARMV4_5_CORE_REG_MODENUM ( armv4_5 - > core_cache , mode , num ) . value , 0 , 32 ) ) ;
2006-06-02 05:36:31 -05:00
}
2009-05-21 04:28:57 -05:00
command_print ( cmd_ctx , " %s " , output ) ;
2006-06-02 05:36:31 -05:00
}
2009-06-20 22:15:51 -05:00
command_print ( cmd_ctx ,
" cpsr: %8.8 " PRIx32 " spsr_fiq: %8.8 " PRIx32 " spsr_irq: %8.8 " PRIx32 " spsr_svc: %8.8 " PRIx32 " spsr_abt: %8.8 " PRIx32 " spsr_und: %8.8 " PRIx32 " " ,
2006-06-02 05:36:31 -05:00
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . value , 0 , 32 ) ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_SPSR_FIQ ] . value , 0 , 32 ) ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_SPSR_IRQ ] . value , 0 , 32 ) ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_SPSR_SVC ] . value , 0 , 32 ) ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_SPSR_ABT ] . value , 0 , 32 ) ,
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_SPSR_UND ] . value , 0 , 32 ) ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_armv4_5_core_state_command )
2006-06-02 05:36:31 -05:00
{
target_t * target = get_current_target ( cmd_ctx ) ;
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( armv4_5 - > common_magic ! = ARMV4_5_COMMON_MAGIC )
{
command_print ( cmd_ctx , " current target isn't an ARMV4/5 target " ) ;
return ERROR_OK ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( argc > 0 )
{
if ( strcmp ( args [ 0 ] , " arm " ) = = 0 )
{
armv4_5 - > core_state = ARMV4_5_STATE_ARM ;
}
if ( strcmp ( args [ 0 ] , " thumb " ) = = 0 )
{
armv4_5 - > core_state = ARMV4_5_STATE_THUMB ;
}
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
command_print ( cmd_ctx , " core state: %s " , armv4_5_state_strings [ armv4_5 - > core_state ] ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_armv4_5_disassemble_command )
2006-06-12 11:49:49 -05:00
{
2008-10-14 06:06:30 -05:00
int retval = ERROR_OK ;
2006-06-12 11:49:49 -05:00
target_t * target = get_current_target ( cmd_ctx ) ;
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2009-06-18 02:08:52 -05:00
uint32_t address ;
2009-08-25 15:02:19 -05:00
int count = 1 ;
2006-06-12 11:49:49 -05:00
int i ;
arm_instruction_t cur_instruction ;
2009-06-18 02:08:52 -05:00
uint32_t opcode ;
2009-06-18 02:07:59 -05:00
uint16_t thumb_opcode ;
2006-08-31 07:41:49 -05:00
int thumb = 0 ;
2008-10-03 08:25:33 -05:00
2006-06-12 11:49:49 -05:00
if ( armv4_5 - > common_magic ! = ARMV4_5_COMMON_MAGIC )
{
command_print ( cmd_ctx , " current target isn't an ARMV4/5 target " ) ;
return ERROR_OK ;
}
2008-10-03 08:25:33 -05:00
2009-08-25 15:02:19 -05:00
switch ( argc ) {
case 3 :
if ( strcmp ( args [ 2 ] , " thumb " ) ! = 0 )
goto usage ;
thumb = 1 ;
/* FALL THROUGH */
case 2 :
2009-10-24 08:36:05 -05:00
COMMAND_PARSE_NUMBER ( int , args [ 1 ] , count ) ;
2009-08-25 15:02:19 -05:00
/* FALL THROUGH */
case 1 :
2009-10-24 08:36:05 -05:00
COMMAND_PARSE_NUMBER ( u32 , args [ 0 ] , address ) ;
2009-08-25 15:02:19 -05:00
if ( address & 0x01 ) {
if ( ! thumb ) {
command_print ( cmd_ctx , " Disassemble as Thumb " ) ;
thumb = 1 ;
}
address & = ~ 1 ;
}
break ;
default :
usage :
command_print ( cmd_ctx ,
" usage: armv4_5 disassemble <address> [<count> ['thumb']] " ) ;
2006-06-12 11:49:49 -05:00
return ERROR_OK ;
}
2008-10-03 08:25:33 -05:00
2006-06-12 11:49:49 -05:00
for ( i = 0 ; i < count ; i + + )
{
2009-05-10 14:02:07 -05:00
if ( thumb )
2008-10-14 06:06:30 -05:00
{
2009-05-10 14:02:07 -05:00
if ( ( retval = target_read_u16 ( target , address , & thumb_opcode ) ) ! = ERROR_OK )
2009-01-19 01:08:28 -06:00
{
return retval ;
}
2009-05-10 14:02:07 -05:00
if ( ( retval = thumb_evaluate_opcode ( thumb_opcode , address , & cur_instruction ) ) ! = ERROR_OK )
2009-01-19 01:08:28 -06:00
{
return retval ;
}
2008-10-14 06:06:30 -05:00
}
2009-01-19 01:08:28 -06:00
else {
2009-05-10 14:02:07 -05:00
if ( ( retval = target_read_u32 ( target , address , & opcode ) ) ! = ERROR_OK )
2009-01-19 01:08:28 -06:00
{
return retval ;
}
2009-05-10 14:02:07 -05:00
if ( ( retval = arm_evaluate_opcode ( opcode , address , & cur_instruction ) ) ! = ERROR_OK )
2009-01-19 01:08:28 -06:00
{
return retval ;
}
2008-10-14 06:06:30 -05:00
}
2006-06-12 11:49:49 -05:00
command_print ( cmd_ctx , " %s " , cur_instruction . text ) ;
address + = ( thumb ) ? 2 : 4 ;
}
2008-10-03 08:25:33 -05:00
2006-06-12 11:49:49 -05:00
return ERROR_OK ;
}
2006-06-02 05:36:31 -05:00
int armv4_5_register_commands ( struct command_context_s * cmd_ctx )
{
command_t * armv4_5_cmd ;
2009-08-25 15:02:19 -05:00
armv4_5_cmd = register_command ( cmd_ctx , NULL , " armv4_5 " ,
NULL , COMMAND_ANY ,
" armv4/5 specific commands " ) ;
2008-10-03 08:25:33 -05:00
2009-08-25 15:02:19 -05:00
register_command ( cmd_ctx , armv4_5_cmd , " reg " ,
handle_armv4_5_reg_command , COMMAND_EXEC ,
" display ARM core registers " ) ;
register_command ( cmd_ctx , armv4_5_cmd , " core_state " ,
handle_armv4_5_core_state_command , COMMAND_EXEC ,
" display/change ARM core state <arm | thumb> " ) ;
register_command ( cmd_ctx , armv4_5_cmd , " disassemble " ,
handle_armv4_5_disassemble_command , COMMAND_EXEC ,
" disassemble instructions <address> [<count> ['thumb']] " ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
int armv4_5_get_gdb_reg_list ( target_t * target , reg_t * * reg_list [ ] , int * reg_list_size )
{
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2006-06-02 05:36:31 -05:00
int i ;
2008-10-03 08:25:33 -05:00
2008-05-19 14:02:36 -05:00
if ( armv4_5_mode_to_number ( armv4_5 - > core_mode ) = = - 1 )
return ERROR_FAIL ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
* reg_list_size = 26 ;
* reg_list = malloc ( sizeof ( reg_t * ) * ( * reg_list_size ) ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < 16 ; i + + )
{
( * reg_list ) [ i ] = & ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5 - > core_mode , i ) ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 16 ; i < 24 ; i + + )
{
( * reg_list ) [ i ] = & armv4_5_gdb_dummy_fp_reg ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
( * reg_list ) [ 24 ] = & armv4_5_gdb_dummy_fps_reg ;
( * reg_list ) [ 25 ] = & armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2008-10-12 12:28:12 -05:00
/* wait for execution to complete and check exit point */
2009-06-18 02:08:52 -05:00
static int armv4_5_run_algorithm_completion ( struct target_s * target , uint32_t exit_point , int timeout_ms , void * arch_info )
2008-10-12 12:28:12 -05:00
{
int retval ;
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2008-10-12 12:28:12 -05:00
2009-05-10 14:02:07 -05:00
if ( ( retval = target_wait_state ( target , TARGET_HALTED , timeout_ms ) ) ! = ERROR_OK )
2008-10-14 06:06:30 -05:00
{
return retval ;
}
2008-10-12 12:28:12 -05:00
if ( target - > state ! = TARGET_HALTED )
{
2009-06-23 17:42:54 -05:00
if ( ( retval = target_halt ( target ) ) ! = ERROR_OK )
2008-10-12 12:28:12 -05:00
return retval ;
2009-06-23 17:42:54 -05:00
if ( ( retval = target_wait_state ( target , TARGET_HALTED , 500 ) ) ! = ERROR_OK )
2008-10-12 12:28:12 -05:00
{
return retval ;
}
return ERROR_TARGET_TIMEOUT ;
}
2009-09-09 01:28:49 -05:00
/* fast exit: ARMv5+ code can use BKPT */
if ( exit_point & & buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ 15 ] . value ,
0 , 32 ) ! = exit_point )
2008-10-12 12:28:12 -05:00
{
2009-06-20 22:15:51 -05:00
LOG_WARNING ( " target reentered debug state, but not at the desired exit point: 0x%4.4 " PRIx32 " " ,
2008-10-12 12:28:12 -05:00
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ 15 ] . value , 0 , 32 ) ) ;
return ERROR_TARGET_TIMEOUT ;
}
return ERROR_OK ;
}
2009-11-13 10:39:42 -06:00
int armv4_5_run_algorithm_inner ( struct target_s * target , int num_mem_params , struct mem_param * mem_params , int num_reg_params , struct reg_param * reg_params , uint32_t entry_point , uint32_t exit_point , int timeout_ms , void * arch_info , int ( * run_it ) ( struct target_s * target , uint32_t exit_point , int timeout_ms , void * arch_info ) )
2006-06-02 05:36:31 -05:00
{
2009-11-06 00:04:22 -06:00
struct armv4_5_common_s * armv4_5 = target_to_armv4_5 ( target ) ;
2009-11-13 10:41:07 -06:00
struct armv4_5_algorithm * armv4_5_algorithm_info = arch_info ;
2006-06-02 05:36:31 -05:00
enum armv4_5_state core_state = armv4_5 - > core_state ;
enum armv4_5_mode core_mode = armv4_5 - > core_mode ;
2009-06-18 02:08:52 -05:00
uint32_t context [ 17 ] ;
uint32_t cpsr ;
2006-06-02 05:36:31 -05:00
int exit_breakpoint_size = 0 ;
int i ;
int retval = ERROR_OK ;
2008-04-03 09:00:17 -05:00
LOG_DEBUG ( " Running algorithm " ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( armv4_5_algorithm_info - > common_magic ! = ARMV4_5_COMMON_MAGIC )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " current target isn't an ARMV4/5 target " ) ;
2006-06-02 05:36:31 -05:00
return ERROR_TARGET_INVALID ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( target - > state ! = TARGET_HALTED )
{
2008-03-25 10:45:17 -05:00
LOG_WARNING ( " target not halted " ) ;
2006-06-02 05:36:31 -05:00
return ERROR_TARGET_NOT_HALTED ;
}
2008-10-03 08:25:33 -05:00
2008-05-19 14:02:36 -05:00
if ( armv4_5_mode_to_number ( armv4_5 - > core_mode ) = = - 1 )
return ERROR_FAIL ;
2009-09-09 01:28:49 -05:00
/* armv5 and later can terminate with BKPT instruction; less overhead */
if ( ! exit_point & & armv4_5 - > is_armv4 )
{
LOG_ERROR ( " ARMv4 target needs HW breakpoint location " ) ;
return ERROR_FAIL ;
}
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < = 16 ; i + + )
{
if ( ! ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . valid )
armv4_5 - > read_core_reg ( target , i , armv4_5_algorithm_info - > core_mode ) ;
context [ i ] = buf_get_u32 ( ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . value , 0 , 32 ) ;
}
cpsr = buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . value , 0 , 32 ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < num_mem_params ; i + + )
{
2009-05-10 14:02:07 -05:00
if ( ( retval = target_write_buffer ( target , mem_params [ i ] . address , mem_params [ i ] . size , mem_params [ i ] . value ) ) ! = ERROR_OK )
2008-10-14 06:06:30 -05:00
{
return retval ;
}
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < num_reg_params ; i + + )
{
reg_t * reg = register_get_by_name ( armv4_5 - > core_cache , reg_params [ i ] . reg_name , 0 ) ;
if ( ! reg )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: register '%s' not found " , reg_params [ i ] . reg_name ) ;
2006-06-02 05:36:31 -05:00
exit ( - 1 ) ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( reg - > size ! = reg_params [ i ] . size )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: register '%s' size doesn't match reg_params[i].size " , reg_params [ i ] . reg_name ) ;
2006-06-02 05:36:31 -05:00
exit ( - 1 ) ;
}
2008-10-03 08:25:33 -05:00
2009-05-10 14:02:07 -05:00
if ( ( retval = armv4_5_set_core_reg ( reg , reg_params [ i ] . value ) ) ! = ERROR_OK )
2008-10-14 06:06:30 -05:00
{
return retval ;
}
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
armv4_5 - > core_state = armv4_5_algorithm_info - > core_state ;
if ( armv4_5 - > core_state = = ARMV4_5_STATE_ARM )
exit_breakpoint_size = 4 ;
else if ( armv4_5 - > core_state = = ARMV4_5_STATE_THUMB )
exit_breakpoint_size = 2 ;
else
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: can't execute algorithms when not in ARM or Thumb state " ) ;
2006-06-02 05:36:31 -05:00
exit ( - 1 ) ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( armv4_5_algorithm_info - > core_mode ! = ARMV4_5_MODE_ANY )
{
2008-03-25 10:45:17 -05:00
LOG_DEBUG ( " setting core_mode: 0x%2.2x " , armv4_5_algorithm_info - > core_mode ) ;
2006-06-02 05:36:31 -05:00
buf_set_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . value , 0 , 5 , armv4_5_algorithm_info - > core_mode ) ;
armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . dirty = 1 ;
armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . valid = 1 ;
}
2009-09-09 01:28:49 -05:00
/* terminate using a hardware or (ARMv5+) software breakpoint */
if ( exit_point & & ( retval = breakpoint_add ( target , exit_point ,
exit_breakpoint_size , BKPT_HARD ) ) ! = ERROR_OK )
2006-06-02 05:36:31 -05:00
{
2009-09-09 01:28:49 -05:00
LOG_ERROR ( " can't add HW breakpoint to terminate algorithm " ) ;
2006-06-02 05:36:31 -05:00
return ERROR_TARGET_FAILURE ;
}
2008-10-03 08:25:33 -05:00
2009-05-10 14:02:07 -05:00
if ( ( retval = target_resume ( target , 0 , entry_point , 1 , 1 ) ) ! = ERROR_OK )
2008-10-14 06:06:30 -05:00
{
return retval ;
}
int retvaltemp ;
2009-06-23 17:42:54 -05:00
retval = run_it ( target , exit_point , timeout_ms , arch_info ) ;
2008-10-03 08:25:33 -05:00
2009-09-09 01:28:49 -05:00
if ( exit_point )
breakpoint_remove ( target , exit_point ) ;
2008-10-03 08:25:33 -05:00
2009-06-23 17:38:12 -05:00
if ( retval ! = ERROR_OK )
2008-10-16 07:20:11 -05:00
return retval ;
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < num_mem_params ; i + + )
{
if ( mem_params [ i ] . direction ! = PARAM_OUT )
2009-05-10 14:02:07 -05:00
if ( ( retvaltemp = target_read_buffer ( target , mem_params [ i ] . address , mem_params [ i ] . size , mem_params [ i ] . value ) ) ! = ERROR_OK )
2008-10-14 06:06:30 -05:00
{
retval = retvaltemp ;
}
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < num_reg_params ; i + + )
{
if ( reg_params [ i ] . direction ! = PARAM_OUT )
{
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
reg_t * reg = register_get_by_name ( armv4_5 - > core_cache , reg_params [ i ] . reg_name , 0 ) ;
if ( ! reg )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: register '%s' not found " , reg_params [ i ] . reg_name ) ;
2006-06-02 05:36:31 -05:00
exit ( - 1 ) ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( reg - > size ! = reg_params [ i ] . size )
{
2008-03-25 10:45:17 -05:00
LOG_ERROR ( " BUG: register '%s' size doesn't match reg_params[i].size " , reg_params [ i ] . reg_name ) ;
2006-06-02 05:36:31 -05:00
exit ( - 1 ) ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
buf_set_u32 ( reg_params [ i ] . value , 0 , 32 , buf_get_u32 ( reg - > value , 0 , 32 ) ) ;
}
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < = 16 ; i + + )
{
2009-06-18 02:08:52 -05:00
uint32_t regvalue ;
2009-04-03 05:10:12 -05:00
regvalue = buf_get_u32 ( ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . value , 0 , 32 ) ;
if ( regvalue ! = context [ i ] )
{
2009-06-20 22:15:51 -05:00
LOG_DEBUG ( " restoring register %s with value 0x%8.8 " PRIx32 " " , ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . name , context [ i ] ) ;
2009-04-03 05:10:12 -05:00
buf_set_u32 ( ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . value , 0 , 32 , context [ i ] ) ;
ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . valid = 1 ;
ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache , armv4_5_algorithm_info - > core_mode , i ) . dirty = 1 ;
}
2006-06-02 05:36:31 -05:00
}
buf_set_u32 ( armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . value , 0 , 32 , cpsr ) ;
armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . valid = 1 ;
armv4_5 - > core_cache - > reg_list [ ARMV4_5_CPSR ] . dirty = 1 ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
armv4_5 - > core_state = core_state ;
armv4_5 - > core_mode = core_mode ;
return retval ;
}
2009-11-13 10:39:42 -06:00
int armv4_5_run_algorithm ( struct target_s * target , int num_mem_params , struct mem_param * mem_params , int num_reg_params , struct reg_param * reg_params , uint32_t entry_point , uint32_t exit_point , int timeout_ms , void * arch_info )
2008-10-12 12:28:12 -05:00
{
return armv4_5_run_algorithm_inner ( target , num_mem_params , mem_params , num_reg_params , reg_params , entry_point , exit_point , timeout_ms , arch_info , armv4_5_run_algorithm_completion ) ;
}
2006-06-02 05:36:31 -05:00
int armv4_5_init_arch_info ( target_t * target , armv4_5_common_t * armv4_5 )
2008-10-03 08:25:33 -05:00
{
2006-06-02 05:36:31 -05:00
target - > arch_info = armv4_5 ;
armv4_5 - > common_magic = ARMV4_5_COMMON_MAGIC ;
armv4_5 - > core_state = ARMV4_5_STATE_ARM ;
armv4_5 - > core_mode = ARMV4_5_MODE_USR ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}