]> git.sur5r.net Git - openocd/blobdiff - src/target/cortex_m3.c
arm920t line length cleanup
[openocd] / src / target / cortex_m3.c
index 9685821977e0e97c6b622b98a992b6b5ebf6a34f..3f347697bd41a8ca76836f3e446225f5daa11fbd 100644 (file)
@@ -80,7 +80,7 @@ static int cortexm3_dap_read_coreregister_u32(struct swjdp_common *swjdp,
        dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
        dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
 
-       retval = swjdp_transaction_endcheck(swjdp);
+       retval = jtagdp_transaction_endcheck(swjdp);
 
        /* restore DCB_DCRDR - this needs to be in a seperate
         * transaction otherwise the emulated DCC channel breaks */
@@ -111,7 +111,7 @@ static int cortexm3_dap_write_coreregister_u32(struct swjdp_common *swjdp,
        dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
        dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR);
 
-       retval = swjdp_transaction_endcheck(swjdp);
+       retval = jtagdp_transaction_endcheck(swjdp);
 
        /* restore DCB_DCRDR - this needs to be in a seperate
         * transaction otherwise the emulated DCC channel breaks */
@@ -185,11 +185,12 @@ static int cortex_m3_endreset_event(struct target *target)
        int i;
        uint32_t dcb_demcr;
        struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
+       struct armv7m_common *armv7m = &cortex_m3->armv7m;
        struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info;
        struct cortex_m3_fp_comparator *fp_list = cortex_m3->fp_comparator_list;
        struct cortex_m3_dwt_comparator *dwt_list = cortex_m3->dwt_comparator_list;
 
-       /* FIXME handling of DEMCR clobbers vector_catch config ... */
+       /* REVISIT The four debug monitor bits are currently ignored... */
        mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &dcb_demcr);
        LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "",dcb_demcr);
 
@@ -204,21 +205,14 @@ static int cortex_m3_endreset_event(struct target *target)
        /* clear any interrupt masking */
        cortex_m3_write_debug_halt_mask(target, 0, C_MASKINTS);
 
-       /* Enable trace and DWT; trap hard and bus faults.
-        *
-        * REVISIT why trap those two?  And why trash the vector_catch
-        * config, instead of preserving it?  Catching HARDERR and BUSERR
-        * will interfere with code that handles those itself...
-        */
-       mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR);
-
-       /* Monitor bus faults as such (instead of as generic HARDERR), but
-        * leave memory management and usage faults disabled.
+       /* Enable features controlled by ITM and DWT blocks, and catch only
+        * the vectors we were told to pay attention to.
         *
-        * REVISIT setting BUSFAULTENA interferes with code which relies
-        * on the default setting.  Why do it?
+        * Target firmware is responsible for all fault handling policy
+        * choices *EXCEPT* explicitly scripted overrides like "vector_catch"
+        * or manual updates to the NVIC SHCSR and CCR registers.
         */
