+369
-241
@@ -54,7 +54,7 @@ static int aarch64_unset_breakpoint(struct target *target,
|
||||
static int aarch64_mmu(struct target *target, int *enabled);
|
||||
static int aarch64_virt2phys(struct target *target,
|
||||
target_addr_t virt, target_addr_t *phys);
|
||||
static int aarch64_read_apb_ap_memory(struct target *target,
|
||||
static int aarch64_read_cpu_memory(struct target *target,
|
||||
uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer);
|
||||
|
||||
#define foreach_smp_target(pos, head) \
|
||||
@@ -161,8 +161,16 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
||||
case ARMV8_64_EL3T:
|
||||
instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0);
|
||||
break;
|
||||
|
||||
case ARM_MODE_SVC:
|
||||
case ARM_MODE_ABT:
|
||||
case ARM_MODE_FIQ:
|
||||
case ARM_MODE_IRQ:
|
||||
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_DEBUG("unknown cpu state 0x%x" PRIx32, armv8->arm.core_state);
|
||||
LOG_DEBUG("unknown cpu state 0x%" PRIx32, armv8->arm.core_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -180,7 +188,7 @@ static int aarch64_init_debug_access(struct target *target)
|
||||
int retval;
|
||||
uint32_t dummy;
|
||||
|
||||
LOG_DEBUG(" ");
|
||||
LOG_DEBUG("%s", target_name(target));
|
||||
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_OSLAR, 0);
|
||||
@@ -634,9 +642,11 @@ static int aarch64_prepare_restart_one(struct target *target)
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
}
|
||||
|
||||
/* clear sticky bits in PRSR, SDR is now 0 */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_PRSR, &tmp);
|
||||
if (retval == ERROR_OK) {
|
||||
/* clear sticky bits in PRSR, SDR is now 0 */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_PRSR, &tmp);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -770,6 +780,9 @@ static int aarch64_step_restart_smp(struct target *target)
|
||||
if (curr == target)
|
||||
continue;
|
||||
|
||||
if (!target_was_examined(curr))
|
||||
continue;
|
||||
|
||||
retval = aarch64_check_state_one(curr,
|
||||
PRSR_SDR, PRSR_SDR, &resumed, &prsr);
|
||||
if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) {
|
||||
@@ -1046,6 +1059,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
int handle_breakpoints)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct aarch64_common *aarch64 = target_to_aarch64(target);
|
||||
int saved_retval = ERROR_OK;
|
||||
int retval;
|
||||
uint32_t edecr;
|
||||
@@ -1066,7 +1080,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
armv8->debug_base + CPUV8_DBG_EDECR, (edecr|0x4));
|
||||
}
|
||||
/* disable interrupts while stepping */
|
||||
if (retval == ERROR_OK)
|
||||
if (retval == ERROR_OK && aarch64->isrmasking_mode == AARCH64_ISRMASK_ON)
|
||||
retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0x3 << 22);
|
||||
/* bail out if stepping setup has failed */
|
||||
if (retval != ERROR_OK)
|
||||
@@ -1110,7 +1124,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
if (retval != ERROR_OK || stepped)
|
||||
break;
|
||||
|
||||
if (timeval_ms() > then + 1000) {
|
||||
if (timeval_ms() > then + 100) {
|
||||
LOG_ERROR("timeout waiting for target %s halt after step",
|
||||
target_name(target));
|
||||
retval = ERROR_TARGET_TIMEOUT;
|
||||
@@ -1118,8 +1132,14 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At least on one SoC (Renesas R8A7795) stepping over a WFI instruction
|
||||
* causes a timeout. The core takes the step but doesn't complete it and so
|
||||
* debug state is never entered. However, you can manually halt the core
|
||||
* as an external debug even is also a WFI wakeup event.
|
||||
*/
|
||||
if (retval == ERROR_TARGET_TIMEOUT)
|
||||
saved_retval = retval;
|
||||
saved_retval = aarch64_halt_one(target, HALT_SYNC);
|
||||
|
||||
/* restore EDECR */
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
@@ -1128,9 +1148,11 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
return retval;
|
||||
|
||||
/* restore interrupts */
|
||||
retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return ERROR_OK;
|
||||
if (aarch64->isrmasking_mode == AARCH64_ISRMASK_ON) {
|
||||
retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (saved_retval != ERROR_OK)
|
||||
return saved_retval;
|
||||
@@ -1668,7 +1690,99 @@ static int aarch64_deassert_reset(struct target *target)
|
||||
return aarch64_init_debug_access(target);
|
||||
}
|
||||
|
||||
static int aarch64_write_apb_ap_memory(struct target *target,
|
||||
static int aarch64_write_cpu_memory_slow(struct target *target,
|
||||
uint32_t size, uint32_t count, const uint8_t *buffer, uint32_t *dscr)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct arm *arm = &armv8->arm;
|
||||
int retval;
|
||||
|
||||
armv8_reg_current(arm, 1)->dirty = true;
|
||||
|
||||
/* change DCC to normal mode if necessary */
|
||||
if (*dscr & DSCR_MA) {
|
||||
*dscr &= ~DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
uint32_t data, opcode;
|
||||
|
||||
/* write the data to store into DTRRX */
|
||||
if (size == 1)
|
||||
data = *buffer;
|
||||
else if (size == 2)
|
||||
data = target_buffer_get_u16(target, buffer);
|
||||
else
|
||||
data = target_buffer_get_u32(target, buffer);
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRRX, data);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64)
|
||||
retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1));
|
||||
else
|
||||
retval = dpm->instr_execute(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (size == 1)
|
||||
opcode = armv8_opcode(armv8, ARMV8_OPC_STRB_IP);
|
||||
else if (size == 2)
|
||||
opcode = armv8_opcode(armv8, ARMV8_OPC_STRH_IP);
|
||||
else
|
||||
opcode = armv8_opcode(armv8, ARMV8_OPC_STRW_IP);
|
||||
retval = dpm->instr_execute(dpm, opcode);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Advance */
|
||||
buffer += size;
|
||||
--count;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aarch64_write_cpu_memory_fast(struct target *target,
|
||||
uint32_t count, const uint8_t *buffer, uint32_t *dscr)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm *arm = &armv8->arm;
|
||||
int retval;
|
||||
|
||||
armv8_reg_current(arm, 1)->dirty = true;
|
||||
|
||||
/* Step 1.d - Change DCC to memory mode */
|
||||
*dscr |= DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
||||
/* Step 2.a - Do the write */
|
||||
retval = mem_ap_write_buf_noincr(armv8->debug_ap,
|
||||
buffer, 4, count, armv8->debug_base + CPUV8_DBG_DTRRX);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Step 3.a - Switch DTR mode back to Normal mode */
|
||||
*dscr &= ~DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aarch64_write_cpu_memory(struct target *target,
|
||||
uint64_t address, uint32_t size,
|
||||
uint32_t count, const uint8_t *buffer)
|
||||
{
|
||||
@@ -1677,144 +1791,213 @@ static int aarch64_write_apb_ap_memory(struct target *target,
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct arm *arm = &armv8->arm;
|
||||
int total_bytes = count * size;
|
||||
int total_u32;
|
||||
int start_byte = address & 0x3;
|
||||
int end_byte = (address + total_bytes) & 0x3;
|
||||
struct reg *reg;
|
||||
uint32_t dscr;
|
||||
uint8_t *tmp_buff = NULL;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4);
|
||||
|
||||
/* Mark register R0 as dirty, as it will be used
|
||||
/* Mark register X0 as dirty, as it will be used
|
||||
* for transferring the data.
|
||||
* It will be restored automatically when exiting
|
||||
* debug mode
|
||||
*/
|
||||
reg = armv8_reg_current(arm, 1);
|
||||
reg->dirty = true;
|
||||
|
||||
reg = armv8_reg_current(arm, 0);
|
||||
reg->dirty = true;
|
||||
armv8_reg_current(arm, 0)->dirty = true;
|
||||
|
||||
/* This algorithm comes from DDI0487A.g, chapter J9.1 */
|
||||
|
||||
/* The algorithm only copies 32 bit words, so the buffer
|
||||
* should be expanded to include the words at either end.
|
||||
* The first and last words will be read first to avoid
|
||||
* corruption if needed.
|
||||
*/
|
||||
tmp_buff = malloc(total_u32 * 4);
|
||||
|
||||
if ((start_byte != 0) && (total_u32 > 1)) {
|
||||
/* First bytes not aligned - read the 32 bit word to avoid corrupting
|
||||
* the other bytes in the word.
|
||||
*/
|
||||
retval = aarch64_read_apb_ap_memory(target, (address & ~0x3), 4, 1, tmp_buff);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_free_buff_w;
|
||||
}
|
||||
|
||||
/* If end of write is not aligned, or the write is less than 4 bytes */
|
||||
if ((end_byte != 0) ||
|
||||
((total_u32 == 1) && (total_bytes != 4))) {
|
||||
|
||||
/* Read the last word to avoid corruption during 32 bit write */
|
||||
int mem_offset = (total_u32-1) * 4;
|
||||
retval = aarch64_read_apb_ap_memory(target, (address & ~0x3) + mem_offset, 4, 1, &tmp_buff[mem_offset]);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_free_buff_w;
|
||||
}
|
||||
|
||||
/* Copy the write buffer over the top of the temporary buffer */
|
||||
memcpy(&tmp_buff[start_byte], buffer, total_bytes);
|
||||
|
||||
/* We now have a 32 bit aligned buffer that can be written */
|
||||
|
||||
/* Read DSCR */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_free_buff_w;
|
||||
return retval;
|
||||
|
||||
/* Set Normal access mode */
|
||||
dscr = (dscr & ~DSCR_MA);
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
/* Write X0 with value 'address' using write procedure */
|
||||
/* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */
|
||||
/* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */
|
||||
retval = dpm->instr_write_data_dcc_64(dpm,
|
||||
ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address & ~0x3ULL);
|
||||
ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address);
|
||||
} else {
|
||||
/* Write R0 with value 'address' using write procedure */
|
||||
/* Step 1.a+b - Write the address for read access into DBGDTRRX */
|
||||
/* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */
|
||||
dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address & ~0x3ULL);
|
||||
|
||||
retval = dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address);
|
||||
}
|
||||
/* Step 1.d - Change DCC to memory mode */
|
||||
dscr = dscr | DSCR_MA;
|
||||
retval += mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_unset_dtr_w;
|
||||
|
||||
|
||||
/* Step 2.a - Do the write */
|
||||
retval = mem_ap_write_buf_noincr(armv8->debug_ap,
|
||||
tmp_buff, 4, total_u32, armv8->debug_base + CPUV8_DBG_DTRRX);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_unset_dtr_w;
|
||||
return retval;
|
||||
|
||||
/* Step 3.a - Switch DTR mode back to Normal mode */
|
||||
dscr = (dscr & ~DSCR_MA);
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_unset_dtr_w;
|
||||
if (size == 4 && (address % 4) == 0)
|
||||
retval = aarch64_write_cpu_memory_fast(target, count, buffer, &dscr);
|
||||
else
|
||||
retval = aarch64_write_cpu_memory_slow(target, size, count, buffer, &dscr);
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
/* Unset DTR mode */
|
||||
mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
dscr &= ~DSCR_MA;
|
||||
mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
}
|
||||
|
||||
/* Check for sticky abort flags in the DSCR */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_free_buff_w;
|
||||
return retval;
|
||||
|
||||
dpm->dscr = dscr;
|
||||
if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) {
|
||||
/* Abort occurred - clear it and exit */
|
||||
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
|
||||
armv8_dpm_handle_exception(dpm);
|
||||
goto error_free_buff_w;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
free(tmp_buff);
|
||||
return ERROR_OK;
|
||||
|
||||
error_unset_dtr_w:
|
||||
/* Unset DTR mode */
|
||||
mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
dscr = (dscr & ~DSCR_MA);
|
||||
mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
error_free_buff_w:
|
||||
LOG_ERROR("error");
|
||||
free(tmp_buff);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int aarch64_read_apb_ap_memory(struct target *target,
|
||||
static int aarch64_read_cpu_memory_slow(struct target *target,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t *dscr)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct arm *arm = &armv8->arm;
|
||||
int retval;
|
||||
|
||||
armv8_reg_current(arm, 1)->dirty = true;
|
||||
|
||||
/* change DCC to normal mode (if necessary) */
|
||||
if (*dscr & DSCR_MA) {
|
||||
*dscr &= DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
uint32_t opcode, data;
|
||||
|
||||
if (size == 1)
|
||||
opcode = armv8_opcode(armv8, ARMV8_OPC_LDRB_IP);
|
||||
else if (size == 2)
|
||||
opcode = armv8_opcode(armv8, ARMV8_OPC_LDRH_IP);
|
||||
else
|
||||
opcode = armv8_opcode(armv8, ARMV8_OPC_LDRW_IP);
|
||||
retval = dpm->instr_execute(dpm, opcode);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64)
|
||||
retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1));
|
||||
else
|
||||
retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX, &data);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (size == 1)
|
||||
*buffer = (uint8_t)data;
|
||||
else if (size == 2)
|
||||
target_buffer_set_u16(target, buffer, (uint16_t)data);
|
||||
else
|
||||
target_buffer_set_u32(target, buffer, data);
|
||||
|
||||
/* Advance */
|
||||
buffer += size;
|
||||
--count;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aarch64_read_cpu_memory_fast(struct target *target,
|
||||
uint32_t count, uint8_t *buffer, uint32_t *dscr)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct arm *arm = &armv8->arm;
|
||||
int retval;
|
||||
uint32_t value;
|
||||
|
||||
/* Mark X1 as dirty */
|
||||
armv8_reg_current(arm, 1)->dirty = true;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
|
||||
retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0));
|
||||
} else {
|
||||
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
|
||||
retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Step 1.e - Change DCC to memory mode */
|
||||
*dscr |= DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Step 1.f - read DBGDTRTX and discard the value */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
count--;
|
||||
/* Read the data - Each read of the DTRTX register causes the instruction to be reissued
|
||||
* Abort flags are sticky, so can be read at end of transactions
|
||||
*
|
||||
* This data is read in aligned to 32 bit boundary.
|
||||
*/
|
||||
|
||||
if (count) {
|
||||
/* Step 2.a - Loop n-1 times, each read of DBGDTRTX reads the data from [X0] and
|
||||
* increments X0 by 4. */
|
||||
retval = mem_ap_read_buf_noincr(armv8->debug_ap, buffer, 4, count,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Step 3.a - set DTR access mode back to Normal mode */
|
||||
*dscr &= ~DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, *dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Step 3.b - read DBGDTRTX for the final value */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
target_buffer_set_u32(target, buffer + count * 4, value);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int aarch64_read_cpu_memory(struct target *target,
|
||||
target_addr_t address, uint32_t size,
|
||||
uint32_t count, uint8_t *buffer)
|
||||
{
|
||||
@@ -1823,126 +2006,74 @@ static int aarch64_read_apb_ap_memory(struct target *target,
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct arm *arm = &armv8->arm;
|
||||
int total_bytes = count * size;
|
||||
int total_u32;
|
||||
int start_byte = address & 0x3;
|
||||
int end_byte = (address + total_bytes) & 0x3;
|
||||
struct reg *reg;
|
||||
uint32_t dscr;
|
||||
uint8_t *tmp_buff = NULL;
|
||||
uint8_t *u8buf_ptr;
|
||||
uint32_t value;
|
||||
|
||||
LOG_DEBUG("Reading CPU memory address 0x%016" PRIx64 " size %" PRIu32 " count %" PRIu32,
|
||||
address, size, count);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4);
|
||||
/* Mark register X0, X1 as dirty, as it will be used
|
||||
/* Mark register X0 as dirty, as it will be used
|
||||
* for transferring the data.
|
||||
* It will be restored automatically when exiting
|
||||
* debug mode
|
||||
*/
|
||||
reg = armv8_reg_current(arm, 1);
|
||||
reg->dirty = true;
|
||||
|
||||
reg = armv8_reg_current(arm, 0);
|
||||
reg->dirty = true;
|
||||
armv8_reg_current(arm, 0)->dirty = true;
|
||||
|
||||
/* Read DSCR */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* This algorithm comes from DDI0487A.g, chapter J9.1 */
|
||||
|
||||
/* Set Normal access mode */
|
||||
dscr = (dscr & ~DSCR_MA);
|
||||
retval += mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
dscr &= ~DSCR_MA;
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
/* Write X0 with value 'address' using write procedure */
|
||||
/* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */
|
||||
/* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */
|
||||
retval += dpm->instr_write_data_dcc_64(dpm,
|
||||
ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address & ~0x3ULL);
|
||||
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
|
||||
retval += dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0));
|
||||
/* Step 1.e - Change DCC to memory mode */
|
||||
dscr = dscr | DSCR_MA;
|
||||
retval += mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
/* Step 1.f - read DBGDTRTX and discard the value */
|
||||
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
|
||||
retval = dpm->instr_write_data_dcc_64(dpm,
|
||||
ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address);
|
||||
} else {
|
||||
/* Write R0 with value 'address' using write procedure */
|
||||
/* Step 1.a+b - Write the address for read access into DBGDTRRXint */
|
||||
/* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */
|
||||
retval += dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address & ~0x3ULL);
|
||||
/* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */
|
||||
retval += dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
|
||||
/* Step 1.e - Change DCC to memory mode */
|
||||
dscr = dscr | DSCR_MA;
|
||||
retval += mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
/* Step 1.f - read DBGDTRTX and discard the value */
|
||||
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
|
||||
|
||||
retval = dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address);
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
goto error_unset_dtr_r;
|
||||
return retval;
|
||||
|
||||
/* Optimize the read as much as we can, either way we read in a single pass */
|
||||
if ((start_byte) || (end_byte)) {
|
||||
/* The algorithm only copies 32 bit words, so the buffer
|
||||
* should be expanded to include the words at either end.
|
||||
* The first and last words will be read into a temp buffer
|
||||
* to avoid corruption
|
||||
*/
|
||||
tmp_buff = malloc(total_u32 * 4);
|
||||
if (!tmp_buff)
|
||||
goto error_unset_dtr_r;
|
||||
if (size == 4 && (address % 4) == 0)
|
||||
retval = aarch64_read_cpu_memory_fast(target, count, buffer, &dscr);
|
||||
else
|
||||
retval = aarch64_read_cpu_memory_slow(target, size, count, buffer, &dscr);
|
||||
|
||||
/* use the tmp buffer to read the entire data */
|
||||
u8buf_ptr = tmp_buff;
|
||||
} else
|
||||
/* address and read length are aligned so read directly into the passed buffer */
|
||||
u8buf_ptr = buffer;
|
||||
|
||||
/* Read the data - Each read of the DTRTX register causes the instruction to be reissued
|
||||
* Abort flags are sticky, so can be read at end of transactions
|
||||
*
|
||||
* This data is read in aligned to 32 bit boundary.
|
||||
*/
|
||||
|
||||
/* Step 2.a - Loop n-1 times, each read of DBGDTRTX reads the data from [X0] and
|
||||
* increments X0 by 4. */
|
||||
retval = mem_ap_read_buf_noincr(armv8->debug_ap, u8buf_ptr, 4, total_u32-1,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_unset_dtr_r;
|
||||
|
||||
/* Step 3.a - set DTR access mode back to Normal mode */
|
||||
dscr = (dscr & ~DSCR_MA);
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
if (dscr & DSCR_MA) {
|
||||
dscr &= ~DSCR_MA;
|
||||
mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_free_buff_r;
|
||||
}
|
||||
|
||||
/* Step 3.b - read DBGDTRTX for the final value */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DTRTX, &value);
|
||||
memcpy(u8buf_ptr + (total_u32-1) * 4, &value, 4);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Check for sticky abort flags in the DSCR */
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
if (retval != ERROR_OK)
|
||||
goto error_free_buff_r;
|
||||
return retval;
|
||||
|
||||
dpm->dscr = dscr;
|
||||
|
||||
@@ -1950,29 +2081,11 @@ static int aarch64_read_apb_ap_memory(struct target *target,
|
||||
/* Abort occurred - clear it and exit */
|
||||
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
|
||||
armv8_dpm_handle_exception(dpm);
|
||||
goto error_free_buff_r;
|
||||
}
|
||||
|
||||
/* check if we need to copy aligned data by applying any shift necessary */
|
||||
if (tmp_buff) {
|
||||
memcpy(buffer, tmp_buff + start_byte, total_bytes);
|
||||
free(tmp_buff);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
return ERROR_OK;
|
||||
|
||||
error_unset_dtr_r:
|
||||
/* Unset DTR mode */
|
||||
mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, &dscr);
|
||||
dscr = (dscr & ~DSCR_MA);
|
||||
mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DSCR, dscr);
|
||||
error_free_buff_r:
|
||||
LOG_ERROR("error");
|
||||
free(tmp_buff);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int aarch64_read_phys_memory(struct target *target,
|
||||
@@ -1986,7 +2099,7 @@ static int aarch64_read_phys_memory(struct target *target,
|
||||
retval = aarch64_mmu_modify(target, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = aarch64_read_apb_ap_memory(target, address, size, count, buffer);
|
||||
retval = aarch64_read_cpu_memory(target, address, size, count, buffer);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -2008,7 +2121,7 @@ static int aarch64_read_memory(struct target *target, target_addr_t address,
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
return aarch64_read_apb_ap_memory(target, address, size, count, buffer);
|
||||
return aarch64_read_cpu_memory(target, address, size, count, buffer);
|
||||
}
|
||||
|
||||
static int aarch64_write_phys_memory(struct target *target,
|
||||
@@ -2022,7 +2135,7 @@ static int aarch64_write_phys_memory(struct target *target,
|
||||
retval = aarch64_mmu_modify(target, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
return aarch64_write_apb_ap_memory(target, address, size, count, buffer);
|
||||
return aarch64_write_cpu_memory(target, address, size, count, buffer);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -2045,7 +2158,7 @@ static int aarch64_write_memory(struct target *target, target_addr_t address,
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
return aarch64_write_apb_ap_memory(target, address, size, count, buffer);
|
||||
return aarch64_write_cpu_memory(target, address, size, count, buffer);
|
||||
}
|
||||
|
||||
static int aarch64_handle_target_request(void *priv)
|
||||
@@ -2090,7 +2203,7 @@ static int aarch64_examine_first(struct target *target)
|
||||
int retval = ERROR_OK;
|
||||
uint64_t debug, ttypr;
|
||||
uint32_t cpuid;
|
||||
uint32_t tmp0, tmp1;
|
||||
uint32_t tmp0, tmp1, tmp2, tmp3;
|
||||
debug = ttypr = cpuid = 0;
|
||||
|
||||
retval = dap_dp_init(swjdp);
|
||||
@@ -2130,32 +2243,6 @@ static int aarch64_examine_first(struct target *target)
|
||||
} else
|
||||
armv8->debug_base = target->dbgbase;
|
||||
|
||||
uint32_t prsr;
|
||||
int64_t then = timeval_ms();
|
||||
do {
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_PRSR, &prsr);
|
||||
if (retval == ERROR_OK) {
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_PRCR, PRCR_COREPURQ|PRCR_CORENPDRQ);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("write to PRCR failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeval_ms() > then + 1000) {
|
||||
retval = ERROR_TARGET_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
} while ((prsr & PRSR_PU) == 0);
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("target %s: failed to set power state of the core.", target_name(target));
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = mem_ap_write_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_OSLAR, 0);
|
||||
if (retval != ERROR_OK) {
|
||||
@@ -2163,34 +2250,40 @@ static int aarch64_examine_first(struct target *target)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
retval = mem_ap_read_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_MAINID0, &cpuid);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("Examine %s failed", "CPUID");
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
retval = mem_ap_read_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_MEMFEATURE0, &tmp0);
|
||||
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
retval += mem_ap_read_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("Examine %s failed", "Memory Model Type");
|
||||
return retval;
|
||||
}
|
||||
ttypr |= tmp1;
|
||||
ttypr = (ttypr << 32) | tmp0;
|
||||
|
||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp0);
|
||||
retval += mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp1);
|
||||
retval = mem_ap_read_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp2);
|
||||
retval += mem_ap_read_u32(armv8->debug_ap,
|
||||
armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp3);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("Examine %s failed", "ID_AA64DFR0_EL1");
|
||||
return retval;
|
||||
}
|
||||
debug |= tmp1;
|
||||
debug = (debug << 32) | tmp0;
|
||||
|
||||
retval = dap_run(armv8->debug_ap->dap);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("%s: examination failed\n", target_name(target));
|
||||
return retval;
|
||||
}
|
||||
|
||||
ttypr |= tmp1;
|
||||
ttypr = (ttypr << 32) | tmp0;
|
||||
debug |= tmp3;
|
||||
debug = (debug << 32) | tmp2;
|
||||
|
||||
LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid);
|
||||
LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr);
|
||||
@@ -2229,9 +2322,9 @@ static int aarch64_examine_first(struct target *target)
|
||||
|
||||
LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num);
|
||||
|
||||
target->state = TARGET_RUNNING;
|
||||
target->state = TARGET_UNKNOWN;
|
||||
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||
|
||||
aarch64->isrmasking_mode = AARCH64_ISRMASK_ON;
|
||||
target_set_examined(target);
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -2369,6 +2462,34 @@ COMMAND_HANDLER(aarch64_handle_smp_on_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(aarch64_mask_interrupts_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct aarch64_common *aarch64 = target_to_aarch64(target);
|
||||
|
||||
static const Jim_Nvp nvp_maskisr_modes[] = {
|
||||
{ .name = "off", .value = AARCH64_ISRMASK_OFF },
|
||||
{ .name = "on", .value = AARCH64_ISRMASK_ON },
|
||||
{ .name = NULL, .value = -1 },
|
||||
};
|
||||
const Jim_Nvp *n;
|
||||
|
||||
if (CMD_ARGC > 0) {
|
||||
n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
|
||||
if (n->name == NULL) {
|
||||
LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
aarch64->isrmasking_mode = n->value;
|
||||
}
|
||||
|
||||
n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode);
|
||||
command_print(CMD_CTX, "aarch64 interrupt mask %s", n->name);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration aarch64_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cache_info",
|
||||
@@ -2397,6 +2518,13 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
|
||||
.help = "Restart smp handling",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.name = "maskisr",
|
||||
.handler = aarch64_mask_interrupts_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "mask aarch64 interrupts during single-step",
|
||||
.usage = "['on'|'off']",
|
||||
},
|
||||
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
|
||||
#define AARCH64_PADDRDBG_CPU_SHIFT 13
|
||||
|
||||
enum aarch64_isrmasking_mode {
|
||||
AARCH64_ISRMASK_OFF,
|
||||
AARCH64_ISRMASK_ON,
|
||||
};
|
||||
|
||||
struct aarch64_brp {
|
||||
int used;
|
||||
int type;
|
||||
@@ -58,6 +63,8 @@ struct aarch64_common {
|
||||
struct aarch64_brp *brp_list;
|
||||
|
||||
struct armv8_common armv8_common;
|
||||
|
||||
enum aarch64_isrmasking_mode isrmasking_mode;
|
||||
};
|
||||
|
||||
static inline struct aarch64_common *
|
||||
|
||||
@@ -124,7 +124,7 @@ static int swd_connect(struct adiv5_dap *dap)
|
||||
|
||||
/* Clear link state, including the SELECT cache. */
|
||||
dap->do_reconnect = false;
|
||||
dap->select = DP_SELECT_INVALID;
|
||||
dap_invalidate_cache(dap);
|
||||
|
||||
swd_queue_dp_read(dap, DP_DPIDR, &dpidr);
|
||||
|
||||
|
||||
+7
-8
@@ -66,14 +66,13 @@ enum arm_mode {
|
||||
ARM_MODE_USER_THREAD = 1,
|
||||
ARM_MODE_HANDLER = 2,
|
||||
|
||||
/* shift left 4 bits for armv8 64 */
|
||||
ARMV8_64_EL0T = 0x0F,
|
||||
ARMV8_64_EL1T = 0x4F,
|
||||
ARMV8_64_EL1H = 0x5F,
|
||||
ARMV8_64_EL2T = 0x8F,
|
||||
ARMV8_64_EL2H = 0x9F,
|
||||
ARMV8_64_EL3T = 0xCF,
|
||||
ARMV8_64_EL3H = 0xDF,
|
||||
ARMV8_64_EL0T = 0x0,
|
||||
ARMV8_64_EL1T = 0x4,
|
||||
ARMV8_64_EL1H = 0x5,
|
||||
ARMV8_64_EL2T = 0x8,
|
||||
ARMV8_64_EL2H = 0x9,
|
||||
ARMV8_64_EL3T = 0xC,
|
||||
ARMV8_64_EL3H = 0xD,
|
||||
|
||||
ARM_MODE_ANY = -1
|
||||
};
|
||||
|
||||
+117
-48
@@ -111,17 +111,68 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw)
|
||||
|
||||
static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar)
|
||||
{
|
||||
if (tar != ap->tar_value ||
|
||||
(ap->csw_value & CSW_ADDRINC_MASK)) {
|
||||
if (!ap->tar_valid || tar != ap->tar_value) {
|
||||
/* LOG_DEBUG("DAP: Set TAR %x",tar); */
|
||||
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
ap->tar_value = tar;
|
||||
ap->tar_valid = true;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int mem_ap_read_tar(struct adiv5_ap *ap, uint32_t *tar)
|
||||
{
|
||||
int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR, tar);
|
||||
if (retval != ERROR_OK) {
|
||||
ap->tar_valid = false;
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = dap_run(ap->dap);
|
||||
if (retval != ERROR_OK) {
|
||||
ap->tar_valid = false;
|
||||
return retval;
|
||||
}
|
||||
|
||||
ap->tar_value = *tar;
|
||||
ap->tar_valid = true;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap)
|
||||
{
|
||||
switch (ap->csw_value & CSW_ADDRINC_MASK) {
|
||||
case CSW_ADDRINC_SINGLE:
|
||||
switch (ap->csw_value & CSW_SIZE_MASK) {
|
||||
case CSW_8BIT:
|
||||
return 1;
|
||||
case CSW_16BIT:
|
||||
return 2;
|
||||
case CSW_32BIT:
|
||||
return 4;
|
||||
}
|
||||
case CSW_ADDRINC_PACKED:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mem_ap_update_tar_cache is called after an access to MEM_AP_REG_DRW
|
||||
*/
|
||||
static void mem_ap_update_tar_cache(struct adiv5_ap *ap)
|
||||
{
|
||||
if (!ap->tar_valid)
|
||||
return;
|
||||
|
||||
uint32_t inc = mem_ap_get_tar_increment(ap);
|
||||
if (inc >= max_tar_block_size(ap->tar_autoincr_block, ap->tar_value))
|
||||
ap->tar_valid = false;
|
||||
else
|
||||
ap->tar_value += inc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue transactions setting up transfer parameters for the
|
||||
* currently selected MEM-AP.
|
||||
@@ -170,7 +221,8 @@ int mem_ap_read_u32(struct adiv5_ap *ap, uint32_t address,
|
||||
/* Use banked addressing (REG_BDx) to avoid some link traffic
|
||||
* (updating TAR) when reading several consecutive addresses.
|
||||
*/
|
||||
retval = mem_ap_setup_transfer(ap, CSW_32BIT | CSW_ADDRINC_OFF,
|
||||
retval = mem_ap_setup_transfer(ap,
|
||||
CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK),
|
||||
address & 0xFFFFFFF0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
@@ -221,7 +273,8 @@ int mem_ap_write_u32(struct adiv5_ap *ap, uint32_t address,
|
||||
/* Use banked addressing (REG_BDx) to avoid some link traffic
|
||||
* (updating TAR) when writing several consecutive addresses.
|
||||
*/
|
||||
retval = mem_ap_setup_transfer(ap, CSW_32BIT | CSW_ADDRINC_OFF,
|
||||
retval = mem_ap_setup_transfer(ap,
|
||||
CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK),
|
||||
address & 0xFFFFFFF0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
@@ -272,7 +325,7 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
|
||||
const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;
|
||||
uint32_t csw_size;
|
||||
uint32_t addr_xor;
|
||||
int retval;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
/* TI BE-32 Quirks mode:
|
||||
* Writes on big-endian TMS570 behave very strangely. Observed behavior:
|
||||
@@ -303,10 +356,6 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
|
||||
if (ap->unaligned_access_bad && (address % size != 0))
|
||||
return ERROR_TARGET_UNALIGNED_ACCESS;
|
||||
|
||||
retval = mem_ap_setup_tar(ap, address ^ addr_xor);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
while (nbytes > 0) {
|
||||
uint32_t this_size = size;
|
||||
|
||||
@@ -322,36 +371,41 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
retval = mem_ap_setup_tar(ap, address ^ addr_xor);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* How many source bytes each transfer will consume, and their location in the DRW,
|
||||
* depends on the type of transfer and alignment. See ARM document IHI0031C. */
|
||||
uint32_t outvalue = 0;
|
||||
uint32_t drw_byte_idx = address;
|
||||
if (dap->ti_be_32_quirks) {
|
||||
switch (this_size) {
|
||||
case 4:
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx & 3) ^ addr_xor);
|
||||
break;
|
||||
case 2:
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx & 3) ^ addr_xor);
|
||||
break;
|
||||
case 1:
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (address++ & 3) ^ addr_xor);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (drw_byte_idx & 3) ^ addr_xor);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (this_size) {
|
||||
case 4:
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);
|
||||
/* fallthrough */
|
||||
case 2:
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
|
||||
outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,12 +415,9 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
/* Rewrite TAR if it wrapped or we're xoring addresses */
|
||||
if (addrinc && (addr_xor || (address % ap->tar_autoincr_block < size && nbytes > 0))) {
|
||||
retval = mem_ap_setup_tar(ap, address ^ addr_xor);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
mem_ap_update_tar_cache(ap);
|
||||
if (addrinc)
|
||||
address += this_size;
|
||||
}
|
||||
|
||||
/* REVISIT: Might want to have a queued version of this function that does not run. */
|
||||
@@ -375,8 +426,7 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
uint32_t tar;
|
||||
if (dap_queue_ap_read(ap, MEM_AP_REG_TAR, &tar) == ERROR_OK
|
||||
&& dap_run(dap) == ERROR_OK)
|
||||
if (mem_ap_read_tar(ap, &tar) == ERROR_OK)
|
||||
LOG_ERROR("Failed to write memory at 0x%08"PRIx32, tar);
|
||||
else
|
||||
LOG_ERROR("Failed to write memory and, additionally, failed to find out where");
|
||||
@@ -405,7 +455,7 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
|
||||
const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;
|
||||
uint32_t csw_size;
|
||||
uint32_t address = adr;
|
||||
int retval;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
/* TI BE-32 Quirks mode:
|
||||
* Reads on big-endian TMS570 behave strangely differently than writes.
|
||||
@@ -429,19 +479,14 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
|
||||
/* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant
|
||||
* over-allocation if packed transfers are going to be used, but determining the real need at
|
||||
* this point would be messy. */
|
||||
uint32_t *read_buf = malloc(count * sizeof(uint32_t));
|
||||
uint32_t *read_buf = calloc(count, sizeof(uint32_t));
|
||||
/* Multiplication count * sizeof(uint32_t) may overflow, calloc() is safe */
|
||||
uint32_t *read_ptr = read_buf;
|
||||
if (read_buf == NULL) {
|
||||
LOG_ERROR("Failed to allocate read buffer");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
retval = mem_ap_setup_tar(ap, address);
|
||||
if (retval != ERROR_OK) {
|
||||
free(read_buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Queue up all reads. Each read will store the entire DRW word in the read buffer. How many
|
||||
* useful bytes it contains, and their location in the word, depends on the type of transfer
|
||||
* and alignment. */
|
||||
@@ -459,19 +504,19 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
retval = mem_ap_setup_tar(ap, address);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW, read_ptr++);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
nbytes -= this_size;
|
||||
address += this_size;
|
||||
if (addrinc)
|
||||
address += this_size;
|
||||
|
||||
/* Rewrite TAR if it wrapped */
|
||||
if (addrinc && address % ap->tar_autoincr_block < size && nbytes > 0) {
|
||||
retval = mem_ap_setup_tar(ap, address);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
mem_ap_update_tar_cache(ap);
|
||||
}
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
@@ -486,8 +531,8 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint
|
||||
* at least give the caller what we have. */
|
||||
if (retval != ERROR_OK) {
|
||||
uint32_t tar;
|
||||
if (dap_queue_ap_read(ap, MEM_AP_REG_TAR, &tar) == ERROR_OK
|
||||
&& dap_run(dap) == ERROR_OK) {
|
||||
if (mem_ap_read_tar(ap, &tar) == ERROR_OK) {
|
||||
/* TAR is incremented after failed transfer on some devices (eg Cortex-M4) */
|
||||
LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar);
|
||||
if (nbytes > tar - address)
|
||||
nbytes = tar - address;
|
||||
@@ -596,6 +641,22 @@ struct adiv5_dap *dap_init(void)
|
||||
return dap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate cached DP select and cached TAR and CSW of all APs
|
||||
*/
|
||||
void dap_invalidate_cache(struct adiv5_dap *dap)
|
||||
{
|
||||
dap->select = DP_SELECT_INVALID;
|
||||
dap->last_read = NULL;
|
||||
|
||||
int i;
|
||||
for (i = 0; i <= 255; i++) {
|
||||
/* force csw and tar write on the next mem-ap access */
|
||||
dap->ap[i].tar_valid = false;
|
||||
dap->ap[i].csw_value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a DAP. This sets up the power domains, prepares the DP
|
||||
* for further use and activates overrun checking.
|
||||
@@ -615,8 +676,7 @@ int dap_dp_init(struct adiv5_dap *dap)
|
||||
if (!dap->ops)
|
||||
dap->ops = &jtag_dp_ops;
|
||||
|
||||
dap->select = DP_SELECT_INVALID;
|
||||
dap->last_read = NULL;
|
||||
dap_invalidate_cache(dap);
|
||||
|
||||
for (size_t i = 0; i < 30; i++) {
|
||||
/* DP initialization */
|
||||
@@ -688,6 +748,8 @@ int mem_ap_init(struct adiv5_ap *ap)
|
||||
int retval;
|
||||
struct adiv5_dap *dap = ap->dap;
|
||||
|
||||
ap->tar_valid = false;
|
||||
ap->csw_value = 0; /* force csw and tar write */
|
||||
retval = mem_ap_setup_transfer(ap, CSW_8BIT | CSW_ADDRINC_PACKED, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
@@ -979,12 +1041,14 @@ static const struct {
|
||||
{ ARM_ID, 0x4a2, "Cortex-A57 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4a3, "Cortex-A53 ROM", "(v7 Memory Map ROM Table)", },
|
||||
{ ARM_ID, 0x4a4, "Cortex-A72 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4a9, "Cortex-A9 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", },
|
||||
{ ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x470, "Cortex-M1 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x471, "Cortex-M0 ROM", "(ROM Table)", },
|
||||
{ ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", },
|
||||
@@ -1025,7 +1089,7 @@ static const struct {
|
||||
{ ARM_ID, 0x9a9, "Cortex-M7 TPIU", "(Trace Port Interface Unit)", },
|
||||
{ ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", },
|
||||
{ ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", },
|
||||
{ ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitoring Unit)", },
|
||||
{ ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", },
|
||||
{ ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", },
|
||||
{ ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", },
|
||||
{ ARM_ID, 0x9d8, "Cortex-A72 PMU", "(Performance Monitor Unit)", },
|
||||
@@ -1048,6 +1112,11 @@ static const struct {
|
||||
{ 0x0c1, 0x1ed, "XMC1000 ROM", "(ROM Table)" },
|
||||
{ 0x0E5, 0x000, "SHARC+/Blackfin+", "", },
|
||||
{ 0x0F0, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", },
|
||||
{ 0x3eb, 0x181, "Tegra 186 ROM", "(ROM Table)", },
|
||||
{ 0x3eb, 0x211, "Tegra 210 ROM", "(ROM Table)", },
|
||||
{ 0x3eb, 0x202, "Denver ETM", "(Denver Embedded Trace)", },
|
||||
{ 0x3eb, 0x302, "Denver Debug", "(Debug Unit)", },
|
||||
{ 0x3eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", },
|
||||
/* legacy comment: 0x113: what? */
|
||||
{ ANY_ID, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */
|
||||
{ ANY_ID, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
#define AP_REG_IDR 0xFC /* RO: Identification Register */
|
||||
|
||||
/* Fields of the MEM-AP's CSW register */
|
||||
#define CSW_SIZE_MASK 7
|
||||
#define CSW_8BIT 0
|
||||
#define CSW_16BIT 1
|
||||
#define CSW_32BIT 2
|
||||
@@ -180,6 +181,9 @@ struct adiv5_ap {
|
||||
|
||||
/* true if unaligned memory access is not supported by the MEM-AP */
|
||||
bool unaligned_access_bad;
|
||||
|
||||
/* true if tar_value is in sync with TAR register */
|
||||
bool tar_valid;
|
||||
};
|
||||
|
||||
|
||||
@@ -476,6 +480,9 @@ struct adiv5_dap *dap_init(void);
|
||||
int dap_dp_init(struct adiv5_dap *dap);
|
||||
int mem_ap_init(struct adiv5_ap *ap);
|
||||
|
||||
/* Invalidate cached DP select and cached TAR and CSW of all APs */
|
||||
void dap_invalidate_cache(struct adiv5_dap *dap);
|
||||
|
||||
/* Probe the AP for ROM Table location */
|
||||
int dap_get_debugbase(struct adiv5_ap *ap,
|
||||
uint32_t *dbgbase, uint32_t *apid);
|
||||
|
||||
+102
-16
@@ -129,6 +129,59 @@ static int evaluate_pld(uint32_t opcode,
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
/* DSB */
|
||||
if ((opcode & 0x07f000f0) == 0x05700040) {
|
||||
instruction->type = ARM_DSB;
|
||||
|
||||
char *opt;
|
||||
switch (opcode & 0x0000000f) {
|
||||
case 0xf:
|
||||
opt = "SY";
|
||||
break;
|
||||
case 0xe:
|
||||
opt = "ST";
|
||||
break;
|
||||
case 0xb:
|
||||
opt = "ISH";
|
||||
break;
|
||||
case 0xa:
|
||||
opt = "ISHST";
|
||||
break;
|
||||
case 0x7:
|
||||
opt = "NSH";
|
||||
break;
|
||||
case 0x6:
|
||||
opt = "NSHST";
|
||||
break;
|
||||
case 0x3:
|
||||
opt = "OSH";
|
||||
break;
|
||||
case 0x2:
|
||||
opt = "OSHST";
|
||||
break;
|
||||
default:
|
||||
opt = "UNK";
|
||||
}
|
||||
|
||||
snprintf(instruction->text,
|
||||
128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDSB %s",
|
||||
address, opcode, opt);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
/* ISB */
|
||||
if ((opcode & 0x07f000f0) == 0x05700060) {
|
||||
instruction->type = ARM_ISB;
|
||||
|
||||
snprintf(instruction->text,
|
||||
128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISB %s",
|
||||
address, opcode,
|
||||
((opcode & 0x0000000f) == 0xf) ? "SY" : "UNK");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
return evaluate_unknown(opcode, address, instruction);
|
||||
}
|
||||
|
||||
@@ -1562,6 +1615,33 @@ static int evaluate_misc_instr(uint32_t opcode,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int evaluate_mov_imm(uint32_t opcode,
|
||||
uint32_t address, struct arm_instruction *instruction)
|
||||
{
|
||||
uint16_t immediate;
|
||||
uint8_t Rd;
|
||||
bool T;
|
||||
|
||||
Rd = (opcode & 0xf000) >> 12;
|
||||
T = opcode & 0x00400000;
|
||||
immediate = (opcode & 0xf0000) >> 4 | (opcode & 0xfff);
|
||||
|
||||
instruction->type = ARM_MOV;
|
||||
instruction->info.data_proc.Rd = Rd;
|
||||
|
||||
snprintf(instruction->text,
|
||||
128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMOV%s%s r%i, #0x%" PRIx16,
|
||||
address,
|
||||
opcode,
|
||||
T ? "T" : "W",
|
||||
COND(opcode),
|
||||
Rd,
|
||||
immediate);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int evaluate_data_proc(uint32_t opcode,
|
||||
uint32_t address, struct arm_instruction *instruction)
|
||||
{
|
||||
@@ -1838,16 +1918,9 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address,
|
||||
|
||||
/* catch opcodes with [27:25] = b001 */
|
||||
if ((opcode & 0x0e000000) == 0x02000000) {
|
||||
/* Undefined instruction */
|
||||
if ((opcode & 0x0fb00000) == 0x03000000) {
|
||||
instruction->type = ARM_UNDEFINED_INSTRUCTION;
|
||||
snprintf(instruction->text,
|
||||
128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
|
||||
address,
|
||||
opcode);
|
||||
return ERROR_OK;
|
||||
}
|
||||
/* 16-bit immediate load */
|
||||
if ((opcode & 0x0fb00000) == 0x03000000)
|
||||
return evaluate_mov_imm(opcode, address, instruction);
|
||||
|
||||
/* Move immediate to status register */
|
||||
if ((opcode & 0x0fb00000) == 0x03200000)
|
||||
@@ -2896,12 +2969,26 @@ static int t2ev_b_bl(uint32_t opcode, uint32_t address,
|
||||
address += 4;
|
||||
address += offset << 1;
|
||||
|
||||
instruction->type = (opcode & (1 << 14)) ? ARM_BL : ARM_B;
|
||||
char *inst;
|
||||
switch ((opcode >> 12) & 0x5) {
|
||||
case 0x1:
|
||||
inst = "B.W";
|
||||
instruction->type = ARM_B;
|
||||
break;
|
||||
case 0x4:
|
||||
inst = "BLX";
|
||||
instruction->type = ARM_BLX;
|
||||
break;
|
||||
case 0x5:
|
||||
inst = "BL";
|
||||
instruction->type = ARM_BL;
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
instruction->info.b_bl_bx_blx.reg_operand = -1;
|
||||
instruction->info.b_bl_bx_blx.target_address = address;
|
||||
sprintf(cp, "%s\t%#8.8" PRIx32,
|
||||
(opcode & (1 << 14)) ? "BL" : "B.W",
|
||||
address);
|
||||
sprintf(cp, "%s\t%#8.8" PRIx32, inst, address);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -3078,10 +3165,9 @@ static int t2ev_b_misc(uint32_t opcode, uint32_t address,
|
||||
|
||||
switch ((opcode >> 12) & 0x5) {
|
||||
case 0x1:
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
return t2ev_b_bl(opcode, address, instruction, cp);
|
||||
case 0x4:
|
||||
goto undef;
|
||||
case 0:
|
||||
if (((opcode >> 23) & 0x07) != 0x07)
|
||||
return t2ev_cond_b(opcode, address, instruction, cp);
|
||||
|
||||
@@ -106,6 +106,8 @@ enum arm_instruction_type {
|
||||
ARM_MCRR,
|
||||
ARM_MRRC,
|
||||
ARM_PLD,
|
||||
ARM_DSB,
|
||||
ARM_ISB,
|
||||
ARM_QADD,
|
||||
ARM_QDADD,
|
||||
ARM_QSUB,
|
||||
|
||||
+7
-51
@@ -45,8 +45,6 @@ static const struct {
|
||||
const char *name;
|
||||
unsigned psr;
|
||||
} armv8_mode_data[] = {
|
||||
/* These special modes are currently only supported
|
||||
* by ARMv6M and ARMv7M profiles */
|
||||
{
|
||||
.name = "USR",
|
||||
.psr = ARM_MODE_USR,
|
||||
@@ -112,48 +110,6 @@ const char *armv8_mode_name(unsigned psr_mode)
|
||||
return "UNRECOGNIZED";
|
||||
}
|
||||
|
||||
int armv8_mode_to_number(enum arm_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case ARM_MODE_ANY:
|
||||
/* map MODE_ANY to user mode */
|
||||
case ARM_MODE_USR:
|
||||
return 0;
|
||||
case ARM_MODE_FIQ:
|
||||
return 1;
|
||||
case ARM_MODE_IRQ:
|
||||
return 2;
|
||||
case ARM_MODE_SVC:
|
||||
return 3;
|
||||
case ARM_MODE_ABT:
|
||||
return 4;
|
||||
case ARM_MODE_UND:
|
||||
return 5;
|
||||
case ARM_MODE_SYS:
|
||||
return 6;
|
||||
case ARM_MODE_MON:
|
||||
return 7;
|
||||
case ARMV8_64_EL0T:
|
||||
return 8;
|
||||
case ARMV8_64_EL1T:
|
||||
return 9;
|
||||
case ARMV8_64_EL1H:
|
||||
return 10;
|
||||
case ARMV8_64_EL2T:
|
||||
return 11;
|
||||
case ARMV8_64_EL2H:
|
||||
return 12;
|
||||
case ARMV8_64_EL3T:
|
||||
return 13;
|
||||
case ARMV8_64_EL3H:
|
||||
return 14;
|
||||
|
||||
default:
|
||||
LOG_ERROR("invalid mode value encountered %d", mode);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
|
||||
{
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
@@ -533,9 +489,8 @@ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr)
|
||||
/* Older ARMs won't have the J bit */
|
||||
enum arm_state state = 0xFF;
|
||||
|
||||
if (((cpsr & 0x10) >> 4) == 0) {
|
||||
state = ARM_STATE_AARCH64;
|
||||
} else {
|
||||
if ((cpsr & 0x10) != 0) {
|
||||
/* Aarch32 state */
|
||||
if (cpsr & (1 << 5)) { /* T */
|
||||
if (cpsr & (1 << 24)) { /* J */
|
||||
LOG_WARNING("ThumbEE -- incomplete support");
|
||||
@@ -549,12 +504,13 @@ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr)
|
||||
} else
|
||||
state = ARM_STATE_ARM;
|
||||
}
|
||||
} else {
|
||||
/* Aarch64 state */
|
||||
state = ARM_STATE_AARCH64;
|
||||
}
|
||||
|
||||
arm->core_state = state;
|
||||
if (arm->core_state == ARM_STATE_AARCH64)
|
||||
arm->core_mode = (mode << 4) | 0xf;
|
||||
else
|
||||
arm->core_mode = mode;
|
||||
arm->core_mode = mode;
|
||||
|
||||
LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr,
|
||||
armv8_mode_name(arm->core_mode),
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode)
|
||||
return 3;
|
||||
/* all Aarch64 modes */
|
||||
default:
|
||||
return (core_mode >> 6) & 3;
|
||||
return (core_mode >> 2) & 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -561,12 +561,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
|
||||
|
||||
} else {
|
||||
LOG_DEBUG("setting mode 0x%"PRIx32, mode);
|
||||
|
||||
/* else force to the specified mode */
|
||||
if (is_arm_mode(mode))
|
||||
cpsr = mode;
|
||||
else
|
||||
cpsr = mode >> 4;
|
||||
cpsr = mode;
|
||||
}
|
||||
|
||||
switch (cpsr & 0x1f) {
|
||||
|
||||
@@ -42,6 +42,12 @@ static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = {
|
||||
[ARMV8_OPC_DCCIVAC] = ARMV8_SYS(SYSTEM_DCCIVAC, 0),
|
||||
[ARMV8_OPC_ICIVAU] = ARMV8_SYS(SYSTEM_ICIVAU, 0),
|
||||
[ARMV8_OPC_HLT] = ARMV8_HLT(11),
|
||||
[ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP(1, 0),
|
||||
[ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP(1, 0),
|
||||
[ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP(1, 0),
|
||||
[ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP(1, 0),
|
||||
[ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP(1, 0),
|
||||
[ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP(1, 0),
|
||||
};
|
||||
|
||||
static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = {
|
||||
@@ -63,6 +69,12 @@ static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = {
|
||||
[ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1),
|
||||
[ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1),
|
||||
[ARMV8_OPC_HLT] = ARMV8_HLT_A1(11),
|
||||
[ARMV8_OPC_LDRB_IP] = ARMV4_5_LDRB_IP(1, 0),
|
||||
[ARMV8_OPC_LDRH_IP] = ARMV4_5_LDRH_IP(1, 0),
|
||||
[ARMV8_OPC_LDRW_IP] = ARMV4_5_LDRW_IP(1, 0),
|
||||
[ARMV8_OPC_STRB_IP] = ARMV4_5_STRB_IP(1, 0),
|
||||
[ARMV8_OPC_STRH_IP] = ARMV4_5_STRH_IP(1, 0),
|
||||
[ARMV8_OPC_STRW_IP] = ARMV4_5_STRW_IP(1, 0),
|
||||
};
|
||||
|
||||
void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64)
|
||||
|
||||
@@ -159,6 +159,14 @@
|
||||
#define ARMV8_MOVFSP_32(Rt) (0x11000000 | (0x1f << 5) | (Rt))
|
||||
#define ARMV8_MOVTSP_32(Rt) (0x11000000 | (Rt << 5) | (0x1F))
|
||||
|
||||
#define ARMV8_LDRB_IP(Rd, Rn) (0x38401400 | (Rn << 5) | Rd)
|
||||
#define ARMV8_LDRH_IP(Rd, Rn) (0x78402400 | (Rn << 5) | Rd)
|
||||
#define ARMV8_LDRW_IP(Rd, Rn) (0xb8404400 | (Rn << 5) | Rd)
|
||||
|
||||
#define ARMV8_STRB_IP(Rd, Rn) (0x38001400 | (Rn << 5) | Rd)
|
||||
#define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd)
|
||||
#define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd)
|
||||
|
||||
#define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt)
|
||||
|
||||
enum armv8_opcode {
|
||||
@@ -180,6 +188,12 @@ enum armv8_opcode {
|
||||
ARMV8_OPC_DCCIVAC,
|
||||
ARMV8_OPC_ICIVAU,
|
||||
ARMV8_OPC_HLT,
|
||||
ARMV8_OPC_STRB_IP,
|
||||
ARMV8_OPC_STRH_IP,
|
||||
ARMV8_OPC_STRW_IP,
|
||||
ARMV8_OPC_LDRB_IP,
|
||||
ARMV8_OPC_LDRH_IP,
|
||||
ARMV8_OPC_LDRW_IP,
|
||||
ARMV8_OPC_NUM,
|
||||
};
|
||||
|
||||
|
||||
@@ -1707,6 +1707,97 @@ void cortex_m_deinit_target(struct target *target)
|
||||
free(cortex_m);
|
||||
}
|
||||
|
||||
int cortex_m_profiling(struct target *target, uint32_t *samples,
|
||||
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
|
||||
{
|
||||
struct timeval timeout, now;
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
uint32_t reg_value;
|
||||
bool use_pcsr = false;
|
||||
int retval = ERROR_OK;
|
||||
struct reg *reg;
|
||||
|
||||
gettimeofday(&timeout, NULL);
|
||||
timeval_add_time(&timeout, seconds, 0);
|
||||
|
||||
retval = target_read_u32(target, DWT_PCSR, ®_value);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Error while reading PCSR");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (reg_value != 0) {
|
||||
use_pcsr = true;
|
||||
LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can...");
|
||||
} else {
|
||||
LOG_INFO("Starting profiling. Halting and resuming the"
|
||||
" target as often as we can...");
|
||||
reg = register_get_by_name(target->reg_cache, "pc", 1);
|
||||
}
|
||||
|
||||
/* Make sure the target is running */
|
||||
target_poll(target);
|
||||
if (target->state == TARGET_HALTED)
|
||||
retval = target_resume(target, 1, 0, 0, 0);
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Error while resuming target");
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint32_t sample_count = 0;
|
||||
|
||||
for (;;) {
|
||||
if (use_pcsr) {
|
||||
if (armv7m && armv7m->debug_ap) {
|
||||
uint32_t read_count = max_num_samples - sample_count;
|
||||
if (read_count > 1024)
|
||||
read_count = 1024;
|
||||
|
||||
retval = mem_ap_read_buf_noincr(armv7m->debug_ap,
|
||||
(void *)&samples[sample_count],
|
||||
4, read_count, DWT_PCSR);
|
||||
sample_count += read_count;
|
||||
} else {
|
||||
target_read_u32(target, DWT_PCSR, &samples[sample_count++]);
|
||||
}
|
||||
} else {
|
||||
target_poll(target);
|
||||
if (target->state == TARGET_HALTED) {
|
||||
reg_value = buf_get_u32(reg->value, 0, 32);
|
||||
/* current pc, addr = 0, do not handle breakpoints, not debugging */
|
||||
retval = target_resume(target, 1, 0, 0, 0);
|
||||
samples[sample_count++] = reg_value;
|
||||
target_poll(target);
|
||||
alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
|
||||
} else if (target->state == TARGET_RUNNING) {
|
||||
/* We want to quickly sample the PC. */
|
||||
retval = target_halt(target);
|
||||
} else {
|
||||
LOG_INFO("Target not halted or running");
|
||||
retval = ERROR_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc");
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) {
|
||||
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*num_samples = sample_count;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* REVISIT cache valid/dirty bits are unmaintained. We could set "valid"
|
||||
* on r/w if the core is not running, and clear on resume or reset ... or
|
||||
* at least, in a post_restore_context() method.
|
||||
@@ -2451,4 +2542,6 @@ struct target_type cortexm_target = {
|
||||
.init_target = cortex_m_init_target,
|
||||
.examine = cortex_m_examine,
|
||||
.deinit_target = cortex_m_deinit_target,
|
||||
|
||||
.profiling = cortex_m_profiling,
|
||||
};
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#define DWT_CTRL 0xE0001000
|
||||
#define DWT_CYCCNT 0xE0001004
|
||||
#define DWT_PCSR 0xE000101C
|
||||
#define DWT_COMP0 0xE0001020
|
||||
#define DWT_MASK0 0xE0001024
|
||||
#define DWT_FUNCTION0 0xE0001028
|
||||
@@ -212,5 +213,7 @@ void cortex_m_enable_breakpoints(struct target *target);
|
||||
void cortex_m_enable_watchpoints(struct target *target);
|
||||
void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target);
|
||||
void cortex_m_deinit_target(struct target *target);
|
||||
int cortex_m_profiling(struct target *target, uint32_t *samples,
|
||||
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
|
||||
|
||||
#endif /* OPENOCD_TARGET_CORTEX_M_H */
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "embeddedice.h"
|
||||
#include "register.h"
|
||||
#include <helper/time_support.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
@@ -576,8 +577,8 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
|
||||
uint8_t field2_out[1];
|
||||
int retval;
|
||||
uint32_t hsact;
|
||||
struct timeval lap;
|
||||
struct timeval now;
|
||||
struct timeval timeout_end;
|
||||
|
||||
if (hsbit == EICE_COMM_CTRL_WBIT)
|
||||
hsact = 1;
|
||||
@@ -610,7 +611,8 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
|
||||
fields[2].in_value = NULL;
|
||||
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
gettimeofday(&lap, NULL);
|
||||
gettimeofday(&timeout_end, NULL);
|
||||
timeval_add_time(&timeout_end, 0, timeout * 1000);
|
||||
do {
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
retval = jtag_execute_queue();
|
||||
@@ -621,8 +623,7 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
|
||||
return ERROR_OK;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
} while ((uint32_t)((now.tv_sec - lap.tv_sec) * 1000
|
||||
+ (now.tv_usec - lap.tv_usec) / 1000) <= timeout);
|
||||
} while (timeval_compare(&now, &timeout_end) <= 0);
|
||||
|
||||
LOG_ERROR("embeddedice handshake timeout");
|
||||
return ERROR_TARGET_TIMEOUT;
|
||||
|
||||
@@ -814,4 +814,5 @@ struct target_type hla_target = {
|
||||
.remove_breakpoint = cortex_m_remove_breakpoint,
|
||||
.add_watchpoint = cortex_m_add_watchpoint,
|
||||
.remove_watchpoint = cortex_m_remove_watchpoint,
|
||||
.profiling = cortex_m_profiling,
|
||||
};
|
||||
|
||||
+138
-11
@@ -444,6 +444,8 @@ static uint32_t get_tapstatus(struct target *t)
|
||||
static int enter_probemode(struct target *t)
|
||||
{
|
||||
uint32_t tapstatus = 0;
|
||||
int retries = 100;
|
||||
|
||||
tapstatus = get_tapstatus(t);
|
||||
LOG_DEBUG("TS before PM enter = 0x%08" PRIx32, tapstatus);
|
||||
if (tapstatus & TS_PM_BIT) {
|
||||
@@ -456,15 +458,17 @@ static int enter_probemode(struct target *t)
|
||||
scan.out[0] = 1;
|
||||
if (drscan(t, scan.out, scan.in, 1) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
tapstatus = get_tapstatus(t);
|
||||
LOG_DEBUG("TS after PM enter = 0x%08" PRIx32, tapstatus);
|
||||
if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT)))
|
||||
return ERROR_OK;
|
||||
else {
|
||||
LOG_ERROR("%s PM enter error, tapstatus = 0x%08" PRIx32
|
||||
, __func__, tapstatus);
|
||||
return ERROR_FAIL;
|
||||
|
||||
while (retries--) {
|
||||
tapstatus = get_tapstatus(t);
|
||||
LOG_DEBUG("TS after PM enter = 0x%08" PRIx32, tapstatus);
|
||||
if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT)))
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
LOG_ERROR("%s PM enter error, tapstatus = 0x%08" PRIx32
|
||||
, __func__, tapstatus);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int exit_probemode(struct target *t)
|
||||
@@ -966,6 +970,7 @@ int lakemont_poll(struct target *t)
|
||||
return target_call_event_callbacks(t, TARGET_EVENT_HALTED);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1111,15 +1116,137 @@ int lakemont_step(struct target *t, int current,
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* TODO - implement resetbreak fully through CLTAP registers */
|
||||
static int lakemont_reset_break(struct target *t)
|
||||
{
|
||||
struct x86_32_common *x86_32 = target_to_x86_32(t);
|
||||
struct jtag_tap *saved_tap = x86_32->curr_tap;
|
||||
struct scan_field *fields = &scan.field;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
||||
LOG_DEBUG("issuing port 0xcf9 reset");
|
||||
|
||||
/* prepare resetbreak setting the proper bits in CLTAPC_CPU_VPREQ */
|
||||
x86_32->curr_tap = jtag_tap_by_position(1);
|
||||
if (x86_32->curr_tap == NULL) {
|
||||
x86_32->curr_tap = saved_tap;
|
||||
LOG_ERROR("%s could not select quark_x10xx.cltap", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
fields->in_value = NULL;
|
||||
fields->num_bits = 8;
|
||||
|
||||
/* select CLTAPC_CPU_VPREQ instruction*/
|
||||
scan.out[0] = 0x51;
|
||||
fields->out_value = ((uint8_t *)scan.out);
|
||||
jtag_add_ir_scan(x86_32->curr_tap, fields, TAP_IDLE);
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK) {
|
||||
x86_32->curr_tap = saved_tap;
|
||||
LOG_ERROR("%s irscan failed to execute queue", __func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* set enable_preq_on_reset & enable_preq_on_reset2 bits*/
|
||||
scan.out[0] = 0x06;
|
||||
fields->out_value = ((uint8_t *)scan.out);
|
||||
jtag_add_dr_scan(x86_32->curr_tap, 1, fields, TAP_IDLE);
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("%s drscan failed to execute queue", __func__);
|
||||
x86_32->curr_tap = saved_tap;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* restore current tap */
|
||||
x86_32->curr_tap = saved_tap;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we ever get an adapter with support for PREQ# and PRDY#, we should
|
||||
* update this function to add support for using those two signals.
|
||||
*
|
||||
* Meanwhile, we're assuming that we only support reset break.
|
||||
*/
|
||||
int lakemont_reset_assert(struct target *t)
|
||||
{
|
||||
LOG_DEBUG("-");
|
||||
struct x86_32_common *x86_32 = target_to_x86_32(t);
|
||||
/* write 0x6 to I/O port 0xcf9 to cause the reset */
|
||||
uint8_t cf9_reset_val = 0x6;
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG(" ");
|
||||
|
||||
if (t->state != TARGET_HALTED) {
|
||||
LOG_DEBUG("target must be halted first");
|
||||
retval = lakemont_halt(t);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("could not halt target");
|
||||
return retval;
|
||||
}
|
||||
x86_32->forced_halt_for_reset = true;
|
||||
}
|
||||
|
||||
if (t->reset_halt) {
|
||||
retval = lakemont_reset_break(t);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = x86_32_common_write_io(t, 0xcf9, BYTE, &cf9_reset_val);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("could not write to port 0xcf9");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!t->reset_halt && x86_32->forced_halt_for_reset) {
|
||||
x86_32->forced_halt_for_reset = false;
|
||||
retval = lakemont_resume(t, true, 0x00, false, true);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* remove breakpoints and watchpoints */
|
||||
x86_32_common_reset_breakpoints_watchpoints(t);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lakemont_reset_deassert(struct target *t)
|
||||
{
|
||||
LOG_DEBUG("-");
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG(" ");
|
||||
|
||||
if (target_was_examined(t)) {
|
||||
retval = lakemont_poll(t);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (t->reset_halt) {
|
||||
/* entered PM after reset, update the state */
|
||||
retval = lakemont_update_after_probemode_entry(t);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("could not update state after probemode entry");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (t->state != TARGET_HALTED) {
|
||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
||||
target_name(t));
|
||||
if (target_was_examined(t)) {
|
||||
retval = target_halt(t);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
} else {
|
||||
t->state = TARGET_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
#define EJTAG_INST_TCBCONTROLA 0x10
|
||||
#define EJTAG_INST_TCBCONTROLB 0x11
|
||||
#define EJTAG_INST_TCBDATA 0x12
|
||||
#define EJTAG_INST_TCBCONTROLC 0x13
|
||||
#define EJTAG_INST_PCSAMPLE 0x14
|
||||
#define EJTAG_INST_TCBCONTROLD 0x15
|
||||
#define EJTAG_INST_TCBCONTROLE 0x16
|
||||
#define EJTAG_INST_FDC 0x17
|
||||
#define EJTAG_INST_BYPASS 0xFF
|
||||
|
||||
/* microchip PIC32MX specific instructions */
|
||||
|
||||
@@ -1248,8 +1248,7 @@ static int or1k_profiling(struct target *target, uint32_t *samples,
|
||||
samples[sample_count++] = reg_value;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if ((sample_count >= max_num_samples) ||
|
||||
((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
|
||||
if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) > 0) {
|
||||
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
|
||||
break;
|
||||
}
|
||||
|
||||
+31
-32
@@ -51,48 +51,47 @@
|
||||
#include "lakemont.h"
|
||||
#include "x86_32_common.h"
|
||||
|
||||
int quark_x10xx_target_create(struct target *t, Jim_Interp *interp)
|
||||
static int quark_x10xx_target_create(struct target *t, Jim_Interp *interp)
|
||||
{
|
||||
struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common));
|
||||
if (x86_32 == NULL) {
|
||||
LOG_ERROR("%s out of memory", __func__);
|
||||
struct x86_32_common *x86_32 = calloc(1, sizeof(*x86_32));
|
||||
|
||||
if (!x86_32)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
x86_32_common_init_arch_info(t, x86_32);
|
||||
lakemont_init_arch_info(t, x86_32);
|
||||
x86_32->core_type = LMT1;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int quark_x10xx_init_target(struct command_context *cmd_ctx, struct target *t)
|
||||
{
|
||||
return lakemont_init_target(cmd_ctx, t);
|
||||
}
|
||||
|
||||
struct target_type quark_x10xx_target = {
|
||||
.name = "quark_x10xx",
|
||||
.name = "quark_x10xx",
|
||||
|
||||
/* Quark X1000 SoC */
|
||||
.target_create = quark_x10xx_target_create,
|
||||
.init_target = quark_x10xx_init_target,
|
||||
.target_create = quark_x10xx_target_create,
|
||||
|
||||
/* lakemont probemode specific code */
|
||||
.poll = lakemont_poll,
|
||||
.arch_state = lakemont_arch_state,
|
||||
.halt = lakemont_halt,
|
||||
.resume = lakemont_resume,
|
||||
.step = lakemont_step,
|
||||
.assert_reset = lakemont_reset_assert,
|
||||
.deassert_reset = lakemont_reset_deassert,
|
||||
.arch_state = lakemont_arch_state,
|
||||
.assert_reset = lakemont_reset_assert,
|
||||
.deassert_reset = lakemont_reset_deassert,
|
||||
.halt = lakemont_halt,
|
||||
.init_target = lakemont_init_target,
|
||||
.poll = lakemont_poll,
|
||||
.resume = lakemont_resume,
|
||||
.step = lakemont_step,
|
||||
|
||||
/* common x86 code */
|
||||
.commands = x86_32_command_handlers,
|
||||
.get_gdb_reg_list = x86_32_get_gdb_reg_list,
|
||||
.read_memory = x86_32_common_read_memory,
|
||||
.write_memory = x86_32_common_write_memory,
|
||||
.add_breakpoint = x86_32_common_add_breakpoint,
|
||||
.remove_breakpoint = x86_32_common_remove_breakpoint,
|
||||
.add_watchpoint = x86_32_common_add_watchpoint,
|
||||
.remove_watchpoint = x86_32_common_remove_watchpoint,
|
||||
.virt2phys = x86_32_common_virt2phys,
|
||||
.read_phys_memory = x86_32_common_read_phys_mem,
|
||||
.write_phys_memory = x86_32_common_write_phys_mem,
|
||||
.mmu = x86_32_common_mmu,
|
||||
.add_breakpoint = x86_32_common_add_breakpoint,
|
||||
.add_watchpoint = x86_32_common_add_watchpoint,
|
||||
.commands = x86_32_command_handlers,
|
||||
.get_gdb_reg_list = x86_32_get_gdb_reg_list,
|
||||
.mmu = x86_32_common_mmu,
|
||||
.read_memory = x86_32_common_read_memory,
|
||||
.read_phys_memory = x86_32_common_read_phys_mem,
|
||||
.remove_breakpoint = x86_32_common_remove_breakpoint,
|
||||
.remove_watchpoint = x86_32_common_remove_watchpoint,
|
||||
.virt2phys = x86_32_common_virt2phys,
|
||||
.write_memory = x86_32_common_write_memory,
|
||||
.write_phys_memory = x86_32_common_write_phys_mem,
|
||||
};
|
||||
|
||||
+16
-25
@@ -1399,7 +1399,6 @@ int target_register_trace_callback(int (*callback)(struct target *target,
|
||||
int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
|
||||
{
|
||||
struct target_timer_callback **callbacks_p = &target_timer_callbacks;
|
||||
struct timeval now;
|
||||
|
||||
if (callback == NULL)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -1416,14 +1415,8 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int
|
||||
(*callbacks_p)->time_ms = time_ms;
|
||||
(*callbacks_p)->removed = false;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
(*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
|
||||
time_ms -= (time_ms % 1000);
|
||||
(*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000);
|
||||
if ((*callbacks_p)->when.tv_usec > 1000000) {
|
||||
(*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000;
|
||||
(*callbacks_p)->when.tv_sec += 1;
|
||||
}
|
||||
gettimeofday(&(*callbacks_p)->when, NULL);
|
||||
timeval_add_time(&(*callbacks_p)->when, 0, time_ms * 1000);
|
||||
|
||||
(*callbacks_p)->priv = priv;
|
||||
(*callbacks_p)->next = NULL;
|
||||
@@ -1558,14 +1551,8 @@ int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data
|
||||
static int target_timer_callback_periodic_restart(
|
||||
struct target_timer_callback *cb, struct timeval *now)
|
||||
{
|
||||
int time_ms = cb->time_ms;
|
||||
cb->when.tv_usec = now->tv_usec + (time_ms % 1000) * 1000;
|
||||
time_ms -= (time_ms % 1000);
|
||||
cb->when.tv_sec = now->tv_sec + time_ms / 1000;
|
||||
if (cb->when.tv_usec > 1000000) {
|
||||
cb->when.tv_usec = cb->when.tv_usec - 1000000;
|
||||
cb->when.tv_sec += 1;
|
||||
}
|
||||
cb->when = *now;
|
||||
timeval_add_time(&cb->when, 0, cb->time_ms * 1000L);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1609,9 +1596,7 @@ static int target_call_timer_callbacks_check_time(int checktime)
|
||||
|
||||
bool call_it = (*callback)->callback &&
|
||||
((!checktime && (*callback)->periodic) ||
|
||||
now.tv_sec > (*callback)->when.tv_sec ||
|
||||
(now.tv_sec == (*callback)->when.tv_sec &&
|
||||
now.tv_usec >= (*callback)->when.tv_usec));
|
||||
timeval_compare(&now, &(*callback)->when) >= 0);
|
||||
|
||||
if (call_it)
|
||||
target_call_timer_callback(*callback, &now);
|
||||
@@ -2030,8 +2015,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples,
|
||||
break;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if ((sample_count >= max_num_samples) ||
|
||||
((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
|
||||
if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) >= 0) {
|
||||
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
|
||||
break;
|
||||
}
|
||||
@@ -3131,6 +3115,10 @@ COMMAND_HANDLER(handle_md_command)
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count);
|
||||
|
||||
uint8_t *buffer = calloc(count, size);
|
||||
if (buffer == NULL) {
|
||||
LOG_ERROR("Failed to allocate md read buffer");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
int retval = fn(target, address, size, count, buffer);
|
||||
@@ -3853,7 +3841,7 @@ typedef unsigned char UNIT[2]; /* unit of profiling */
|
||||
|
||||
/* Dump a gmon.out histogram file. */
|
||||
static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range,
|
||||
uint32_t start_address, uint32_t end_address, struct target *target)
|
||||
uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms)
|
||||
{
|
||||
uint32_t i;
|
||||
FILE *f = fopen(filename, "w");
|
||||
@@ -3921,7 +3909,8 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena
|
||||
writeLong(f, min, target); /* low_pc */
|
||||
writeLong(f, max, target); /* high_pc */
|
||||
writeLong(f, numBuckets, target); /* # of buckets */
|
||||
writeLong(f, 100, target); /* KLUDGE! We lie, ca. 100Hz best case. */
|
||||
float sample_rate = sampleNum / (duration_ms / 1000.0);
|
||||
writeLong(f, sample_rate, target);
|
||||
writeString(f, "seconds");
|
||||
for (i = 0; i < (15-strlen("seconds")); i++)
|
||||
writeData(f, &zero, 1);
|
||||
@@ -3970,6 +3959,7 @@ COMMAND_HANDLER(handle_profile_command)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint64_t timestart_ms = timeval_ms();
|
||||
/**
|
||||
* Some cores let us sample the PC without the
|
||||
* annoying halt/resume step; for example, ARMv7 PCSR.
|
||||
@@ -3981,6 +3971,7 @@ COMMAND_HANDLER(handle_profile_command)
|
||||
free(samples);
|
||||
return retval;
|
||||
}
|
||||
uint32_t duration_ms = timeval_ms() - timestart_ms;
|
||||
|
||||
assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM);
|
||||
|
||||
@@ -4013,7 +4004,7 @@ COMMAND_HANDLER(handle_profile_command)
|
||||
}
|
||||
|
||||
write_gmon(samples, num_of_samples, CMD_ARGV[1],
|
||||
with_range, start_address, end_address, target);
|
||||
with_range, start_address, end_address, target, duration_ms);
|
||||
command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
|
||||
|
||||
free(samples);
|
||||
|
||||
@@ -84,7 +84,7 @@ struct target_type {
|
||||
* "halt".
|
||||
*
|
||||
* reset run; halt
|
||||
*/
|
||||
*/
|
||||
int (*deassert_reset)(struct target *target);
|
||||
int (*soft_reset_halt)(struct target *target);
|
||||
|
||||
|
||||
+60
-15
@@ -209,15 +209,16 @@ static int read_phys_mem(struct target *t, uint32_t phys_address,
|
||||
LOG_ERROR("%s invalid read size", __func__);
|
||||
break;
|
||||
}
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
/* restore CR0.PG bit if needed (regardless of retval) */
|
||||
if (pg_disabled) {
|
||||
retval = x86_32->enable_paging(t);
|
||||
if (retval != ERROR_OK) {
|
||||
int retval2 = x86_32->enable_paging(t);
|
||||
if (retval2 != ERROR_OK) {
|
||||
LOG_ERROR("%s could not enable paging", __func__);
|
||||
return retval;
|
||||
return retval2;
|
||||
}
|
||||
pg_disabled = true;
|
||||
}
|
||||
/* TODO: After reading memory from target, we must replace
|
||||
* software breakpoints with the original instructions again.
|
||||
@@ -364,6 +365,9 @@ static int read_mem(struct target *t, uint32_t size,
|
||||
break;
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* read_hw_reg() will write to 4 bytes (uint32_t)
|
||||
* Watch out, the buffer passed into read_mem() might be 1 or 2 bytes.
|
||||
*/
|
||||
@@ -436,6 +440,10 @@ static int write_mem(struct target *t, uint32_t size,
|
||||
LOG_ERROR("%s invalid write mem size", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = x86_32->transaction_status(t);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("%s error on mem write", __func__);
|
||||
@@ -606,7 +614,6 @@ int x86_32_common_read_memory(struct target *t, target_addr_t addr,
|
||||
&& x86_32_common_read_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) {
|
||||
LOG_ERROR("%s failed to read memory from physical address " TARGET_ADDR_FMT,
|
||||
__func__, physaddr);
|
||||
retval = ERROR_FAIL;
|
||||
}
|
||||
/* restore PG bit if it was cleared prior (regardless of retval) */
|
||||
retval = x86_32->enable_paging(t);
|
||||
@@ -662,7 +669,6 @@ int x86_32_common_write_memory(struct target *t, target_addr_t addr,
|
||||
&& x86_32_common_write_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) {
|
||||
LOG_ERROR("%s failed to write memory to physical address " TARGET_ADDR_FMT,
|
||||
__func__, physaddr);
|
||||
retval = ERROR_FAIL;
|
||||
}
|
||||
/* restore PG bit if it was cleared prior (regardless of retval) */
|
||||
retval = x86_32->enable_paging(t);
|
||||
@@ -733,15 +739,19 @@ int x86_32_common_read_io(struct target *t, uint32_t addr,
|
||||
LOG_ERROR("%s invalid read io size", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* restore CR0.PG bit if needed */
|
||||
if (pg_disabled) {
|
||||
retval = x86_32->enable_paging(t);
|
||||
if (retval != ERROR_OK) {
|
||||
int retval2 = x86_32->enable_paging(t);
|
||||
if (retval2 != ERROR_OK) {
|
||||
LOG_ERROR("%s could not enable paging", __func__);
|
||||
return retval;
|
||||
return retval2;
|
||||
}
|
||||
pg_disabled = false;
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
uint32_t regval = 0;
|
||||
retval = x86_32->read_hw_reg(t, EAX, ®val, 0);
|
||||
if (retval != ERROR_OK) {
|
||||
@@ -818,15 +828,19 @@ int x86_32_common_write_io(struct target *t, uint32_t addr,
|
||||
LOG_ERROR("%s invalid write io size", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* restore CR0.PG bit if needed */
|
||||
if (pg_disabled) {
|
||||
retval = x86_32->enable_paging(t);
|
||||
if (retval != ERROR_OK) {
|
||||
int retval2 = x86_32->enable_paging(t);
|
||||
if (retval2 != ERROR_OK) {
|
||||
LOG_ERROR("%s could not enable paging", __func__);
|
||||
return retval;
|
||||
return retval2;
|
||||
}
|
||||
pg_disabled = false;
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = x86_32->transaction_status(t);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("%s error on io write", __func__);
|
||||
@@ -1141,7 +1155,6 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp)
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("%s core doesn't support SW breakpoints", __func__);
|
||||
error = ERROR_FAIL;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
@@ -1260,6 +1273,38 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* after reset breakpoints and watchpoints in memory are not valid anymore and
|
||||
* debug registers are cleared.
|
||||
* we can't afford to remove sw breakpoints using the default methods as the
|
||||
* memory doesn't have the same layout yet and an access might crash the target,
|
||||
* so we just clear the openocd breakpoints structures.
|
||||
*/
|
||||
void x86_32_common_reset_breakpoints_watchpoints(struct target *t)
|
||||
{
|
||||
struct x86_32_common *x86_32 = target_to_x86_32(t);
|
||||
struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
|
||||
struct breakpoint *next_b;
|
||||
struct watchpoint *next_w;
|
||||
|
||||
while (t->breakpoints) {
|
||||
next_b = t->breakpoints->next;
|
||||
free(t->breakpoints->orig_instr);
|
||||
free(t->breakpoints);
|
||||
t->breakpoints = next_b;
|
||||
}
|
||||
|
||||
while (t->watchpoints) {
|
||||
next_w = t->watchpoints->next;
|
||||
free(t->watchpoints);
|
||||
t->watchpoints = next_w;
|
||||
}
|
||||
|
||||
for (int i = 0; i < x86_32->num_hw_bpoints; i++) {
|
||||
debug_reg_list[i].used = 0;
|
||||
debug_reg_list[i].bp_value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hw_reg_to_cache(struct target *t, int num)
|
||||
{
|
||||
uint32_t reg_value;
|
||||
|
||||
@@ -217,6 +217,7 @@ struct x86_32_common {
|
||||
struct reg_cache *cache;
|
||||
struct jtag_tap *curr_tap;
|
||||
uint32_t stored_pc;
|
||||
int forced_halt_for_reset;
|
||||
int flush;
|
||||
|
||||
/* pm_regs are for probemode save/restore state */
|
||||
@@ -326,5 +327,6 @@ int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp);
|
||||
int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp);
|
||||
int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp);
|
||||
int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp);
|
||||
void x86_32_common_reset_breakpoints_watchpoints(struct target *t);
|
||||
|
||||
#endif /* OPENOCD_TARGET_X86_32_COMMON_H */
|
||||
|
||||
+1
-2
@@ -404,8 +404,7 @@ static int xscale_read_tx(struct target *target, int consume)
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if ((now.tv_sec > timeout.tv_sec) ||
|
||||
((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) {
|
||||
if (timeval_compare(&now, &timeout) > 0) {
|
||||
LOG_ERROR("time out reading TX register");
|
||||
return ERROR_TARGET_TIMEOUT;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user