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 12:19:33 -06:00
# include "arm_jtag.h"
2009-11-16 02:34:57 -06:00
# include "breakpoints.h"
2009-05-10 23:46:21 -05:00
# include "arm_disassembler.h"
2009-12-03 06:14:25 -06:00
# include <helper/binarybuffer.h>
2009-11-16 02:35:05 -06:00
# include "algorithm.h"
2009-11-16 02:35:14 -06:00
# include "register.h"
2006-06-02 05:36:31 -05:00
2009-11-22 05:37:21 -06:00
/* offsets into armv4_5 core register cache */
enum {
// ARMV4_5_CPSR = 31,
ARMV4_5_SPSR_FIQ = 32 ,
ARMV4_5_SPSR_IRQ = 33 ,
ARMV4_5_SPSR_SVC = 34 ,
ARMV4_5_SPSR_ABT = 35 ,
ARMV4_5_SPSR_UND = 36 ,
ARM_SPSR_MON = 39 ,
} ;
2009-11-18 17:31:24 -06:00
static const uint8_t arm_usr_indices [ 17 ] = {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , ARMV4_5_CPSR ,
} ;
static const uint8_t arm_fiq_indices [ 8 ] = {
16 , 17 , 18 , 19 , 20 , 21 , 22 , ARMV4_5_SPSR_FIQ ,
} ;
static const uint8_t arm_irq_indices [ 3 ] = {
23 , 24 , ARMV4_5_SPSR_IRQ ,
} ;
static const uint8_t arm_svc_indices [ 3 ] = {
25 , 26 , ARMV4_5_SPSR_SVC ,
} ;
static const uint8_t arm_abt_indices [ 3 ] = {
27 , 28 , ARMV4_5_SPSR_ABT ,
} ;
static const uint8_t arm_und_indices [ 3 ] = {
29 , 30 , ARMV4_5_SPSR_UND ,
} ;
static const uint8_t arm_mon_indices [ 3 ] = {
37 , 38 , ARM_SPSR_MON ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-18 01:50:23 -06:00
static const struct {
const char * name ;
2009-11-18 17:31:24 -06:00
unsigned short psr ;
/* For user and system modes, these list indices for all registers.
* otherwise they ' re just indices for the shadow registers and SPSR .
*/
unsigned short n_indices ;
const uint8_t * indices ;
2009-11-18 01:50:23 -06:00
} arm_mode_data [ ] = {
/* Seven modes are standard from ARM7 on. "System" and "User" share
* the same registers ; other modes shadow from 3 to 8 registers .
*/
{
. name = " User " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_USR ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_usr_indices ) ,
. indices = arm_usr_indices ,
2009-11-18 01:50:23 -06:00
} ,
{
. name = " FIQ " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_FIQ ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_fiq_indices ) ,
. indices = arm_fiq_indices ,
2009-11-18 01:50:23 -06:00
} ,
{
. name = " Supervisor " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_SVC ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_svc_indices ) ,
. indices = arm_svc_indices ,
2009-11-18 01:50:23 -06:00
} ,
{
. name = " Abort " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_ABT ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_abt_indices ) ,
. indices = arm_abt_indices ,
2009-11-18 01:50:23 -06:00
} ,
{
. name = " IRQ " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_IRQ ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_irq_indices ) ,
. indices = arm_irq_indices ,
2009-11-18 01:50:23 -06:00
} ,
{
2009-11-18 17:31:24 -06:00
. name = " Undefined instruction " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_UND ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_und_indices ) ,
. indices = arm_und_indices ,
2009-11-18 01:50:23 -06:00
} ,
{
. name = " System " ,
2009-12-04 21:21:14 -06:00
. psr = ARM_MODE_SYS ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_usr_indices ) ,
. indices = arm_usr_indices ,
2009-11-18 01:50:23 -06:00
} ,
/* TrustZone "Security Extensions" add a secure monitor mode.
* This is distinct from a " debug monitor " which can support
* non - halting debug , in conjunction with some debuggers .
*/
{
. name = " Secure Monitor " ,
. psr = ARM_MODE_MON ,
2009-11-18 17:31:24 -06:00
. n_indices = ARRAY_SIZE ( arm_mon_indices ) ,
. indices = arm_mon_indices ,
2009-11-18 01:50:23 -06:00
} ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-18 01:50:23 -06:00
/** Map PSR mode bits to the name of an ARM processor operating mode. */
const char * arm_mode_name ( unsigned psr_mode )
{
2009-11-18 01:50:26 -06:00
for ( unsigned i = 0 ; i < ARRAY_SIZE ( arm_mode_data ) ; i + + ) {
2009-11-18 01:50:23 -06:00
if ( arm_mode_data [ i ] . psr = = psr_mode )
return arm_mode_data [ i ] . name ;
}
LOG_ERROR ( " unrecognized psr mode: %#02x " , psr_mode ) ;
return " UNRECOGNIZED " ;
}
2009-11-16 17:27:36 -06:00
2009-11-18 01:50:26 -06:00
/** Return true iff the parameter denotes a valid ARM processor mode. */
bool is_arm_mode ( unsigned psr_mode )
{
for ( unsigned i = 0 ; i < ARRAY_SIZE ( arm_mode_data ) ; i + + ) {
if ( arm_mode_data [ i ] . psr = = psr_mode )
return true ;
}
return false ;
}
/** Map PSR mode bits to linear number indexing armv4_5_core_reg_map */
2009-12-04 21:33:33 -06:00
int arm_mode_to_number ( enum arm_mode mode )
2009-11-16 17:27:36 -06:00
{
switch ( mode ) {
2009-12-04 21:21:14 -06:00
case ARM_MODE_ANY :
2009-11-16 17:27:36 -06:00
/* map MODE_ANY to user mode */
2009-12-04 21:21:14 -06:00
case ARM_MODE_USR :
2009-11-16 17:27:36 -06:00
return 0 ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_FIQ :
2009-11-16 17:27:36 -06:00
return 1 ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_IRQ :
2009-11-16 17:27:36 -06:00
return 2 ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_SVC :
2009-11-16 17:27:36 -06:00
return 3 ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_ABT :
2009-11-16 17:27:36 -06:00
return 4 ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_UND :
2009-11-16 17:27:36 -06:00
return 5 ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_SYS :
2009-11-16 17:27:36 -06:00
return 6 ;
2009-11-18 15:23:00 -06:00
case ARM_MODE_MON :
return 7 ;
2009-11-16 17:27:36 -06:00
default :
LOG_ERROR ( " invalid mode value encountered %d " , mode ) ;
return - 1 ;
}
}
2009-11-18 01:50:26 -06:00
/** Map linear number indexing armv4_5_core_reg_map to PSR mode bits. */
2009-12-04 21:33:33 -06:00
enum arm_mode armv4_5_number_to_mode ( int number )
2009-11-16 17:27:36 -06:00
{
switch ( number ) {
case 0 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_USR ;
2009-11-16 17:27:36 -06:00
case 1 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_FIQ ;
2009-11-16 17:27:36 -06:00
case 2 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_IRQ ;
2009-11-16 17:27:36 -06:00
case 3 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_SVC ;
2009-11-16 17:27:36 -06:00
case 4 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_ABT ;
2009-11-16 17:27:36 -06:00
case 5 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_UND ;
2009-11-16 17:27:36 -06:00
case 6 :
2009-12-04 21:21:14 -06:00
return ARM_MODE_SYS ;
2009-11-18 15:23:00 -06:00
case 7 :
return ARM_MODE_MON ;
2009-11-16 17:27:36 -06:00
default :
LOG_ERROR ( " mode index out of bounds %d " , number ) ;
2009-12-04 21:21:14 -06:00
return ARM_MODE_ANY ;
2009-11-16 17:27:36 -06:00
}
}
2008-05-19 07:39:06 -05:00
2009-12-04 21:39:25 -06:00
const char * arm_state_strings [ ] =
2006-06-02 05:36:31 -05:00
{
2009-11-19 04:33:01 -06:00
" ARM " , " Thumb " , " Jazelle " , " ThumbEE " ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-19 15:23:08 -06:00
/* Templates for ARM core registers.
*
* NOTE : offsets in this table are coupled to the arm_mode_data
* table above , the armv4_5_core_reg_map array below , and also to
2009-11-22 05:37:21 -06:00
* the ARMV4_5_CPSR symbol ( which should vanish after ARM11 updates ) .
2009-11-19 15:23:08 -06:00
*/
static const struct {
/* The name is used for e.g. the "regs" command. */
const char * name ;
/* The {cookie, mode} tuple uniquely identifies one register.
* In a given mode , cookies 0. .15 map to registers R0 . . R15 ,
* with R13 . . R15 usually called SP , LR , PC .
*
* MODE_ANY is used as * input * to the mapping , and indicates
* various special cases ( sigh ) and errors .
*
* Cookie 16 is ( currently ) confusing , since it indicates
* CPSR - or - SPSR depending on whether ' mode ' is MODE_ANY .
* ( Exception modes have both CPSR and SPSR registers . . . )
*/
unsigned cookie ;
2009-12-04 21:33:33 -06:00
enum arm_mode mode ;
2009-11-19 15:23:08 -06:00
} arm_core_regs [ ] = {
2009-11-22 05:38:34 -06:00
/* IMPORTANT: we guarantee that the first eight cached registers
* correspond to r0 . . r7 , and the fifteenth to PC , so that callers
* don ' t need to map them .
*/
2009-12-04 21:21:14 -06:00
{ . name = " r0 " , . cookie = 0 , . mode = ARM_MODE_ANY , } ,
{ . name = " r1 " , . cookie = 1 , . mode = ARM_MODE_ANY , } ,
{ . name = " r2 " , . cookie = 2 , . mode = ARM_MODE_ANY , } ,
{ . name = " r3 " , . cookie = 3 , . mode = ARM_MODE_ANY , } ,
{ . name = " r4 " , . cookie = 4 , . mode = ARM_MODE_ANY , } ,
{ . name = " r5 " , . cookie = 5 , . mode = ARM_MODE_ANY , } ,
{ . name = " r6 " , . cookie = 6 , . mode = ARM_MODE_ANY , } ,
{ . name = " r7 " , . cookie = 7 , . mode = ARM_MODE_ANY , } ,
2009-11-19 15:23:08 -06:00
/* NOTE: regs 8..12 might be shadowed by FIQ ... flagging
2009-11-22 05:38:34 -06:00
* them as MODE_ANY creates special cases . ( ANY means
* " not mapped " elsewhere ; here it ' s " everything but FIQ " . )
2009-11-19 15:23:08 -06:00
*/
2009-12-04 21:21:14 -06:00
{ . name = " r8 " , . cookie = 8 , . mode = ARM_MODE_ANY , } ,
{ . name = " r9 " , . cookie = 9 , . mode = ARM_MODE_ANY , } ,
{ . name = " r10 " , . cookie = 10 , . mode = ARM_MODE_ANY , } ,
{ . name = " r11 " , . cookie = 11 , . mode = ARM_MODE_ANY , } ,
{ . name = " r12 " , . cookie = 12 , . mode = ARM_MODE_ANY , } ,
2009-11-19 15:23:08 -06:00
/* NOTE all MODE_USR registers are equivalent to MODE_SYS ones */
2009-12-04 21:21:14 -06:00
{ . name = " sp_usr " , . cookie = 13 , . mode = ARM_MODE_USR , } ,
{ . name = " lr_usr " , . cookie = 14 , . mode = ARM_MODE_USR , } ,
2009-11-19 15:23:08 -06:00
2009-11-22 05:38:34 -06:00
/* guaranteed to be at index 15 */
2009-12-04 21:21:14 -06:00
{ . name = " pc " , . cookie = 15 , . mode = ARM_MODE_ANY , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " r8_fiq " , . cookie = 8 , . mode = ARM_MODE_FIQ , } ,
{ . name = " r9_fiq " , . cookie = 9 , . mode = ARM_MODE_FIQ , } ,
{ . name = " r10_fiq " , . cookie = 10 , . mode = ARM_MODE_FIQ , } ,
{ . name = " r11_fiq " , . cookie = 11 , . mode = ARM_MODE_FIQ , } ,
{ . name = " r12_fiq " , . cookie = 12 , . mode = ARM_MODE_FIQ , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " sp_fiq " , . cookie = 13 , . mode = ARM_MODE_FIQ , } ,
{ . name = " lr_fiq " , . cookie = 14 , . mode = ARM_MODE_FIQ , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " sp_irq " , . cookie = 13 , . mode = ARM_MODE_IRQ , } ,
{ . name = " lr_irq " , . cookie = 14 , . mode = ARM_MODE_IRQ , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " sp_svc " , . cookie = 13 , . mode = ARM_MODE_SVC , } ,
{ . name = " lr_svc " , . cookie = 14 , . mode = ARM_MODE_SVC , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " sp_abt " , . cookie = 13 , . mode = ARM_MODE_ABT , } ,
{ . name = " lr_abt " , . cookie = 14 , . mode = ARM_MODE_ABT , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " sp_und " , . cookie = 13 , . mode = ARM_MODE_UND , } ,
{ . name = " lr_und " , . cookie = 14 , . mode = ARM_MODE_UND , } ,
2009-11-19 15:23:08 -06:00
2009-12-04 21:21:14 -06:00
{ . name = " cpsr " , . cookie = 16 , . mode = ARM_MODE_ANY , } ,
{ . name = " spsr_fiq " , . cookie = 16 , . mode = ARM_MODE_FIQ , } ,
{ . name = " spsr_irq " , . cookie = 16 , . mode = ARM_MODE_IRQ , } ,
{ . name = " spsr_svc " , . cookie = 16 , . mode = ARM_MODE_SVC , } ,
{ . name = " spsr_abt " , . cookie = 16 , . mode = ARM_MODE_ABT , } ,
{ . name = " spsr_und " , . cookie = 16 , . mode = ARM_MODE_UND , } ,
2009-11-19 15:23:08 -06:00
2009-12-02 13:31:32 -06:00
{ . name = " sp_mon " , . cookie = 13 , . mode = ARM_MODE_MON , } ,
{ . name = " lr_mon " , . cookie = 14 , . mode = ARM_MODE_MON , } ,
2009-11-19 15:23:08 -06:00
{ . name = " spsr_mon " , . cookie = 16 , . mode = ARM_MODE_MON , } ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-19 15:23:08 -06:00
/* map core mode (USR, FIQ, ...) and register number to
* indices into the register cache
*/
2009-11-18 15:23:00 -06:00
const int armv4_5_core_reg_map [ 8 ] [ 17 ] =
2006-06-02 05:36:31 -05:00
{
{ /* USR */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 31
} ,
2009-11-18 15:23:00 -06:00
{ /* FIQ (8 shadows of USR, vs normal 3) */
2006-06-02 05:36:31 -05:00
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
} ,
2009-11-18 15:23:00 -06:00
{ /* SYS (same registers as USR) */
2006-06-02 05:36:31 -05:00
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 31
2009-11-18 15:23:00 -06:00
} ,
{ /* MON */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 37 , 38 , 15 , 39 ,
2006-06-02 05:36:31 -05:00
}
} ;
2009-11-22 05:38:34 -06:00
/**
* Configures host - side ARM records to reflect the specified CPSR .
* Later , code can use arm_reg_current ( ) to map register numbers
* according to how they are exposed by this mode .
*/
void arm_set_cpsr ( struct arm * arm , uint32_t cpsr )
{
2009-12-04 21:33:33 -06:00
enum arm_mode mode = cpsr & 0x1f ;
2009-11-22 05:38:34 -06:00
int num ;
/* NOTE: this may be called very early, before the register
* cache is set up . We can ' t defend against many errors , in
* particular against CPSRs that aren ' t valid * here * . . .
*/
if ( arm - > cpsr ) {
buf_set_u32 ( arm - > cpsr - > value , 0 , 32 , cpsr ) ;
arm - > cpsr - > valid = 1 ;
arm - > cpsr - > dirty = 0 ;
}
arm - > core_mode = mode ;
/* mode_to_number() warned; set up a somewhat-sane mapping */
2009-12-04 21:33:33 -06:00
num = arm_mode_to_number ( mode ) ;
2009-11-22 05:38:34 -06:00
if ( num < 0 ) {
2009-12-04 21:21:14 -06:00
mode = ARM_MODE_USR ;
2009-11-22 05:38:34 -06:00
num = 0 ;
}
arm - > map = & armv4_5_core_reg_map [ num ] [ 0 ] ;
2009-12-04 21:21:14 -06:00
arm - > spsr = ( mode = = ARM_MODE_USR | | mode = = ARM_MODE_SYS )
2009-11-22 05:38:34 -06:00
? NULL
: arm - > core_cache - > reg_list + arm - > map [ 16 ] ;
2009-11-22 05:41:14 -06:00
/* Older ARMs won't have the J bit */
2009-12-04 21:39:25 -06:00
enum arm_state state ;
2009-11-22 05:41:14 -06:00
if ( cpsr & ( 1 < < 5 ) ) { /* T */
if ( cpsr & ( 1 < < 24 ) ) { /* J */
LOG_WARNING ( " ThumbEE -- incomplete support " ) ;
state = ARM_STATE_THUMB_EE ;
} else
2009-12-04 21:14:48 -06:00
state = ARM_STATE_THUMB ;
2009-11-22 05:41:14 -06:00
} else {
if ( cpsr & ( 1 < < 24 ) ) { /* J */
LOG_ERROR ( " Jazelle state handling is BROKEN! " ) ;
2009-12-04 21:14:48 -06:00
state = ARM_STATE_JAZELLE ;
2009-11-22 05:41:14 -06:00
} else
2009-12-04 21:14:48 -06:00
state = ARM_STATE_ARM ;
2009-11-22 05:41:14 -06:00
}
arm - > core_state = state ;
2009-11-25 18:18:22 -06:00
LOG_DEBUG ( " set CPSR %#8.8x: %s mode, %s state " , ( unsigned ) cpsr ,
arm_mode_name ( mode ) ,
2009-12-04 21:39:25 -06:00
arm_state_strings [ arm - > core_state ] ) ;
2009-11-22 05:38:34 -06:00
}
/**
* Returns handle to the register currently mapped to a given number .
* Someone must have called arm_set_cpsr ( ) before .
*
* \ param arm This core ' s state and registers are used .
* \ param regnum From 0. .15 corresponding to R0 . . R14 and PC .
* Note that R0 . . R7 don ' t require mapping ; you may access those
* as the first eight entries in the register cache . Likewise
* R15 ( PC ) doesn ' t need mapping ; you may also access it directly .
* However , R8 . . R14 , and SPSR ( arm - > spsr ) * must * be mapped .
* CPSR ( arm - > cpsr ) is also not mapped .
*/
struct reg * arm_reg_current ( struct arm * arm , unsigned regnum )
{
struct reg * r ;
if ( regnum > 16 )
return NULL ;
r = arm - > core_cache - > reg_list + arm - > map [ regnum ] ;
/* e.g. invalid CPSR said "secure monitor" mode on a core
* that doesn ' t support it . . .
*/
if ( ! r ) {
LOG_ERROR ( " Invalid CPSR mode " ) ;
r = arm - > core_cache - > reg_list + regnum ;
}
return r ;
}
2009-11-18 01:50:17 -06:00
static const uint8_t arm_gdb_dummy_fp_value [ 12 ] ;
/**
* Dummy FPA registers are required to support GDB on ARM .
* Register packets require eight obsolete FPA register values .
* Modern ARM cores use Vector Floating Point ( VFP ) , if they
* have any floating point support . VFP is not FPA - compatible .
*/
struct reg arm_gdb_dummy_fp_reg =
2006-06-02 05:36:31 -05:00
{
2009-11-18 01:50:17 -06:00
. name = " GDB dummy FPA register " ,
. value = ( uint8_t * ) arm_gdb_dummy_fp_value ,
2009-11-13 18:22:36 -06:00
. valid = 1 ,
. size = 96 ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-18 01:50:17 -06:00
static const uint8_t arm_gdb_dummy_fps_value [ 4 ] ;
2006-06-02 05:36:31 -05:00
2009-11-18 01:50:17 -06:00
/**
* Dummy FPA status registers are required to support GDB on ARM .
* Register packets require an obsolete FPA status register .
*/
struct reg arm_gdb_dummy_fps_reg =
2006-06-02 05:36:31 -05:00
{
2009-11-18 01:50:17 -06:00
. name = " GDB dummy FPA status register " ,
. value = ( uint8_t * ) arm_gdb_dummy_fps_value ,
2009-11-13 18:22:36 -06:00
. valid = 1 ,
. size = 32 ,
2006-06-02 05:36:31 -05:00
} ;
2009-11-18 01:50:17 -06:00
static void arm_gdb_dummy_init ( void ) __attribute__ ( ( constructor ) ) ;
static void arm_gdb_dummy_init ( void )
{
register_init_dummy ( & arm_gdb_dummy_fp_reg ) ;
register_init_dummy ( & arm_gdb_dummy_fps_reg ) ;
}
2009-11-18 16:49:22 -06:00
static int armv4_5_get_core_reg ( struct reg * reg )
2006-06-02 05:36:31 -05:00
{
int retval ;
2009-11-20 18:27:24 -06:00
struct arm_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
2009-11-20 18:27:24 -06:00
retval = armv4_5 - > armv4_5_common - > read_core_reg ( target , reg , armv4_5 - > num , armv4_5 - > mode ) ;
if ( retval = = ERROR_OK ) {
2009-11-18 16:49:22 -06:00
reg - > valid = 1 ;
2009-11-20 18:27:24 -06:00
reg - > dirty = 0 ;
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return retval ;
}
2009-11-18 16:49:22 -06:00
static int armv4_5_set_core_reg ( struct reg * reg , uint8_t * buf )
2006-06-02 05:36:31 -05:00
{
2009-11-20 18:27:24 -06:00
struct arm_reg * armv4_5 = reg - > arch_info ;
2009-11-13 12:11:13 -06:00
struct target * target = armv4_5 - > target ;
2009-12-04 21:43:03 -06:00
struct arm * armv4_5_target = target_to_arm ( 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 )
{
2009-11-18 16:49:22 -06: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
2009-11-20 18:27:24 -06:00
/* Except for CPSR, the "reg" command exposes a writeback model
* for the register cache .
*/
2009-11-22 05:41:14 -06:00
if ( reg = = armv4_5_target - > cpsr ) {
arm_set_cpsr ( armv4_5_target , value ) ;
2009-11-20 18:27:24 -06:00
2009-11-22 05:41:14 -06:00
/* Older cores need help to be in ARM mode during halt
* mode debug , so we clear the J and T bits if we flush .
* For newer cores ( v6 / v7a / v7r ) we don ' t need that , but
* it won ' t hurt since CPSR is always flushed anyway .
2009-11-20 18:27:24 -06:00
*/
2009-11-22 05:41:14 -06:00
if ( armv4_5_target - > core_mode ! =
2009-12-04 21:33:33 -06:00
( enum arm_mode ) ( value & 0x1f ) ) {
2009-11-18 01:50:23 -06:00
LOG_DEBUG ( " changing ARM core mode to '%s' " ,
arm_mode_name ( value & 0x1f ) ) ;
2009-11-22 05:41:14 -06:00
value & = ~ ( ( 1 < < 24 ) | ( 1 < < 5 ) ) ;
2009-11-20 18:27:24 -06:00
armv4_5_target - > write_core_reg ( target , reg ,
2009-12-04 21:21:14 -06:00
16 , ARM_MODE_ANY , value ) ;
2007-04-11 09:25:12 -05:00
}
2009-11-22 05:41:14 -06:00
} else {
buf_set_u32 ( reg - > value , 0 , 32 , value ) ;
reg - > valid = 1 ;
2006-09-28 05:41:43 -05:00
}
2009-11-22 05:41:14 -06:00
reg - > dirty = 1 ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2009-11-17 11:06:45 -06:00
static const struct reg_arch_type arm_reg_type = {
. get = armv4_5_get_core_reg ,
. set = armv4_5_set_core_reg ,
} ;
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
{
2009-11-19 15:23:08 -06:00
int num_regs = ARRAY_SIZE ( arm_core_regs ) ;
2009-11-13 10:44:08 -06:00
struct reg_cache * cache = malloc ( sizeof ( struct reg_cache ) ) ;
2009-11-18 15:23:00 -06:00
struct reg * reg_list = calloc ( num_regs , sizeof ( struct reg ) ) ;
2009-11-20 18:27:24 -06:00
struct arm_reg * arch_info = calloc ( num_regs , sizeof ( struct arm_reg ) ) ;
2006-06-02 05:36:31 -05:00
int i ;
2008-10-03 08:25:33 -05:00
2009-11-18 15:23:00 -06:00
if ( ! cache | | ! reg_list | | ! arch_info ) {
free ( cache ) ;
free ( reg_list ) ;
free ( arch_info ) ;
return NULL ;
}
cache - > name = " ARM registers " ;
2006-06-02 05:36:31 -05:00
cache - > next = NULL ;
cache - > reg_list = reg_list ;
2009-11-18 15:23:00 -06:00
cache - > num_regs = 0 ;
2008-10-03 08:25:33 -05:00
2009-11-18 15:23:00 -06:00
for ( i = 0 ; i < num_regs ; i + + )
2006-06-02 05:36:31 -05:00
{
2009-11-18 15:23:00 -06:00
/* Skip registers this core doesn't expose */
2009-11-19 15:23:08 -06:00
if ( arm_core_regs [ i ] . mode = = ARM_MODE_MON
2009-11-18 15:23:00 -06:00
& & armv4_5_common - > core_type ! = ARM_MODE_MON )
continue ;
/* REVISIT handle Cortex-M, which only shadows R13/SP */
2009-11-19 15:23:08 -06:00
arch_info [ i ] . num = arm_core_regs [ i ] . cookie ;
arch_info [ i ] . mode = arm_core_regs [ i ] . mode ;
2006-06-02 05:36:31 -05:00
arch_info [ i ] . target = target ;
arch_info [ i ] . armv4_5_common = armv4_5_common ;
2009-11-19 15:23:08 -06:00
reg_list [ i ] . name = ( char * ) arm_core_regs [ i ] . name ;
2006-06-02 05:36:31 -05:00
reg_list [ i ] . size = 32 ;
2009-11-19 15:23:49 -06:00
reg_list [ i ] . value = & arch_info [ i ] . value ;
2009-11-17 11:06:45 -06:00
reg_list [ i ] . type = & arm_reg_type ;
2006-06-02 05:36:31 -05:00
reg_list [ i ] . arch_info = & arch_info [ i ] ;
2009-11-18 15:23:00 -06:00
cache - > num_regs + + ;
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2009-11-22 05:37:21 -06:00
armv4_5_common - > cpsr = reg_list + ARMV4_5_CPSR ;
2009-11-20 18:27:24 -06:00
armv4_5_common - > core_cache = cache ;
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-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( target ) ;
2008-10-03 08:25:33 -05:00
2009-12-04 21:46:44 -06:00
if ( armv4_5 - > common_magic ! = ARM_COMMON_MAGIC )
2006-06-02 05:36:31 -05:00
{
2009-12-04 18:51:48 -06:00
LOG_ERROR ( " BUG: called for a non-ARM target " ) ;
2009-11-16 19:52:50 -06:00
return ERROR_FAIL ;
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2009-12-04 18:51:48 -06: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 " %s " ,
2009-12-04 21:39:25 -06:00
arm_state_strings [ armv4_5 - > core_state ] ,
2009-12-04 18:51:48 -06:00
Jim_Nvp_value2name_simple ( nvp_target_debug_reason ,
target - > debug_reason ) - > name ,
2009-11-18 01:50:23 -06:00
arm_mode_name ( armv4_5 - > core_mode ) ,
2009-11-22 05:37:21 -06:00
buf_get_u32 ( armv4_5 - > cpsr - > value , 0 , 32 ) ,
2009-12-04 18:51:48 -06:00
buf_get_u32 ( armv4_5 - > core_cache - > reg_list [ 15 ] . value ,
0 , 32 ) ,
armv4_5 - > is_semihosting ? " , semihosting " : " " ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}
2009-11-18 01:50:26 -06:00
# define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \
cache - > reg_list [ armv4_5_core_reg_map [ mode ] [ num ] ]
2009-11-10 01:56:52 -06:00
COMMAND_HANDLER ( handle_armv4_5_reg_command )
2006-06-02 05:36:31 -05:00
{
2009-11-15 07:57:37 -06:00
struct target * target = get_current_target ( CMD_CTX ) ;
2009-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( target ) ;
2009-11-18 17:31:24 -06:00
unsigned num_regs ;
struct reg * regs ;
2008-10-03 08:25:33 -05:00
2009-11-16 18:36:09 -06:00
if ( ! is_arm ( armv4_5 ) )
2006-06-02 05:36:31 -05:00
{
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " current target isn't an ARM " ) ;
2009-11-16 18:36:09 -06:00
return ERROR_FAIL ;
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
if ( target - > state ! = TARGET_HALTED )
{
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " error: target must be halted for register accesses " ) ;
2009-11-18 17:31:24 -06:00
return ERROR_FAIL ;
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2009-11-18 01:50:26 -06:00
if ( ! is_arm_mode ( armv4_5 - > core_mode ) )
2008-05-19 14:02:36 -05:00
return ERROR_FAIL ;
2009-11-16 18:36:12 -06:00
if ( ! armv4_5 - > full_context ) {
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " error: target doesn't support %s " ,
2009-11-16 18:36:12 -06:00
CMD_NAME ) ;
return ERROR_FAIL ;
}
2009-11-18 17:31:24 -06:00
num_regs = armv4_5 - > core_cache - > num_regs ;
regs = armv4_5 - > core_cache - > reg_list ;
for ( unsigned mode = 0 ; mode < ARRAY_SIZE ( arm_mode_data ) ; mode + + ) {
const char * name ;
char * sep = " \n " ;
char * shadow = " " ;
/* label this bank of registers (or shadows) */
switch ( arm_mode_data [ mode ] . psr ) {
2009-12-04 21:21:14 -06:00
case ARM_MODE_SYS :
2009-11-18 17:31:24 -06:00
continue ;
2009-12-04 21:21:14 -06:00
case ARM_MODE_USR :
2009-11-18 17:31:24 -06:00
name = " System and User " ;
sep = " " ;
break ;
case ARM_MODE_MON :
if ( armv4_5 - > core_type ! = ARM_MODE_MON )
continue ;
/* FALLTHROUGH */
default :
name = arm_mode_data [ mode ] . name ;
shadow = " shadow " ;
break ;
}
command_print ( CMD_CTX , " %s%s mode %sregisters " ,
sep , name , shadow ) ;
/* display N rows of up to 4 registers each */
for ( unsigned i = 0 ; i < arm_mode_data [ mode ] . n_indices ; ) {
char output [ 80 ] ;
int output_len = 0 ;
for ( unsigned j = 0 ; j < 4 ; j + + , i + + ) {
uint32_t value ;
struct reg * reg = regs ;
if ( i > = arm_mode_data [ mode ] . n_indices )
break ;
reg + = arm_mode_data [ mode ] . indices [ i ] ;
/* REVISIT be smarter about faults... */
if ( ! reg - > valid )
armv4_5 - > full_context ( target ) ;
value = buf_get_u32 ( reg - > value , 0 , 32 ) ;
output_len + = snprintf ( output + output_len ,
sizeof ( output ) - output_len ,
2009-06-23 17:49:23 -05:00
" %8s: %8.8 " PRIx32 " " ,
2009-11-18 17:31:24 -06:00
reg - > name , value ) ;
}
command_print ( CMD_CTX , " %s " , output ) ;
2006-06-02 05:36:31 -05:00
}
}
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-15 07:57:37 -06:00
struct target * target = get_current_target ( CMD_CTX ) ;
2009-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( target ) ;
2008-10-03 08:25:33 -05:00
2009-11-16 18:36:09 -06:00
if ( ! is_arm ( armv4_5 ) )
2006-06-02 05:36:31 -05:00
{
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " current target isn't an ARM " ) ;
2009-11-16 18:36:09 -06:00
return ERROR_FAIL ;
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2009-11-15 06:57:12 -06:00
if ( CMD_ARGC > 0 )
2006-06-02 05:36:31 -05:00
{
2009-11-15 10:15:59 -06:00
if ( strcmp ( CMD_ARGV [ 0 ] , " arm " ) = = 0 )
2006-06-02 05:36:31 -05:00
{
2009-12-04 21:14:48 -06:00
armv4_5 - > core_state = ARM_STATE_ARM ;
2006-06-02 05:36:31 -05:00
}
2009-11-15 10:15:59 -06:00
if ( strcmp ( CMD_ARGV [ 0 ] , " thumb " ) = = 0 )
2006-06-02 05:36:31 -05:00
{
2009-12-04 21:14:48 -06:00
armv4_5 - > core_state = ARM_STATE_THUMB ;
2006-06-02 05:36:31 -05:00
}
}
2008-10-03 08:25:33 -05:00
2009-12-04 21:39:25 -06:00
command_print ( CMD_CTX , " core state: %s " , arm_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-15 07:57:37 -06:00
struct target * target = get_current_target ( CMD_CTX ) ;
2009-11-16 17:29:14 -06:00
struct arm * arm = target ? target_to_arm ( target ) : NULL ;
2009-06-18 02:08:52 -05:00
uint32_t address ;
2009-08-25 15:02:19 -05:00
int count = 1 ;
2006-08-31 07:41:49 -05:00
int thumb = 0 ;
2008-10-03 08:25:33 -05:00
2009-11-16 17:29:14 -06:00
if ( ! is_arm ( arm ) ) {
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " current target isn't an ARM " ) ;
2009-11-16 17:29:14 -06:00
return ERROR_FAIL ;
2006-06-12 11:49:49 -05:00
}
2008-10-03 08:25:33 -05:00
2009-11-15 06:57:12 -06:00
switch ( CMD_ARGC ) {
2009-08-25 15:02:19 -05:00
case 3 :
2009-11-15 10:15:59 -06:00
if ( strcmp ( CMD_ARGV [ 2 ] , " thumb " ) ! = 0 )
2009-08-25 15:02:19 -05:00
goto usage ;
thumb = 1 ;
/* FALL THROUGH */
case 2 :
2009-11-15 10:15:59 -06:00
COMMAND_PARSE_NUMBER ( int , CMD_ARGV [ 1 ] , count ) ;
2009-08-25 15:02:19 -05:00
/* FALL THROUGH */
case 1 :
2009-11-15 10:15:59 -06:00
COMMAND_PARSE_NUMBER ( u32 , CMD_ARGV [ 0 ] , address ) ;
2009-08-25 15:02:19 -05:00
if ( address & 0x01 ) {
if ( ! thumb ) {
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " Disassemble as Thumb " ) ;
2009-08-25 15:02:19 -05:00
thumb = 1 ;
}
address & = ~ 1 ;
}
break ;
default :
usage :
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX ,
2009-11-16 18:36:09 -06:00
" usage: arm disassemble <address> [<count> ['thumb']] " ) ;
2009-11-16 17:29:14 -06:00
count = 0 ;
retval = ERROR_FAIL ;
2006-06-12 11:49:49 -05:00
}
2008-10-03 08:25:33 -05:00
2009-11-16 17:29:14 -06:00
while ( count - - > 0 ) {
struct arm_instruction cur_instruction ;
if ( thumb ) {
/* Always use Thumb2 disassembly for best handling
* of 32 - bit BL / BLX , and to work with newer cores
* ( some ARMv6 , all ARMv7 ) that use Thumb2 .
*/
retval = thumb2_opcode ( target , address ,
& cur_instruction ) ;
if ( retval ! = ERROR_OK )
break ;
} else {
uint32_t opcode ;
retval = target_read_u32 ( target , address , & opcode ) ;
if ( retval ! = ERROR_OK )
break ;
retval = arm_evaluate_opcode ( opcode , address ,
& cur_instruction ) ! = ERROR_OK ;
if ( retval ! = ERROR_OK )
break ;
2008-10-14 06:06:30 -05:00
}
2009-11-15 07:57:37 -06:00
command_print ( CMD_CTX , " %s " , cur_instruction . text ) ;
2009-11-16 17:29:14 -06:00
address + = cur_instruction . instruction_size ;
2006-06-12 11:49:49 -05:00
}
2008-10-03 08:25:33 -05:00
2009-11-16 17:29:14 -06:00
return retval ;
2006-06-12 11:49:49 -05:00
}
2009-12-01 02:48:53 -06:00
static int jim_mcrmrc ( Jim_Interp * interp , int argc , Jim_Obj * const * argv )
{
struct command_context * context ;
struct target * target ;
struct arm * arm ;
int retval ;
context = Jim_GetAssocData ( interp , " context " ) ;
if ( context = = NULL ) {
LOG_ERROR ( " %s: no command context " , __func__ ) ;
return JIM_ERR ;
}
target = get_current_target ( context ) ;
if ( target = = NULL ) {
LOG_ERROR ( " %s: no current target " , __func__ ) ;
return JIM_ERR ;
}
if ( ! target_was_examined ( target ) ) {
LOG_ERROR ( " %s: not yet examined " , target_name ( target ) ) ;
return JIM_ERR ;
}
arm = target_to_arm ( target ) ;
if ( ! is_arm ( arm ) ) {
LOG_ERROR ( " %s: not an ARM " , target_name ( target ) ) ;
return JIM_ERR ;
}
if ( ( argc < 6 ) | | ( argc > 7 ) ) {
/* FIXME use the command name to verify # params... */
LOG_ERROR ( " %s: wrong number of arguments " , __func__ ) ;
return JIM_ERR ;
}
int cpnum ;
uint32_t op1 ;
uint32_t op2 ;
uint32_t CRn ;
uint32_t CRm ;
uint32_t value ;
long l ;
/* NOTE: parameter sequence matches ARM instruction set usage:
* MCR pNUM , op1 , rX , CRn , CRm , op2 ; write CP from rX
* MRC pNUM , op1 , rX , CRn , CRm , op2 ; read CP into rX
* The " rX " is necessarily omitted ; it uses Tcl mechanisms .
*/
retval = Jim_GetLong ( interp , argv [ 1 ] , & l ) ;
if ( retval ! = JIM_OK )
return retval ;
if ( l & ~ 0xf ) {
LOG_ERROR ( " %s: %s %d out of range " , __func__ ,
" coprocessor " , ( int ) l ) ;
return JIM_ERR ;
}
cpnum = l ;
retval = Jim_GetLong ( interp , argv [ 2 ] , & l ) ;
if ( retval ! = JIM_OK )
return retval ;
if ( l & ~ 0x7 ) {
LOG_ERROR ( " %s: %s %d out of range " , __func__ ,
" op1 " , ( int ) l ) ;
return JIM_ERR ;
}
op1 = l ;
retval = Jim_GetLong ( interp , argv [ 3 ] , & l ) ;
if ( retval ! = JIM_OK )
return retval ;
if ( l & ~ 0xf ) {
LOG_ERROR ( " %s: %s %d out of range " , __func__ ,
" CRn " , ( int ) l ) ;
return JIM_ERR ;
}
CRn = l ;
retval = Jim_GetLong ( interp , argv [ 4 ] , & l ) ;
if ( retval ! = JIM_OK )
return retval ;
if ( l & ~ 0xf ) {
LOG_ERROR ( " %s: %s %d out of range " , __func__ ,
" CRm " , ( int ) l ) ;
return JIM_ERR ;
}
CRm = l ;
retval = Jim_GetLong ( interp , argv [ 5 ] , & l ) ;
if ( retval ! = JIM_OK )
return retval ;
if ( l & ~ 0x7 ) {
LOG_ERROR ( " %s: %s %d out of range " , __func__ ,
" op2 " , ( int ) l ) ;
return JIM_ERR ;
}
op2 = l ;
value = 0 ;
/* FIXME don't assume "mrc" vs "mcr" from the number of params;
* that could easily be a typo ! Check both . . .
*
* FIXME change the call syntax here . . . simplest to just pass
* the MRC ( ) or MCR ( ) instruction to be executed . That will also
* let us support the " mrc2 " and " mcr2 " opcodes ( toggling one bit )
* if that ' s ever needed .
*/
if ( argc = = 7 ) {
retval = Jim_GetLong ( interp , argv [ 6 ] , & l ) ;
if ( retval ! = JIM_OK ) {
return retval ;
}
value = l ;
/* NOTE: parameters reordered! */
// ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2)
retval = arm - > mcr ( target , cpnum , op1 , op2 , CRn , CRm , value ) ;
if ( retval ! = ERROR_OK )
return JIM_ERR ;
} else {
/* NOTE: parameters reordered! */
// ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2)
retval = arm - > mrc ( target , cpnum , op1 , op2 , CRn , CRm , & value ) ;
if ( retval ! = ERROR_OK )
return JIM_ERR ;
Jim_SetResult ( interp , Jim_NewIntObj ( interp , value ) ) ;
}
return JIM_OK ;
}
2009-11-23 09:43:05 -06:00
static const struct command_registration arm_exec_command_handlers [ ] = {
{
. name = " reg " ,
. handler = & handle_armv4_5_reg_command ,
. mode = COMMAND_EXEC ,
. help = " display ARM core registers " ,
} ,
{
. name = " core_state " ,
. handler = & handle_armv4_5_core_state_command ,
. mode = COMMAND_EXEC ,
. usage = " <arm | thumb> " ,
. help = " display/change ARM core state " ,
} ,
{
. name = " disassemble " ,
. handler = & handle_armv4_5_disassemble_command ,
. mode = COMMAND_EXEC ,
. usage = " <address> [<count> ['thumb']] " ,
. help = " disassemble instructions " ,
} ,
2009-12-01 02:48:53 -06:00
{
. name = " mcr " ,
. mode = COMMAND_EXEC ,
. jim_handler = & jim_mcrmrc ,
. help = " write coprocessor register " ,
. usage = " cpnum op1 CRn op2 CRm value " ,
} ,
{
. name = " mrc " ,
. jim_handler = & jim_mcrmrc ,
. help = " read coprocessor register " ,
. usage = " cpnum op1 CRn op2 CRm " ,
} ,
2009-11-23 09:43:05 -06:00
COMMAND_REGISTRATION_DONE
} ;
2009-11-23 10:17:01 -06:00
const struct command_registration arm_command_handlers [ ] = {
2009-11-23 09:43:05 -06:00
{
. name = " arm " ,
. mode = COMMAND_ANY ,
. help = " ARM command group " ,
. chain = arm_exec_command_handlers ,
} ,
COMMAND_REGISTRATION_DONE
} ;
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-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( target ) ;
2006-06-02 05:36:31 -05:00
int i ;
2008-10-03 08:25:33 -05:00
2009-11-18 01:50:26 -06:00
if ( ! is_arm_mode ( armv4_5 - > core_mode ) )
2008-05-19 14:02:36 -05:00
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 + + )
2009-11-22 05:38:34 -06:00
( * reg_list ) [ i ] = arm_reg_current ( armv4_5 , i ) ;
2008-10-03 08:25:33 -05:00
2006-06-02 05:36:31 -05:00
for ( i = 16 ; i < 24 ; i + + )
2009-11-18 01:50:17 -06:00
( * reg_list ) [ i ] = & arm_gdb_dummy_fp_reg ;
2008-10-03 08:25:33 -05:00
2009-11-18 01:50:17 -06:00
( * reg_list ) [ 24 ] = & arm_gdb_dummy_fps_reg ;
2009-11-22 05:37:21 -06:00
( * reg_list ) [ 25 ] = 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-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( 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-25 18:18:22 -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-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( target ) ;
2009-11-13 10:41:07 -06:00
struct armv4_5_algorithm * armv4_5_algorithm_info = arch_info ;
2009-12-04 21:39:25 -06:00
enum arm_state core_state = armv4_5 - > core_state ;
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 ;
2009-11-25 18:18:22 -06:00
2008-04-03 09:00:17 -05:00
LOG_DEBUG ( " Running algorithm " ) ;
2008-10-03 08:25:33 -05:00
2009-12-04 21:46:44 -06:00
if ( armv4_5_algorithm_info - > common_magic ! = ARM_COMMON_MAGIC )
2006-06-02 05:36:31 -05:00
{
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
2009-11-18 01:50:26 -06:00
if ( ! is_arm_mode ( armv4_5 - > core_mode ) )
2008-05-19 14:02:36 -05:00
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 ;
}
2009-11-22 05:38:34 -06:00
/* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure;
* they ' ll be restored later .
*/
2006-06-02 05:36:31 -05:00
for ( i = 0 ; i < = 16 ; i + + )
{
2009-11-20 18:27:24 -06:00
struct reg * r ;
r = & ARMV4_5_CORE_REG_MODE ( armv4_5 - > core_cache ,
armv4_5_algorithm_info - > core_mode , i ) ;
if ( ! r - > valid )
armv4_5 - > read_core_reg ( target , r , i ,
armv4_5_algorithm_info - > core_mode ) ;
context [ i ] = buf_get_u32 ( r - > value , 0 , 32 ) ;
2006-06-02 05:36:31 -05:00
}
2009-11-22 05:37:21 -06:00
cpsr = buf_get_u32 ( 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 ) ;
2009-11-16 19:52:50 -06:00
return ERROR_INVALID_ARGUMENTS ;
2006-06-02 05:36:31 -05:00
}
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 ) ;
2009-11-16 19:52:50 -06:00
return ERROR_INVALID_ARGUMENTS ;
2006-06-02 05:36:31 -05:00
}
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 ;
2009-12-04 21:14:48 -06:00
if ( armv4_5 - > core_state = = ARM_STATE_ARM )
2006-06-02 05:36:31 -05:00
exit_breakpoint_size = 4 ;
2009-12-04 21:14:48 -06:00
else if ( armv4_5 - > core_state = = ARM_STATE_THUMB )
2006-06-02 05:36:31 -05:00
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 " ) ;
2009-11-16 19:52:50 -06:00
return ERROR_INVALID_ARGUMENTS ;
2006-06-02 05:36:31 -05:00
}
2008-10-03 08:25:33 -05:00
2009-12-04 21:21:14 -06:00
if ( armv4_5_algorithm_info - > core_mode ! = ARM_MODE_ANY )
2006-06-02 05:36:31 -05:00
{
2009-11-22 05:37:21 -06:00
LOG_DEBUG ( " setting core_mode: 0x%2.2x " ,
armv4_5_algorithm_info - > core_mode ) ;
buf_set_u32 ( armv4_5 - > cpsr - > value , 0 , 5 ,
armv4_5_algorithm_info - > core_mode ) ;
armv4_5 - > cpsr - > dirty = 1 ;
armv4_5 - > cpsr - > valid = 1 ;
2006-06-02 05:36:31 -05:00
}
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 ) ;
2009-11-16 19:52:50 -06:00
retval = ERROR_INVALID_ARGUMENTS ;
continue ;
2006-06-02 05:36:31 -05:00
}
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 ) ;
2009-11-16 19:52:50 -06:00
retval = ERROR_INVALID_ARGUMENTS ;
continue ;
2006-06-02 05:36:31 -05:00
}
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
2009-11-22 05:38:34 -06:00
/* restore everything we saved before (17 or 18 registers) */
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
}
2009-11-22 05:38:34 -06:00
arm_set_cpsr ( armv4_5 , cpsr ) ;
2009-11-22 05:37:21 -06:00
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 ;
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 */
2009-11-16 05:29:30 -06:00
for ( i = 0 ; i < ARRAY_SIZE ( arm_crc_code ) ; i + + ) {
2009-11-15 12:35:34 -06:00
retval = target_write_u32 ( target ,
crc_algorithm - > address + i * sizeof ( uint32_t ) ,
arm_crc_code [ i ] ) ;
if ( retval ! = ERROR_OK )
return retval ;
}
2009-12-04 21:46:44 -06:00
armv4_5_info . common_magic = ARM_COMMON_MAGIC ;
2009-12-04 21:21:14 -06:00
armv4_5_info . core_mode = ARM_MODE_SVC ;
2009-12-04 21:14:48 -06:00
armv4_5_info . core_state = ARM_STATE_ARM ;
2009-11-15 12:35:34 -06:00
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 */
2009-11-16 05:29:30 -06:00
for ( i = 0 ; i < ARRAY_SIZE ( check_code ) ; i + + ) {
2009-11-15 12:35:34 -06:00
retval = target_write_u32 ( target ,
check_algorithm - > address
+ i * sizeof ( uint32_t ) ,
check_code [ i ] ) ;
if ( retval ! = ERROR_OK )
return retval ;
}
2009-12-04 21:46:44 -06:00
armv4_5_info . common_magic = ARM_COMMON_MAGIC ;
2009-12-04 21:21:14 -06:00
armv4_5_info . core_mode = ARM_MODE_SVC ;
2009-12-04 21:14:48 -06:00
armv4_5_info . core_state = ARM_STATE_ARM ;
2009-11-15 12:35:34 -06:00
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-18 16:49:22 -06:00
static int arm_full_context ( struct target * target )
{
2009-12-04 21:43:03 -06:00
struct arm * armv4_5 = target_to_arm ( target ) ;
2009-11-18 16:49:22 -06:00
unsigned num_regs = armv4_5 - > core_cache - > num_regs ;
struct reg * reg = armv4_5 - > core_cache - > reg_list ;
int retval = ERROR_OK ;
for ( ; num_regs & & retval = = ERROR_OK ; num_regs - - , reg + + ) {
if ( reg - > valid )
continue ;
retval = armv4_5_get_core_reg ( reg ) ;
}
return retval ;
}
2009-12-01 02:48:53 -06:00
static int arm_default_mrc ( struct target * target , int cpnum ,
uint32_t op1 , uint32_t op2 ,
uint32_t CRn , uint32_t CRm ,
uint32_t * value )
{
LOG_ERROR ( " %s doesn't implement MRC " , target_type_name ( target ) ) ;
return ERROR_FAIL ;
}
static int arm_default_mcr ( struct target * target , int cpnum ,
uint32_t op1 , uint32_t op2 ,
uint32_t CRn , uint32_t CRm ,
uint32_t value )
{
LOG_ERROR ( " %s doesn't implement MCR " , target_type_name ( target ) ) ;
return ERROR_FAIL ;
}
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 ;
2009-11-24 02:13:58 -06:00
armv4_5 - > target = target ;
2006-06-02 05:36:31 -05:00
2009-12-04 21:46:44 -06:00
armv4_5 - > common_magic = ARM_COMMON_MAGIC ;
2009-12-04 21:21:14 -06:00
arm_set_cpsr ( armv4_5 , ARM_MODE_USR ) ;
2008-10-03 08:25:33 -05:00
2009-11-18 15:22:27 -06:00
/* core_type may be overridden by subtype logic */
2009-12-04 21:21:14 -06:00
armv4_5 - > core_type = ARM_MODE_ANY ;
2009-11-18 15:22:27 -06:00
2009-11-18 16:49:22 -06:00
/* default full_context() has no core-specific optimizations */
if ( ! armv4_5 - > full_context & & armv4_5 - > read_core_reg )
armv4_5 - > full_context = arm_full_context ;
2009-12-01 02:48:53 -06:00
if ( ! armv4_5 - > mrc )
armv4_5 - > mrc = arm_default_mrc ;
if ( ! armv4_5 - > mcr )
armv4_5 - > mcr = arm_default_mcr ;
2006-06-02 05:36:31 -05:00
return ERROR_OK ;
}