target: lakemon: implement assert_reset and deassert_reset 16/4016/3
authorFelipe Balbi <felipe.balbi@linux.intel.com>
Fri, 24 Feb 2017 13:26:39 +0000 (15:26 +0200)
committerPaul Fertser <fercerpav@gmail.com>
Sat, 13 Jan 2018 09:25:34 +0000 (09:25 +0000)
We're using an I/O port reset by default. The only board currently
supported (Galileo) doesn't have SRST routed on the JTAG connector.

When using 'reset halt', we must rely on Reset Break because our
adapters don't have support for PREQ#/PRDY# signals.

Tested with Intel Galileo GEN2.

Change-Id: Ia406e31c156f8001717d5b6a08bd03f71de790d3
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Reviewed-on: http://openocd.zylin.com/4016
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
src/target/lakemont.c
src/target/x86_32_common.c
src/target/x86_32_common.h

index 5f92f0d..b81213e 100644 (file)
@@ -970,6 +970,7 @@ int lakemont_poll(struct target *t)
                        return target_call_event_callbacks(t, TARGET_EVENT_HALTED);
                }
        }
+
        return ERROR_OK;
 }
 
@@ -1115,15 +1116,137 @@ int lakemont_step(struct target *t, int current,
        return retval;
 }
 
-/* TODO - implement resetbreak fully through CLTAP registers */
+static int lakemont_reset_break(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct jtag_tap *saved_tap = x86_32->curr_tap;
+       struct scan_field *fields = &scan.field;
+
+       int retval = ERROR_OK;
+
+       LOG_DEBUG("issuing port 0xcf9 reset");
+
+       /* prepare resetbreak setting the proper bits in CLTAPC_CPU_VPREQ */
+       x86_32->curr_tap = jtag_tap_by_position(1);
+       if (x86_32->curr_tap == NULL) {
+               x86_32->curr_tap = saved_tap;
+               LOG_ERROR("%s could not select quark_x10xx.cltap", __func__);
+               return ERROR_FAIL;
+       }
+
+       fields->in_value  = NULL;
+       fields->num_bits  = 8;
+
+       /* select CLTAPC_CPU_VPREQ instruction*/
+       scan.out[0] = 0x51;
+       fields->out_value = ((uint8_t *)scan.out);
+       jtag_add_ir_scan(x86_32->curr_tap, fields, TAP_IDLE);
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               x86_32->curr_tap = saved_tap;
+               LOG_ERROR("%s irscan failed to execute queue", __func__);
+               return retval;
+       }
+
+       /* set enable_preq_on_reset & enable_preq_on_reset2 bits*/
+       scan.out[0] = 0x06;
+       fields->out_value  = ((uint8_t *)scan.out);
+       jtag_add_dr_scan(x86_32->curr_tap, 1, fields, TAP_IDLE);
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s drscan failed to execute queue", __func__);
+               x86_32->curr_tap = saved_tap;
+               return retval;
+       }
+
+       /* restore current tap */
+       x86_32->curr_tap = saved_tap;
+
+       return ERROR_OK;
+}
+
+/*
+ * If we ever get an adapter with support for PREQ# and PRDY#, we should
+ * update this function to add support for using those two signals.
+ *
+ * Meanwhile, we're assuming that we only support reset break.
+ */
 int lakemont_reset_assert(struct target *t)
 {
-       LOG_DEBUG("-");
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       /* write 0x6 to I/O port 0xcf9 to cause the reset */
+       uint8_t cf9_reset_val = 0x6;
+       int retval;
+
+       LOG_DEBUG(" ");
+
+       if (t->state != TARGET_HALTED) {
+               LOG_DEBUG("target must be halted first");
+               retval = lakemont_halt(t);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("could not halt target");
+                       return retval;
+               }
+               x86_32->forced_halt_for_reset = true;
+       }
+
+       if (t->reset_halt) {
+               retval = lakemont_reset_break(t);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = x86_32_common_write_io(t, 0xcf9, BYTE, &cf9_reset_val);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("could not write to port 0xcf9");
+               return retval;
+       }
+
+       if (!t->reset_halt && x86_32->forced_halt_for_reset) {
+               x86_32->forced_halt_for_reset = false;
+               retval = lakemont_resume(t, true, 0x00, false, true);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       /* remove breakpoints and watchpoints */
+       x86_32_common_reset_breakpoints_watchpoints(t);
+
        return ERROR_OK;
 }
 
 int lakemont_reset_deassert(struct target *t)
 {
-       LOG_DEBUG("-");
+       int retval;
+
+       LOG_DEBUG(" ");
+
+       if (target_was_examined(t)) {
+               retval = lakemont_poll(t);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       if (t->reset_halt) {
+               /* entered PM after reset, update the state */
+               retval = lakemont_update_after_probemode_entry(t);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("could not update state after probemode entry");
+                       return retval;
+               }
+
+               if (t->state != TARGET_HALTED) {
+                       LOG_WARNING("%s: ran after reset and before halt ...",
+                               target_name(t));
+                       if (target_was_examined(t)) {
+                               retval = target_halt(t);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                       } else {
+                               t->state = TARGET_UNKNOWN;
+                       }
+               }
+       }
+
        return ERROR_OK;
 }
index 34f92ea..0d87ba5 100644 (file)
@@ -1260,6 +1260,38 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp)
        return ERROR_OK;
 }
 
+/* after reset breakpoints and watchpoints in memory are not valid anymore and
+ * debug registers are cleared.
+ * we can't afford to remove sw breakpoints using the default methods as the
+ * memory doesn't have the same layout yet and an access might crash the target,
+ * so we just clear the openocd breakpoints structures.
+ */
+void x86_32_common_reset_breakpoints_watchpoints(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
+       struct breakpoint *next_b;
+       struct watchpoint *next_w;
+
+       while (t->breakpoints) {
+               next_b = t->breakpoints->next;
+               free(t->breakpoints->orig_instr);
+               free(t->breakpoints);
+               t->breakpoints = next_b;
+       }
+
+       while (t->watchpoints) {
+               next_w = t->watchpoints->next;
+               free(t->watchpoints);
+               t->watchpoints = next_w;
+       }
+
+       for (int i = 0; i < x86_32->num_hw_bpoints; i++) {
+               debug_reg_list[i].used = 0;
+               debug_reg_list[i].bp_value = 0;
+       }
+}
+
 static int read_hw_reg_to_cache(struct target *t, int num)
 {
        uint32_t reg_value;
index 0aaa963..14e6e35 100644 (file)
@@ -217,6 +217,7 @@ struct x86_32_common {
        struct reg_cache *cache;
        struct jtag_tap *curr_tap;
        uint32_t stored_pc;
+       int forced_halt_for_reset;
        int flush;
 
        /* pm_regs are for probemode save/restore state */
@@ -326,5 +327,6 @@ int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp);
 int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp);
 int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp);
 int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp);
+void x86_32_common_reset_breakpoints_watchpoints(struct target *t);
 
 #endif /* OPENOCD_TARGET_X86_32_COMMON_H */