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-11-16 02:34:57 -06:00
# include "breakpoints.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-16 02:35:05 -06:00
# include "algorithm.h"
2006-06-02 05:36:31 -05:00
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
2009-11-13 11:55:49 -06:00
struct reg armv4_5_gdb_dummy_fp_reg =
2006-06-02 05:36:31 -05:00
{
2009-11-13 18:22:36 -06:00
. name = " GDB dummy floating-point register " ,
. value = armv4_5_gdb_dummy_fp_value ,
. dirty = 0 ,
. valid = 1 ,
. size = 96 ,
. arch_info = NULL ,
. arch_type = 0 ,
2006-06-02 05:36:31 -05:00
} ;
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
2009-11-13 11:55:49 -06:00
struct reg armv4_5_gdb_dummy_fps_reg =
2006-06-02 05:36:31 -05:00
{
2009-11-13 18:22:36 -06:00
. name = " GDB dummy floating-point status register " ,
. value = armv4_5_gdb_dummy_fps_value ,
. dirty = 0 ,
. valid = 1 ,
. size = 32 ,
. arch_info = NULL ,
. arch_type = 0 ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-13 11:55:49 -06:00
int armv4_5_get_core_reg ( struct reg * reg )
2006-06-02 05:36:31 -05:00
{
int retval ;
2009-11-13 10:41:14 -06:00
struct armv4_5_core_reg * armv4_5 = reg - > arch_info ;
2009-11-13 12:11:13 -06:00
struct target * 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-11-13 11:55:49 -06:00
int armv4_5_set_core_reg ( struct reg * 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 ;
2009-11-13 12:11:13 -06:00
struct target * 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 ;
}
2009-11-13 12:11:13 -06:00
int armv4_5_invalidate_core_regs ( struct target * 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 ) ;
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 12:11:13 -06:00
struct reg_cache * armv4_5_build_reg_cache ( struct target * target , struct arm * 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 ) ) ;
2009-11-13 11:55:49 -06:00
struct reg * reg_list = malloc ( sizeof ( struct reg ) * 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 ] . 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 ;
}
2009-11-13 12:11:13 -06:00
int armv4_5_arch_state ( struct target * 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 ;
2009-11-13 12:11:13 -06:00
struct target * 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
{
2009-11-13 12:11:13 -06:00
struct target * 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 ;
2009-11-13 12:11:13 -06:00
struct target * 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 ;
2009-11-13 11:06:49 -06:00
struct arm_instruction 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 ;
}
2009-11-13 15:25:47 -06:00
int armv4_5_register_commands ( struct command_context * cmd_ctx )
2006-06-02 05:36:31 -05:00
{
2009-11-13 15:30:50 -06:00
struct command * armv4_5_cmd ;
2006-06-02 05:36:31 -05:00
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 ;
}
2009-11-13 12:11:13 -06:00
int armv4_5_get_gdb_reg_list ( struct target * target , struct reg * * reg_list [ ] , int * reg_list_size )
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 ) ;
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 ;
2009-11-13 11:55:49 -06:00
* reg_list = malloc ( sizeof ( struct reg * ) * ( * 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-11-13 12:11:13 -06:00
static int armv4_5_run_algorithm_completion ( struct target * 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 12:11:13 -06:00
int armv4_5_run_algorithm_inner ( struct target * 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 * 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 + + )
{
2009-11-13 11:55:49 -06:00
struct reg * reg = register_get_by_name ( armv4_5 - > core_cache , reg_params [ i ] . reg_name , 0 ) ;
2006-06-02 05:36:31 -05:00
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
2009-11-13 11:55:49 -06:00
struct reg * reg = register_get_by_name ( armv4_5 - > core_cache , reg_params [ i ] . reg_name , 0 ) ;
2006-06-02 05:36:31 -05:00
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 12:11:13 -06:00
int armv4_5_run_algorithm ( struct target * 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 ) ;
}
2009-11-15 12:35:34 -06:00
/**
* Runs ARM code in the target to calculate a CRC32 checksum .
*
* \ todo On ARMv5 + , rely on BKPT termination for reduced overhead .
*/
int arm_checksum_memory ( struct target * target ,
uint32_t address , uint32_t count , uint32_t * checksum )
{
struct working_area * crc_algorithm ;
struct armv4_5_algorithm armv4_5_info ;
struct reg_param reg_params [ 2 ] ;
int retval ;
uint32_t i ;
static const uint32_t arm_crc_code [ ] = {
0xE1A02000 , /* mov r2, r0 */
0xE3E00000 , /* mov r0, #0xffffffff */
0xE1A03001 , /* mov r3, r1 */
0xE3A04000 , /* mov r4, #0 */
0xEA00000B , /* b ncomp */
/* nbyte: */
0xE7D21004 , /* ldrb r1, [r2, r4] */
0xE59F7030 , /* ldr r7, CRC32XOR */
0xE0200C01 , /* eor r0, r0, r1, asl 24 */
0xE3A05000 , /* mov r5, #0 */
/* loop: */
0xE3500000 , /* cmp r0, #0 */
0xE1A06080 , /* mov r6, r0, asl #1 */
0xE2855001 , /* add r5, r5, #1 */
0xE1A00006 , /* mov r0, r6 */
0xB0260007 , /* eorlt r0, r6, r7 */
0xE3550008 , /* cmp r5, #8 */
0x1AFFFFF8 , /* bne loop */
0xE2844001 , /* add r4, r4, #1 */
/* ncomp: */
0xE1540003 , /* cmp r4, r3 */
0x1AFFFFF1 , /* bne nbyte */
/* end: */
0xEAFFFFFE , /* b end */
/* CRC32XOR: */
0x04C11DB7 /* .word 0x04C11DB7 */
} ;
retval = target_alloc_working_area ( target ,
sizeof ( arm_crc_code ) , & crc_algorithm ) ;
if ( retval ! = ERROR_OK )
return retval ;
/* convert code into a buffer in target endianness */
for ( i = 0 ; i < DIM ( arm_crc_code ) ; i + + ) {
retval = target_write_u32 ( target ,
crc_algorithm - > address + i * sizeof ( uint32_t ) ,
arm_crc_code [ i ] ) ;
if ( retval ! = ERROR_OK )
return retval ;
}
armv4_5_info . common_magic = ARMV4_5_COMMON_MAGIC ;
armv4_5_info . core_mode = ARMV4_5_MODE_SVC ;
armv4_5_info . core_state = ARMV4_5_STATE_ARM ;
init_reg_param ( & reg_params [ 0 ] , " r0 " , 32 , PARAM_IN_OUT ) ;
init_reg_param ( & reg_params [ 1 ] , " r1 " , 32 , PARAM_OUT ) ;
buf_set_u32 ( reg_params [ 0 ] . value , 0 , 32 , address ) ;
buf_set_u32 ( reg_params [ 1 ] . value , 0 , 32 , count ) ;
/* 20 second timeout/megabyte */
int timeout = 20000 * ( 1 + ( count / ( 1024 * 1024 ) ) ) ;
retval = target_run_algorithm ( target , 0 , NULL , 2 , reg_params ,
crc_algorithm - > address ,
crc_algorithm - > address + sizeof ( arm_crc_code ) - 8 ,
timeout , & armv4_5_info ) ;
if ( retval ! = ERROR_OK ) {
LOG_ERROR ( " error executing ARM crc algorithm " ) ;
destroy_reg_param ( & reg_params [ 0 ] ) ;
destroy_reg_param ( & reg_params [ 1 ] ) ;
target_free_working_area ( target , crc_algorithm ) ;
return retval ;
}
* checksum = buf_get_u32 ( reg_params [ 0 ] . value , 0 , 32 ) ;
destroy_reg_param ( & reg_params [ 0 ] ) ;
destroy_reg_param ( & reg_params [ 1 ] ) ;
target_free_working_area ( target , crc_algorithm ) ;
return ERROR_OK ;
}
/**
* Runs ARM code in the target to check whether a memory block holds
* all ones . NOR flash which has been erased , and thus may be written ,
* holds all ones .
*
* \ todo On ARMv5 + , rely on BKPT termination for reduced overhead .
*/
int arm_blank_check_memory ( struct target * target ,
uint32_t address , uint32_t count , uint32_t * blank )
{
struct working_area * check_algorithm ;
struct reg_param reg_params [ 3 ] ;
struct armv4_5_algorithm armv4_5_info ;
int retval ;
uint32_t i ;
static const uint32_t check_code [ ] = {
/* loop: */
0xe4d03001 , /* ldrb r3, [r0], #1 */
0xe0022003 , /* and r2, r2, r3 */
0xe2511001 , /* subs r1, r1, #1 */
0x1afffffb , /* bne loop */
/* end: */
0xeafffffe /* b end */
} ;
/* make sure we have a working area */
retval = target_alloc_working_area ( target ,
sizeof ( check_code ) , & check_algorithm ) ;
if ( retval ! = ERROR_OK )
return retval ;
/* convert code into a buffer in target endianness */
for ( i = 0 ; i < DIM ( check_code ) ; i + + ) {
retval = target_write_u32 ( target ,
check_algorithm - > address
+ i * sizeof ( uint32_t ) ,
check_code [ i ] ) ;
if ( retval ! = ERROR_OK )
return retval ;
}
armv4_5_info . common_magic = ARMV4_5_COMMON_MAGIC ;
armv4_5_info . core_mode = ARMV4_5_MODE_SVC ;
armv4_5_info . core_state = ARMV4_5_STATE_ARM ;
init_reg_param ( & reg_params [ 0 ] , " r0 " , 32 , PARAM_OUT ) ;
buf_set_u32 ( reg_params [ 0 ] . value , 0 , 32 , address ) ;
init_reg_param ( & reg_params [ 1 ] , " r1 " , 32 , PARAM_OUT ) ;
buf_set_u32 ( reg_params [ 1 ] . value , 0 , 32 , count ) ;
init_reg_param ( & reg_params [ 2 ] , " r2 " , 32 , PARAM_IN_OUT ) ;
buf_set_u32 ( reg_params [ 2 ] . value , 0 , 32 , 0xff ) ;
retval = target_run_algorithm ( target , 0 , NULL , 3 , reg_params ,
check_algorithm - > address ,
check_algorithm - > address + sizeof ( check_code ) - 4 ,
10000 , & armv4_5_info ) ;
if ( retval ! = ERROR_OK ) {
destroy_reg_param ( & reg_params [ 0 ] ) ;
destroy_reg_param ( & reg_params [ 1 ] ) ;
destroy_reg_param ( & reg_params [ 2 ] ) ;
target_free_working_area ( target , check_algorithm ) ;
return retval ;
}
* blank = buf_get_u32 ( reg_params [ 2 ] . value , 0 , 32 ) ;
destroy_reg_param ( & reg_params [ 0 ] ) ;
destroy_reg_param ( & reg_params [ 1 ] ) ;
destroy_reg_param ( & reg_params [ 2 ] ) ;
target_free_working_area ( target , check_algorithm ) ;
return ERROR_OK ;
}
2009-11-13 12:11:13 -06:00
int armv4_5_init_arch_info ( struct target * target , struct arm * 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 ;
}