{
LOG_DEBUG("nds32_v3_debug_entry");
- jtag_poll_set_enabled(false);
-
enum target_state backup_state = nds32->target->state;
nds32->target->state = TARGET_HALTED;
if (enable_watchpoint)
CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target));
+ struct breakpoint *syscall_break = &(nds32->syscall_break);
+ if (nds32->virtual_hosting) {
+ if (syscall_break->set) {
+ /** disable virtual hosting */
+
+ /* remove breakpoint at syscall entry */
+ target_remove_breakpoint(nds32->target, syscall_break);
+ syscall_break->set = 0;
+
+ uint32_t value_pc;
+ nds32_get_mapped_reg(nds32, PC, &value_pc);
+ if (value_pc == syscall_break->address)
+ /** process syscall for virtual hosting */
+ nds32->hit_syscall = true;
+ }
+ }
+
if (ERROR_OK != nds32_examine_debug_reason(nds32)) {
nds32->target->state = backup_state;
if (enable_watchpoint)
CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(nds32->target));
- jtag_poll_set_enabled(true);
-
return ERROR_FAIL;
}
*/
CHECK_RETVAL(nds32_restore_context(target));
- /* enable polling */
- jtag_poll_set_enabled(true);
+ if (nds32->virtual_hosting) {
+ /** enable virtual hosting */
+ uint32_t value_ir3;
+ uint32_t entry_size;
+ uint32_t syscall_address;
+
+ /* get syscall entry address */
+ nds32_get_mapped_reg(nds32, IR3, &value_ir3);
+ entry_size = 0x4 << (((value_ir3 >> 14) & 0x3) << 1);
+ syscall_address = (value_ir3 & 0xFFFF0000) + entry_size * 8; /* The index of SYSCALL is 8 */
+
+ if (nds32->hit_syscall) {
+ /* single step to skip syscall entry */
+ /* use IRET to skip syscall */
+ struct aice_port_s *aice = target_to_aice(target);
+ uint32_t value_ir9;
+ uint32_t value_ir6;
+ uint32_t syscall_id;
+
+ nds32_get_mapped_reg(nds32, IR6, &value_ir6);
+ syscall_id = (value_ir6 >> 16) & 0x7FFF;
+
+ if (syscall_id == NDS32_SYSCALL_EXIT) {
+ /* If target hits exit syscall, do not use IRET to skip handler. */
+ aice_step(aice);
+ } else {
+ /* use api->read/write_reg to skip nds32 register cache */
+ uint32_t value_dimbr;
+ aice_read_debug_reg(aice, NDS_EDM_SR_DIMBR, &value_dimbr);
+ aice_write_register(aice, IR11, value_dimbr + 0xC);
+
+ aice_read_register(aice, IR9, &value_ir9);
+ value_ir9 += 4; /* syscall is always 4 bytes */
+ aice_write_register(aice, IR9, value_ir9);
+
+ /* backup hardware breakpoint 0 */
+ uint32_t backup_bpa, backup_bpam, backup_bpc;
+ aice_read_debug_reg(aice, NDS_EDM_SR_BPA0, &backup_bpa);
+ aice_read_debug_reg(aice, NDS_EDM_SR_BPAM0, &backup_bpam);
+ aice_read_debug_reg(aice, NDS_EDM_SR_BPC0, &backup_bpc);
+
+ /* use hardware breakpoint 0 to stop cpu after skipping syscall */
+ aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, value_ir9);
+ aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, 0);
+ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, 0xA);
+
+ /* Execute two IRET.
+ * First IRET is used to quit debug mode.
+ * Second IRET is used to quit current syscall. */
+ uint32_t dim_inst[4] = {NOP, NOP, IRET, IRET};
+ aice_execute(aice, dim_inst, 4);
+
+ /* restore origin hardware breakpoint 0 */
+ aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, backup_bpa);
+ aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, backup_bpam);
+ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, backup_bpc);
+ }
+
+ nds32->hit_syscall = false;
+ }
+
+ /* insert breakpoint at syscall entry */
+ struct breakpoint *syscall_break = &(nds32->syscall_break);
+
+ syscall_break->address = syscall_address;
+ syscall_break->type = BKPT_SOFT;
+ syscall_break->set = 1;
+ target_add_breakpoint(target, syscall_break);
+ }
return ERROR_OK;
}
uint32_t match_count;
int32_t i;
static int32_t number_of_hard_break;
+ uint32_t bp_control;
if (number_of_hard_break == 0) {
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
if (match_bits & (1 << i)) {
aice_read_debug_reg(aice, NDS_EDM_SR_BPA0 + i, address);
match_count++;
+
+ /* If target hits multiple read/access watchpoint,
+ * select the first one. */
+ aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &bp_control);
+ if (0x3 == (bp_control & 0x3)) {
+ match_count = 1;
+ break;
+ }
}
}
nds32_read_opcode(nds32, val_pc, &opcode);
nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction);
- LOG_DEBUG("PC: 0x%08x, access start: 0x%08x, end: 0x%08x", val_pc,
- instruction.access_start, instruction.access_end);
+ LOG_DEBUG("PC: 0x%08" PRIx32 ", access start: 0x%08" PRIx32 ", end: 0x%08" PRIx32,
+ val_pc, instruction.access_start, instruction.access_end);
/* check if multiple hits in the access range */
uint32_t in_range_watch_count = 0;
return ERROR_OK;
}
-int nds32_v3_soft_reset_halt(struct target *target)
-{
- struct aice_port_s *aice = target_to_aice(target);
- return aice_assert_srst(aice, AICE_RESET_HOLD);
-}
-
int nds32_v3_checksum_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *checksum)
{
return ERROR_FAIL;
}
+/**
+ * find out which watchpoint hits
+ * get exception address and compare the address to watchpoints
+ */
+int nds32_v3_hit_watchpoint(struct target *target,
+ struct watchpoint **hit_watchpoint)
+{
+ static struct watchpoint scan_all_watchpoint;
+
+ uint32_t exception_address;
+ struct watchpoint *wp;
+ struct nds32 *nds32 = target_to_nds32(target);
+
+ exception_address = nds32->watched_address;
+
+ if (exception_address == 0xFFFFFFFF)
+ return ERROR_FAIL;
+
+ if (exception_address == 0) {
+ scan_all_watchpoint.address = 0;
+ scan_all_watchpoint.rw = WPT_WRITE;
+ scan_all_watchpoint.next = 0;
+ scan_all_watchpoint.unique_id = 0x5CA8;
+
+ *hit_watchpoint = &scan_all_watchpoint;
+ return ERROR_OK;
+ }
+
+ for (wp = target->watchpoints; wp; wp = wp->next) {
+ if (((exception_address ^ wp->address) & (~wp->mask)) == 0) {
+ *hit_watchpoint = wp;
+
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_FAIL;
+}
+
int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32)
{
nds32->register_map = nds32_v3_register_mapping;
else
return ERROR_FAIL;
- return nds32_read_buffer(target, address, size, buffer);
+ int result;
+ struct aice_port_s *aice = target_to_aice(target);
+ /* give arbitrary initial value to avoid warning messages */
+ enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
+
+ if (nds32->hit_syscall) {
+ /* Use bus mode to access memory during virtual hosting */
+ origin_access_channel = memory->access_channel;
+ memory->access_channel = NDS_MEMORY_ACC_BUS;
+ aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
+ }
+
+ result = nds32_read_buffer(target, address, size, buffer);
+
+ if (nds32->hit_syscall) {
+ /* Restore access_channel after virtual hosting */
+ memory->access_channel = origin_access_channel;
+ aice_memory_access(aice, origin_access_channel);
+ }
+
+ return result;
}
int nds32_v3_write_buffer(struct target *target, uint32_t address,
else
return ERROR_FAIL;
+ if (nds32->hit_syscall) {
+ struct aice_port_s *aice = target_to_aice(target);
+ enum nds_memory_access origin_access_channel;
+ origin_access_channel = memory->access_channel;
+
+ /* If target has no cache, use BUS mode to access memory. */
+ if ((memory->dcache.line_size == 0)
+ || (memory->dcache.enable == false)) {
+ /* There is no Dcache or Dcache is disabled. */
+ memory->access_channel = NDS_MEMORY_ACC_BUS;
+ aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
+ }
+
+ int result;
+ result = nds32_gdb_fileio_write_memory(nds32, address, size, buffer);
+
+ if (NDS_MEMORY_ACC_CPU == origin_access_channel) {
+ memory->access_channel = NDS_MEMORY_ACC_CPU;
+ aice_memory_access(aice, NDS_MEMORY_ACC_CPU);
+ }
+
+ return result;
+ }
+
return nds32_write_buffer(target, address, size, buffer);
}
else
return ERROR_FAIL;
+ struct aice_port_s *aice = target_to_aice(target);
+ /* give arbitrary initial value to avoid warning messages */
+ enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
int result;
+ if (nds32->hit_syscall) {
+ /* Use bus mode to access memory during virtual hosting */
+ origin_access_channel = memory->access_channel;
+ memory->access_channel = NDS_MEMORY_ACC_BUS;
+ aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
+ }
+
result = nds32_read_memory(target, address, size, count, buffer);
+ if (nds32->hit_syscall) {
+ /* Restore access_channel after virtual hosting */
+ memory->access_channel = origin_access_channel;
+ aice_memory_access(aice, origin_access_channel);
+ }
+
return result;
}
nds32_init(nds32);
+ target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
+ target->fileio_info->identifier = NULL;
+
return ERROR_OK;
}