target algo: do not write reg_param if direction is PARAM_IN
[openocd.git] / src / target / nds32_v3_common.c
index 2fbd1a3780ad61928f76febcd38e6a3d3dfd841a..271ffdd1cebdcc33dfa9bb700f337a420ac4d687 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #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,14 +367,8 @@ int nds32_v3_target_request_data(struct target *target,
        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)
+               target_addr_t address, uint32_t count, uint32_t *checksum)
 {
        LOG_WARNING("Not implemented: %s", __func__);
 
@@ -353,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)
 {
@@ -363,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);
@@ -375,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. */
 
@@ -398,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);
@@ -413,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. */
 
@@ -436,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);
@@ -451,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. */
 
@@ -474,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);
@@ -493,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. */
 
@@ -527,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;
 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)