-       mem_ap_write_u32(swjdp, NVIC_SHCSR, SHCSR_BUSFAULTENA);
+       mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | armv7m->demcr);
 
        /* Paranoia: evidently some (early?) chips don't preserve all the
         * debug state (including FBP, DWT, etc) across reset...
@@ -244,7 +238,7 @@ static int cortex_m3_endreset_event(struct target *target)
                target_write_u32(target, dwt_list[i].dwt_comparator_address + 8,
                                dwt_list[i].function);
        }
-       swjdp_transaction_endcheck(swjdp);
+       jtagdp_transaction_endcheck(swjdp);
 
        register_cache_invalidate(cortex_m3->armv7m.core_cache);
 
@@ -323,7 +317,7 @@ static int cortex_m3_examine_exception_reason(struct target *target)
                        except_sr = 0;
                        break;
        }
-       swjdp_transaction_endcheck(swjdp);
+       jtagdp_transaction_endcheck(swjdp);
        LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32 "", armv7m_exception_string(armv7m->exception_number), \
                shcsr, except_sr, cfsr, except_ar);
        return ERROR_OK;
@@ -422,6 +416,21 @@ static int cortex_m3_poll(struct target *target)
                return retval;
        }
 
+       /* 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",
+                               target_name(target));
+               cortex_m3_write_debug_halt_mask(target, C_HALT, 0);
+               target->debug_reason = DBG_REASON_DBGRQ;
+
+               /* refresh status bits */
+               mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
+       }
+
        if (cortex_m3->dcb_dhcsr & S_RESET_ST)
        {
                /* check if still in reset */
@@ -533,7 +542,7 @@ static int cortex_m3_soft_reset_halt(struct target *target)
        uint32_t dcb_dhcsr = 0;
        int retval, timeout = 0;
 
-       /* Enter debug state on reset; see end_reset_event() */
+       /* Enter debug state on reset; restore DEMCR in endreset_event() */
        mem_ap_write_u32(swjdp, DCB_DEMCR,
                        TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
 
@@ -644,6 +653,16 @@ static int cortex_m3_resume(struct target *target, int current,
                r->valid = true;
        }
 
+       /* if we halted last time due to a bkpt instruction
+        * then we have to manually step over it, otherwise
+        * the core will break again */
+
+       if (!breakpoint_find(target, buf_get_u32(r->value, 0, 32))
+                       && !debug_execution)
+       {
+               armv7m_maybe_skip_bkpt_inst(target, NULL);
+       }
+
        resume_pc = buf_get_u32(r->value, 0, 32);
 
        armv7m_restore_context(target);
@@ -696,6 +715,7 @@ static int cortex_m3_step(struct target *target, int current,
        struct swjdp_common *swjdp = &armv7m->swjdp_info;
        struct breakpoint *breakpoint = NULL;
        struct reg *pc = armv7m->core_cache->reg_list + 15;
+       bool bkpt_inst_found = false;
 
        if (target->state != TARGET_HALTED)
        {
@@ -715,14 +735,23 @@ static int cortex_m3_step(struct target *target, int current,
                        cortex_m3_unset_breakpoint(target, breakpoint);
        }
 
+       armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found);
+
        target->debug_reason = DBG_REASON_SINGLESTEP;
 
        armv7m_restore_context(target);
 
        target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
 
-       /* set step and clear halt */
-       cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+       /* if no bkpt instruction is found at pc then we can perform
+        * a normal step, otherwise we have to manually step over the bkpt
+        * 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);
+       }
+
        mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
 
        /* registers are now invalid */
@@ -741,6 +770,7 @@ static int cortex_m3_step(struct target *target, int current,
        LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32
                        " nvic_icsr = 0x%" PRIx32,
                        cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
+
        return ERROR_OK;
 }
 
@@ -782,14 +812,15 @@ static int cortex_m3_assert_reset(struct target *target)
 
                /* clear C_HALT in dhcsr reg */
                cortex_m3_write_debug_halt_mask(target, 0, C_HALT);
-
-               /* Enter debug state on reset, cf. end_reset_event() */
-               mem_ap_write_u32(swjdp, DCB_DEMCR,
-                               TRCENA | VC_HARDERR | VC_BUSERR);
        }
        else
        {
-               /* Enter debug state on reset, cf. end_reset_event() */
+               /* Halt in debug on reset; endreset_event() restores DEMCR.
+                *
+                * REVISIT catching BUSERR presumably helps to defend against
+                * bad vector table entries.  Should this include MMERR or
+                * other flags too?
+                */
                mem_ap_write_atomic_u32(swjdp, DCB_DEMCR,
                                TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
        }
@@ -1659,8 +1690,8 @@ static int cortex_m3_examine(struct target *target)
                        return retval;
 
                if (((cpuid >> 4) & 0xc3f) == 0xc23)
-                       LOG_DEBUG("Cortex-M3 r%dp%d processor detected",
-                               (cpuid >> 20) & 0xf, (cpuid >> 0) & 0xf);
+                       LOG_DEBUG("Cortex-M3 r%" PRId8 "p%" PRId8 " processor detected",
+                               (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf));
                LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
 
                /* NOTE: FPB and DWT are both optional. */
@@ -1938,12 +1969,20 @@ COMMAND_HANDLER(handle_cortex_m3_vector_catch_command)
                        }
                }
 write:
+               /* For now, armv7m->demcr only stores vector catch flags. */
+               armv7m->demcr = catch;
+
                demcr &= ~0xffff;
                demcr |= catch;
 
-               /* write, but don't assume it stuck */
+               /* write, but don't assume it stuck (why not??) */
                mem_ap_write_u32(swjdp, DCB_DEMCR, demcr);
                mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr);
+
+               /* FIXME be sure to clear DEMCR on clean server shutdown.
+                * Otherwise the vector catch hardware could fire when there's
+                * no debugger hooked up, causing much confusion...
+                */
        }
 
        for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++)
@@ -1989,24 +2028,24 @@ COMMAND_HANDLER(handle_cortex_m3_mask_interrupts_command)
 static const struct command_registration cortex_m3_exec_command_handlers[] = {
        {
                .name = "disassemble",
-               .handler = &handle_cortex_m3_disassemble_command,
+               .handler = handle_cortex_m3_disassemble_command,
                .mode = COMMAND_EXEC,
                .help = "disassemble Thumb2 instructions",
-               .usage = "<address> [<count>]",
+               .usage = "address [count]",
        },
        {
                .name = "maskisr",
-               .handler = &handle_cortex_m3_mask_interrupts_command,
+               .handler = handle_cortex_m3_mask_interrupts_command,
                .mode = COMMAND_EXEC,
                .help = "mask cortex_m3 interrupts",
                .usage = "['on'|'off']",
        },
        {
                .name = "vector_catch",
-               .handler = &handle_cortex_m3_vector_catch_command,
+               .handler = handle_cortex_m3_vector_catch_command,
                .mode = COMMAND_EXEC,
-               .help = "catch hardware vectors",
-               .usage = "['all'|'none'|<list>]",
+               .help = "configure hardware vectors to trigger debug entry",
+               .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]",
        },
        COMMAND_REGISTRATION_DONE
 };