warning fix: remove senseless assignment before bailing out of fn w/error
[fw/openocd] / src / target / cortex_m3.c
index 2a58f5bf0d6201f801737acbb584d7665bb7b52e..a2f8b78e13f79f4ac3c459564eabda5d03d5d7d0 100644 (file)
@@ -39,6 +39,7 @@
 #include "register.h"
 #include "arm_opcodes.h"
 #include "arm_semihosting.h"
+#include <helper/time_support.h>
 
 /* NOTE:  most of this should work fine for the Cortex-M1 and
  * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M.
  * any longer.
  */
 
+/**
+ * Returns the type of a break point required by address location
+ */
+#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT)
+
 
 /* forward declarations */
 static int cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint);
@@ -520,7 +526,8 @@ static int cortex_m3_debug_entry(struct target *target)
 
 static int cortex_m3_poll(struct target *target)
 {
-       int retval;
+       int detected_failure = ERROR_OK;
+       int retval = ERROR_OK;
        enum target_state prev_target_state = target->state;
        struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
        struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap;
@@ -535,15 +542,18 @@ static int cortex_m3_poll(struct target *target)
 
        /* Recover from lockup.  See ARMv7-M architecture spec,
         * section B1.5.15 "Unrecoverable exception cases".
-        *
-        * REVISIT Is there a better way to report and handle this?
         */
        if (cortex_m3->dcb_dhcsr & S_LOCKUP) {
-               LOG_WARNING("%s -- clearing lockup after double fault",
+               LOG_ERROR("%s -- clearing lockup after double fault",
                                target_name(target));
                cortex_m3_write_debug_halt_mask(target, C_HALT, 0);
                target->debug_reason = DBG_REASON_DBGRQ;
 
+               /* We have to execute the rest (the "finally" equivalent, but
+                * still throw this exception again).
+                */
+               detected_failure = ERROR_FAIL;
+
                /* refresh status bits */
                retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
                if (retval != ERROR_OK)
@@ -610,11 +620,14 @@ static int cortex_m3_poll(struct target *target)
                if (cortex_m3->dcb_dhcsr & S_RETIRE_ST)
                {
                        target->state = TARGET_RUNNING;
-                       return ERROR_OK;
+                       retval = ERROR_OK;
                }
        }
 
-       return ERROR_OK;
+       /* Did we detect a failure condition that we cleared? */
+       if (detected_failure != ERROR_OK)
+               retval = detected_failure;
+       return retval;
 }
 
 static int cortex_m3_halt(struct target *target)
@@ -846,6 +859,8 @@ static int cortex_m3_step(struct target *target, int current,
        struct breakpoint *breakpoint = NULL;
        struct reg *pc = armv7m->arm.pc;
        bool bkpt_inst_found = false;
+       int retval;
+       bool isr_timed_out = false;
 
        if (target->state != TARGET_HALTED)
        {
@@ -857,10 +872,11 @@ static int cortex_m3_step(struct target *target, int current,
        if (!current)
                buf_set_u32(pc->value, 0, 32, address);
 
+       uint32_t pc_value = buf_get_u32(pc->value, 0, 32);
+
        /* the front-end may request us not to handle breakpoints */
        if (handle_breakpoints) {
-               breakpoint = breakpoint_find(target,
-                               buf_get_u32(pc->value, 0, 32));
+               breakpoint = breakpoint_find(target, pc_value);
                if (breakpoint)
                        cortex_m3_unset_breakpoint(target, breakpoint);
        }
@@ -878,11 +894,79 @@ static int cortex_m3_step(struct target *target, int current,
         * instruction - as such simulate a step */
        if (bkpt_inst_found == false)
        {
-               /* set step and clear halt */
-               cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+               /* Automatic ISR masking mode off: Just step over the next instruction */
+               if ((cortex_m3->isrmasking_mode != CORTEX_M3_ISRMASK_AUTO))
+               {
+                       cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+               }
+               else
+               {
+                       /* Process interrupts during stepping in a way they don't interfere
+                        * debugging.
+                        *
+                        * Principle:
+                        *
+                        * Set a temporary break point at the current pc and let the core run
+                        * with interrupts enabled. Pending interrupts get served and we run
+                        * into the breakpoint again afterwards. Then we step over the next
+                        * instruction with interrupts disabled.
+                        *
+                        * If the pending interrupts don't complete within time, we leave the
+                        * core running. This may happen if the interrupts trigger faster
+                        * than the core can process them or the handler doesn't return.
+                        *
+                        * If no more breakpoints are available we simply do a step with
+                        * interrupts enabled.
+                        *
+                        */
+
+                       /* Set a temporary break point */
+                       retval = breakpoint_add(target, pc_value , 2, BKPT_TYPE_BY_ADDR(pc_value));
+                       bool tmp_bp_set = (retval == ERROR_OK);
+
+                       /* No more breakpoints left, just do a step */
+                       if (!tmp_bp_set)
+                       {
+                               cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+                       }
+                       else
+                       {
+                               /* Start the core */
+                               LOG_DEBUG("Starting core to serve pending interrupts");
+                               int64_t t_start = timeval_ms();
+                               cortex_m3_write_debug_halt_mask(target, 0, C_HALT | C_STEP);
+
+                               /* Wait for pending handlers to complete or timeout */
+                               do {
+                                       retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
+                                       if (retval != ERROR_OK)
+                                       {
+                                               target->state = TARGET_UNKNOWN;
+                                               return retval;
+                                       }
+                                       isr_timed_out = ((timeval_ms() - t_start) > 500);
+                               } while (!((cortex_m3->dcb_dhcsr & S_HALT) || isr_timed_out));
+
+                               /* Remove the temporary breakpoint */
+                               breakpoint_remove(target, pc_value);
+
+                               if (isr_timed_out)
+                               {
+                                       LOG_DEBUG("Interrupt handlers didn't complete within time, "
+                                                       "leaving target running");
+                               }
+                               else
+                               {
+                                       /* Step over next instruction with interrupts disabled */
+                                       cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0);
+                                       cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+                                       /* Re-enable interrupts */
+                                       cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
+                               }
+                       }
+               }
        }
 
-       int retval;
        retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
        if (retval != ERROR_OK)
                return retval;
@@ -893,6 +977,13 @@ static int cortex_m3_step(struct target *target, int current,
        if (breakpoint)
                cortex_m3_set_breakpoint(target, breakpoint);
 
+       if (isr_timed_out) {
+               /* Leave the core running. The user has to stop execution manually. */
+               target->debug_reason = DBG_REASON_NOTHALTED;
+               target->state = TARGET_RUNNING;
+               return ERROR_OK;
+       }
+
        LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32
                        " nvic_icsr = 0x%" PRIx32,
                        cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
@@ -913,20 +1004,22 @@ static int cortex_m3_assert_reset(struct target *target)
 {
        struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
        struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap;
-       int assert_srst = 1;
+       enum cortex_m3_soft_reset_config reset_config = cortex_m3->soft_reset_config;
 
        LOG_DEBUG("target->state: %s",
                target_state_name(target));
 
        enum reset_types jtag_reset_config = jtag_get_reset_config();
 
-       /*
-        * We can reset Cortex-M3 targets using just the NVIC without
-        * requiring SRST, getting a SoC reset (or a core-only reset)
-        * instead of a system reset.
-        */
-       if (!(jtag_reset_config & RESET_HAS_SRST))
-               assert_srst = 0;
+       if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
+               /* allow scripts to override the reset event */
+
+               target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
+               register_cache_invalidate(cortex_m3->armv7m.core_cache);
+               target->state = TARGET_RESET;
+
+               return ERROR_OK;
+       }
 
        /* Enable debug requests */
        int retval;
@@ -975,49 +1068,7 @@ static int cortex_m3_assert_reset(struct target *target)
                        return retval;
        }
 
-       /*
-        * When nRST is asserted on most Stellaris devices, it clears some of
-        * the debug state.  The ARMv7M and Cortex-M3 TRMs say that's wrong;
-        * and OpenOCD depends on those TRMs.  So we won't use SRST on those
-        * chips.  (Only power-on reset should affect debug state, beyond a
-        * few specified bits; not the chip's nRST input, wired to SRST.)
-        *
-        * REVISIT current errata specs don't seem to cover this issue.
-        * Do we have more details than this email?
-        *   https://lists.berlios.de/pipermail
-        *      /openocd-development/2008-August/003065.html
-        */
-       if (strcmp(target->variant, "lm3s") == 0)
-       {
-               /* Check for silicon revisions with the issue. */
-               uint32_t did0;
-
-               if (target_read_u32(target, 0x400fe000, &did0) == ERROR_OK)
-               {
-                       switch ((did0 >> 16) & 0xff)
-                       {
-                               case 0:
-                                       /* all Sandstorm suffer issue */
-                                       assert_srst = 0;
-                                       break;
-
-                               case 1:
-                               case 3:
-                                       /* Fury and DustDevil rev A have
-                                        * this nRST problem.  It should
-                                        * be fixed in rev B silicon.
-                                        */
-                                       if (((did0 >> 8) & 0xff) == 0)
-                                               assert_srst = 0;
-                                       break;
-                               case 4:
-                                       /* Tempest should be fine. */
-                                       break;
-                       }
-               }
-       }
-
-       if (assert_srst)
+       if (jtag_reset_config & RESET_HAS_SRST)
        {
                /* default to asserting srst */
                if (jtag_reset_config & RESET_SRST_PULLS_TRST)
@@ -1032,15 +1083,23 @@ static int cortex_m3_assert_reset(struct target *target)
        else
        {
                /* Use a standard Cortex-M3 software reset mechanism.
-                * SYSRESETREQ will reset SoC peripherals outside the
-                * core, like watchdog timers, if the SoC wires it up
-                * correctly.  Else VECRESET can reset just the core.
+                * We default to using VECRESET as it is supported on all current cores.
+                * This has the disadvantage of not resetting the peripherals, so a
+                * reset-init event handler is needed to perform any peripheral resets.
                 */
                retval = mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR,
-                               AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
+                               AIRCR_VECTKEY | ((reset_config == CORTEX_M3_RESET_SYSRESETREQ)
+                               ? AIRCR_SYSRESETREQ : AIRCR_VECTRESET));
                if (retval != ERROR_OK)
                        return retval;
-               LOG_DEBUG("Using Cortex-M3 SYSRESETREQ");
+
+               LOG_DEBUG("Using Cortex-M3 %s", (reset_config == CORTEX_M3_RESET_SYSRESETREQ)
+                               ? "SYSRESETREQ" : "VECTRESET");
+
+               if (reset_config == CORTEX_M3_RESET_VECTRESET) {
+                       LOG_WARNING("Only resetting the Cortex-M3 core, use a reset-init event "
+                                       "handler to reset any peripherals");
+               }
 
                {
                        /* I do not know why this is necessary, but it
@@ -1096,7 +1155,7 @@ cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint)
 
        if (cortex_m3->auto_bp_type)
        {
-               breakpoint->type = (breakpoint->address < 0x20000000) ? BKPT_HARD : BKPT_SOFT;
+               breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address);
        }
 
        if (breakpoint->type == BKPT_HARD)
@@ -1216,7 +1275,7 @@ cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
 
        if (cortex_m3->auto_bp_type)
        {
-               breakpoint->type = (breakpoint->address < 0x20000000) ? BKPT_HARD : BKPT_SOFT;
+               breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address);
 #ifdef ARMV7_GDB_HACKS
                if (breakpoint->length != 2) {
                        /* XXX Hack: Replace all breakpoints with length != 2 with
@@ -1227,16 +1286,18 @@ cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
 #endif
        }
 
-       if ((breakpoint->type == BKPT_HARD) && (breakpoint->address >= 0x20000000))
-       {
-               LOG_INFO("flash patch comparator requested outside code memory region");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       }
+       if(breakpoint->type != BKPT_TYPE_BY_ADDR(breakpoint->address)) {
+               if (breakpoint->type == BKPT_HARD)
+               {
+                       LOG_INFO("flash patch comparator requested outside code memory region");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
 
-       if ((breakpoint->type == BKPT_SOFT) && (breakpoint->address < 0x20000000))
-       {
-               LOG_INFO("soft breakpoint requested in code (flash) memory region");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               if (breakpoint->type == BKPT_SOFT)
+               {
+                       LOG_INFO("soft breakpoint requested in code (flash) memory region");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
        }
 
        if ((breakpoint->type == BKPT_HARD) && (cortex_m3->fp_code_available < 1))
@@ -1253,9 +1314,8 @@ cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
 
        if (breakpoint->type == BKPT_HARD)
                cortex_m3->fp_code_available--;
-       cortex_m3_set_breakpoint(target, breakpoint);
 
-       return ERROR_OK;
+       return cortex_m3_set_breakpoint(target, breakpoint);
 }
 
 static int
@@ -1272,7 +1332,7 @@ cortex_m3_remove_breakpoint(struct target *target, struct breakpoint *breakpoint
 
        if (cortex_m3->auto_bp_type)
        {
-               breakpoint->type = (breakpoint->address < 0x20000000) ? BKPT_HARD : BKPT_SOFT;
+               breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address);
        }
 
        if (breakpoint->set)
@@ -1569,7 +1629,7 @@ static int cortex_m3_store_core_reg_u32(struct target *target,
                {
                        struct reg *r;
 
-                       LOG_ERROR("JTAG failure %i", retval);
+                       LOG_ERROR("JTAG failure");
                        r = armv7m->core_cache->reg_list + num;
                        r->dirty = r->valid;
                        return ERROR_JTAG_DEVICE_ERROR;
@@ -1644,7 +1704,7 @@ static int cortex_m3_read_memory(struct target *target, uint32_t address,
 }
 
 static int cortex_m3_write_memory(struct target *target, uint32_t address,
-               uint32_t size, uint32_t count, uint8_t *buffer)
+               uint32_t size, uint32_t count, const uint8_t *buffer)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
        struct adiv5_dap *swjdp = &armv7m->dap;
@@ -1668,7 +1728,7 @@ static int cortex_m3_write_memory(struct target *target, uint32_t address,
 }
 
 static int cortex_m3_bulk_write_memory(struct target *target, uint32_t address,
-               uint32_t count, uint8_t *buffer)
+               uint32_t count, const uint8_t *buffer)
 {
        return cortex_m3_write_memory(target, address, 4, count, buffer);
 }
@@ -1969,6 +2029,10 @@ static int cortex_m3_init_arch_info(struct target *target,
        cortex_m3->jtag_info.tap = tap;
        cortex_m3->jtag_info.scann_size = 4;
 
+       /* default reset mode is to use srst if fitted
+        * if not it will use CORTEX_M3_RESET_VECTRESET */
+       cortex_m3->soft_reset_config = CORTEX_M3_RESET_VECTRESET;
+
        armv7m->arm.dap = &armv7m->dap;
 
        /* Leave (only) generic DAP stuff for debugport_init(); */
@@ -2118,6 +2182,15 @@ COMMAND_HANDLER(handle_cortex_m3_mask_interrupts_command)
        struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
        int retval;
 
+       static const Jim_Nvp nvp_maskisr_modes[] = {
+               { .name = "auto", .value = CORTEX_M3_ISRMASK_AUTO },
+               { .name = "off" , .value = CORTEX_M3_ISRMASK_OFF },
+               { .name = "on"  , .value = CORTEX_M3_ISRMASK_ON },
+               { .name = NULL  , .value = -1 },
+       };
+       const Jim_Nvp *n;
+
+
        retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3);
        if (retval != ERROR_OK)
                return retval;
@@ -2130,15 +2203,65 @@ COMMAND_HANDLER(handle_cortex_m3_mask_interrupts_command)
 
        if (CMD_ARGC > 0)
        {
-               bool enable;
-               COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
-               uint32_t mask_on = C_HALT | (enable ? C_MASKINTS : 0);
-               uint32_t mask_off = enable ? 0 : C_MASKINTS;
-               cortex_m3_write_debug_halt_mask(target, mask_on, mask_off);
+               n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+               if (n->name == NULL)
+               {
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               cortex_m3->isrmasking_mode = n->value;
+
+
+               if(cortex_m3->isrmasking_mode == CORTEX_M3_ISRMASK_ON)
+               {
+                       cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0);
+               }
+               else
+               {
+                       cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
+               }
        }
 
-       command_print(CMD_CTX, "cortex_m3 interrupt mask %s",
-                       (cortex_m3->dcb_dhcsr & C_MASKINTS) ? "on" : "off");
+       n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_m3->isrmasking_mode);
+       command_print(CMD_CTX, "cortex_m3 interrupt mask %s", n->name);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_cortex_m3_reset_config_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
+       int retval;
+       char *reset_config;
+
+       retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (CMD_ARGC > 0)
+       {
+               if (strcmp(*CMD_ARGV, "sysresetreq") == 0)
+                       cortex_m3->soft_reset_config = CORTEX_M3_RESET_SYSRESETREQ;
+               else if (strcmp(*CMD_ARGV, "vectreset") == 0)
+                       cortex_m3->soft_reset_config = CORTEX_M3_RESET_VECTRESET;
+       }
+
+       switch (cortex_m3->soft_reset_config)
+       {
+               case CORTEX_M3_RESET_SYSRESETREQ:
+                       reset_config = "sysresetreq";
+                       break;
+
+               case CORTEX_M3_RESET_VECTRESET:
+                       reset_config = "vectreset";
+                       break;
+
+               default:
+                       reset_config = "unknown";
+                       break;
+       }
+
+       command_print(CMD_CTX, "cortex_m3 reset_config %s", reset_config);
 
        return ERROR_OK;
 }
@@ -2149,7 +2272,7 @@ static const struct command_registration cortex_m3_exec_command_handlers[] = {
                .handler = handle_cortex_m3_mask_interrupts_command,
                .mode = COMMAND_EXEC,
                .help = "mask cortex_m3 interrupts",
-               .usage = "['on'|'off']",
+               .usage = "['auto'|'on'|'off']",
        },
        {
                .name = "vector_catch",
@@ -2158,6 +2281,13 @@ static const struct command_registration cortex_m3_exec_command_handlers[] = {
                .help = "configure hardware vectors to trigger debug entry",
                .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]",
        },
+       {
+               .name = "reset_config",
+               .handler = handle_cortex_m3_reset_config_command,
+               .mode = COMMAND_ANY,
+               .help = "configure software reset handling",
+               .usage = "['srst'|'sysresetreq'|'vectreset']",
+       },
        COMMAND_REGISTRATION_DONE
 };
 static const struct command_registration cortex_m3_command_handlers[] = {
@@ -2199,6 +2329,8 @@ struct target_type cortexm3_target =
        .blank_check_memory = armv7m_blank_check_memory,
 
        .run_algorithm = armv7m_run_algorithm,
+       .start_algorithm = armv7m_start_algorithm,
+       .wait_algorithm = armv7m_wait_algorithm,
 
        .add_breakpoint = cortex_m3_add_breakpoint,
        .remove_breakpoint = cortex_m3_remove_breakpoint,