X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fnds32_v3_common.c;h=271ffdd1cebdcc33dfa9bb700f337a420ac4d687;hp=49d841311f23660f431393fe93384cdbbbb28164;hb=010b09121ca08f955921654c6a3d405be80afef1;hpb=cf8a3c3d7075abad3c88cd604f8add4d06898abc diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c index 49d841311f..271ffdd1ce 100644 --- a/src/target/nds32_v3_common.c +++ b/src/target/nds32_v3_common.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -59,8 +57,6 @@ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) { LOG_DEBUG("nds32_v3_debug_entry"); - jtag_poll_set_enabled(false); - enum target_state backup_state = nds32->target->state; nds32->target->state = TARGET_HALTED; @@ -80,6 +76,23 @@ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) 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; @@ -89,8 +102,6 @@ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) if (enable_watchpoint) CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(nds32->target)); - jtag_poll_set_enabled(true); - return ERROR_FAIL; } @@ -132,8 +143,75 @@ static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoin */ 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; } @@ -151,6 +229,7 @@ static int nds32_v3_get_exception_address(struct nds32 *nds32, 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); @@ -166,6 +245,14 @@ static int nds32_v3_get_exception_address(struct nds32 *nds32, 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; + } } } @@ -192,8 +279,8 @@ static int nds32_v3_get_exception_address(struct nds32 *nds32, 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; @@ -280,16 +367,49 @@ int nds32_v3_target_request_data(struct target *target, return ERROR_OK; } -int nds32_v3_soft_reset_halt(struct target *target) +int nds32_v3_checksum_memory(struct target *target, + target_addr_t address, uint32_t count, uint32_t *checksum) { - struct aice_port_s *aice = target_to_aice(target); - return aice_assert_srst(aice, AICE_RESET_HOLD); + LOG_WARNING("Not implemented: %s", __func__); + + return ERROR_FAIL; } -int nds32_v3_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum) +/** + * 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) { - LOG_WARNING("Not implemented: %s", __func__); + 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; } @@ -314,8 +434,8 @@ int nds32_v3_run_algorithm(struct target *target, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, - uint32_t exit_point, + target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) { @@ -324,7 +444,7 @@ int nds32_v3_run_algorithm(struct target *target, return ERROR_FAIL; } -int nds32_v3_read_buffer(struct target *target, uint32_t address, +int nds32_v3_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -336,7 +456,7 @@ int nds32_v3_read_buffer(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -359,10 +479,30 @@ int nds32_v3_read_buffer(struct target *target, uint32_t address, 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, +int nds32_v3_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -374,7 +514,7 @@ int nds32_v3_write_buffer(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -397,10 +537,34 @@ 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); } -int nds32_v3_read_memory(struct target *target, uint32_t address, +int nds32_v3_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -412,7 +576,7 @@ int nds32_v3_read_memory(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -435,14 +599,30 @@ int nds32_v3_read_memory(struct target *target, uint32_t address, 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; } -int nds32_v3_write_memory(struct target *target, uint32_t address, +int nds32_v3_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -454,7 +634,7 @@ int nds32_v3_write_memory(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -488,5 +668,8 @@ int nds32_v3_init_target(struct command_context *cmd_ctx, nds32_init(nds32); + target->fileio_info = malloc(sizeof(struct gdb_fileio_info)); + target->fileio_info->identifier = NULL; + return ERROR_OK; }