static int enter_probemode(struct target *t) { uint32_t tapstatus = 0; tapstatus = get_tapstatus(t); LOG_DEBUG("TS before PM enter = 0x%08" PRIx32, tapstatus); if (tapstatus & TS_PM_BIT) { LOG_DEBUG("core already in probemode"); return ERROR_OK; } scan.out[0] = PROBEMODE; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; scan.out[0] = 1; if (drscan(t, scan.out, scan.in, 1) != ERROR_OK) return ERROR_FAIL; /* HACK */ int cnt = 5; do { tapstatus = get_tapstatus(t); if (tapstatus & TS_PM_BIT) return ERROR_OK; LOG_DEBUG("%s Waiting for PM, TS = 0x%08" PRIx32, __func__, tapstatus); usleep(100000); cnt--; } while (cnt); return ERROR_FAIL; /* TODO: find a nicer way to wait until PM_BIT changes*/ }
static int enter_probemode(struct target *t) { uint32_t tapstatus = 0; tapstatus = get_tapstatus(t); LOG_DEBUG("TS before PM enter = 0x%08" PRIx32, tapstatus); if (tapstatus & TS_PM_BIT) { LOG_DEBUG("core already in probemode"); return ERROR_OK; } scan.out[0] = PROBEMODE; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; scan.out[0] = 1; if (drscan(t, scan.out, scan.in, 1) != ERROR_OK) return ERROR_FAIL; tapstatus = get_tapstatus(t); LOG_DEBUG("TS after PM enter = 0x%08" PRIx32, tapstatus); if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT))) return ERROR_OK; else { LOG_ERROR("%s PM enter error, tapstatus = 0x%08" PRIx32 , __func__, tapstatus); return ERROR_FAIL; } }
static bool sw_bpts_supported(struct target *t) { uint32_t tapstatus = get_tapstatus(t); if (tapstatus & TS_SBP_BIT) return true; else return false; }
static int transaction_status(struct target *t) { uint32_t tapstatus = get_tapstatus(t); if ((TS_EN_PM_BIT | TS_PRDY_BIT) & tapstatus) { LOG_ERROR("%s transaction error tapstatus = 0x%08" PRIx32 , __func__, tapstatus); return ERROR_FAIL; } else { return ERROR_OK; } }
static int exit_probemode(struct target *t) { uint32_t tapstatus = get_tapstatus(t); LOG_DEBUG("TS before PM exit = 0x%08" PRIx32, tapstatus); if (!(tapstatus & TS_PM_BIT)) { LOG_USER("core not in PM"); return ERROR_OK; } scan.out[0] = PROBEMODE; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; scan.out[0] = 0; if (drscan(t, scan.out, scan.in, 1) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; }
/* * PIR (Probe Mode Instruction Register), SUBMITPIR is an "IR only" TAP * command; there is no corresponding data register */ static int submit_pir(struct target *t, uint64_t op) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t tapstatus = 0; uint8_t op_buf[8]; buf_set_u64(op_buf, 0, 64, op); int flush = x86_32->flush; x86_32->flush = 0; scan.out[0] = WRPIR; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; if (drscan(t, op_buf, scan.out, PIR_SIZE) != ERROR_OK) return ERROR_FAIL; scan.out[0] = SUBMITPIR; x86_32->flush = flush; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; jtag_add_sleep(DELAY_SUBMITPIR); /* HACK */ if (x86_32->flush) { int cnt = 10; do { tapstatus = get_tapstatus(t); if (!(tapstatus & TS_PIR_BIT)) return ERROR_OK; LOG_DEBUG("%s Waiting for TS_PIR_BIT, TS = 0x%08" PRIx32, __func__, tapstatus); usleep(100); cnt--; } while (cnt); LOG_ERROR("%s TS_PIR_BIT did not clear, TS = 0x%08" PRIx32, __func__, tapstatus); return ERROR_FAIL; /* TODO: find a nicer way to wait until PM_BIT changes*/ } return ERROR_OK; }
static int transaction_status(struct target *t) { uint32_t tapstatus = 0; /* HACK */ int cnt = 5; do { tapstatus = get_tapstatus(t); if (!((TS_EN_PM_BIT | TS_PRDY_BIT) & tapstatus)) return ERROR_OK; LOG_DEBUG("%s Waiting for PRDY & PM, TS = 0x%08" PRIx32, __func__, tapstatus); usleep(100000); cnt--; } while (cnt); return ERROR_FAIL; /* TODO: find a nicer way to wait until PM_BIT & PRDY_BIT changes*/ }
int lakemont_poll(struct target *t) { /* LMT1 PMCR register currently allows code breakpoints, data breakpoints, * single stepping and shutdowns to be redirected to PM but does not allow * redirecting into PM as a result of SMM enter and SMM exit */ uint32_t ts = get_tapstatus(t); if (ts == 0xFFFFFFFF && t->state != TARGET_DEBUG_RUNNING) { /* something is wrong here */ LOG_ERROR("tapstatus invalid - scan_chain serialization or locked JTAG access issues"); /* TODO: Give a hint that unlocking is wrong or maybe a * 'jtag arp_init' helps */ t->state = TARGET_DEBUG_RUNNING; return ERROR_OK; } if ((!(ts & TS_PM_BIT))) { if (t->state == TARGET_HALTED) { LOG_USER("target running for unknown reason"); } else if (t->state == TARGET_DEBUG_RUNNING) { LOG_USER("Debug running tapstatus=0x%08" PRIx32, ts); } LOG_DEBUG("tapstatus=0x%08" PRIx32, ts); t->state = TARGET_RUNNING; } if (t->state == TARGET_RUNNING || t->state == TARGET_DEBUG_RUNNING) { if (ts & TS_PM_BIT) { LOG_USER("redirect to PM, tapstatus=0x%08" PRIx32, get_tapstatus(t)); t->state = TARGET_DEBUG_RUNNING; if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; t->debug_reason = DBG_REASON_UNDEFINED; struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); uint32_t dr6 = buf_get_u32(x86_32->cache->reg_list[DR6].value, 0, 32); uint32_t hwbreakpoint = (uint32_t)-1; if (dr6 & DR6_BRKDETECT_0) hwbreakpoint = 0; if (dr6 & DR6_BRKDETECT_1) hwbreakpoint = 1; if (dr6 & DR6_BRKDETECT_2) hwbreakpoint = 2; if (dr6 & DR6_BRKDETECT_3) hwbreakpoint = 3; if (hwbreakpoint != (uint32_t)-1) { uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32); uint32_t type = dr7 & (0x03 << (DR7_RW_SHIFT + hwbreakpoint*DR7_RW_LEN_SIZE)); if (type == DR7_BP_EXECUTE) { LOG_USER("hit hardware breakpoint (hwreg=%" PRIu32 ") at 0x%08" PRIx32, hwbreakpoint, eip); } else { uint32_t address = 0; switch (hwbreakpoint) { default: case 0: address = buf_get_u32(x86_32->cache->reg_list[DR0].value, 0, 32); break; case 1: address = buf_get_u32(x86_32->cache->reg_list[DR1].value, 0, 32); break; case 2: address = buf_get_u32(x86_32->cache->reg_list[DR2].value, 0, 32); break; case 3: address = buf_get_u32(x86_32->cache->reg_list[DR3].value, 0, 32); break; } LOG_USER("hit '%s' watchpoint for 0x%08" PRIx32 " (hwreg=%" PRIu32 ") at 0x%08" PRIx32, type == DR7_BP_WRITE ? "write" : "access", address, hwbreakpoint, eip); } t->debug_reason = DBG_REASON_BREAKPOINT; } else { /* Check if the target hit a software breakpoint. * ! Watch out: EIP is currently pointing after the breakpoint opcode */ struct breakpoint *bp = NULL; bp = breakpoint_find(t, eip-1); if (bp != NULL) { t->debug_reason = DBG_REASON_BREAKPOINT; if (bp->type == BKPT_SOFT) { /* The EIP is now pointing the the next byte after the * breakpoint instruction. This needs to be corrected. */ buf_set_u32(x86_32->cache->reg_list[EIP].value, 0, 32, eip-1); x86_32->cache->reg_list[EIP].dirty = 1; x86_32->cache->reg_list[EIP].valid = 1; LOG_USER("hit software breakpoint at 0x%08" PRIx32, eip-1); } else { /* it's not a hardware breakpoint (checked already in DR6 state) * and it's also not a software breakpoint ... */ LOG_USER("hit unknown breakpoint at 0x%08" PRIx32, eip); } } else { /* There is also the case that we hit an breakpoint instruction, * which was not set by us. This needs to be handled be the * application that introduced the breakpoint. */ LOG_USER("unknown break reason at 0x%08" PRIx32, eip); } } return target_call_event_callbacks(t, TARGET_EVENT_HALTED); } } return ERROR_OK; }
int lakemont_step(struct target *t, int current, uint32_t address, int handle_breakpoints) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32); uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); uint32_t pmcr = buf_get_u32(x86_32->cache->reg_list[PMCR].value, 0, 32); struct breakpoint *bp = NULL; int retval = ERROR_OK; uint32_t tapstatus = 0; if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; bp = breakpoint_find(t, eip); if (retval == ERROR_OK && bp != NULL/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. */ retval = x86_32_common_remove_breakpoint(t, bp); } /* Set EFLAGS[TF] and PMCR[IR], exit pm and wait for PRDY# */ LOG_DEBUG("modifying PMCR = 0x%08" PRIx32 " and EFLAGS = 0x%08" PRIx32, pmcr, eflags); eflags = eflags | (EFLAGS_TF | EFLAGS_RF); buf_set_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32, eflags); buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); LOG_DEBUG("EFLAGS [TF] [RF] bits set=0x%08" PRIx32 ", PMCR=0x%08" PRIx32 ", EIP=0x%08" PRIx32, eflags, pmcr, eip); tapstatus = get_tapstatus(t); t->debug_reason = DBG_REASON_SINGLESTEP; t->state = TARGET_DEBUG_RUNNING; if (restore_context(t) != ERROR_OK) return ERROR_FAIL; if (exit_probemode(t) != ERROR_OK) return ERROR_FAIL; target_call_event_callbacks(t, TARGET_EVENT_RESUMED); tapstatus = get_tapstatus(t); if (tapstatus & (TS_PM_BIT | TS_EN_PM_BIT | TS_PRDY_BIT | TS_PMCR_BIT)) { /* target has stopped */ if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; LOG_USER("step done from EIP 0x%08" PRIx32 " to 0x%08" PRIx32, eip, buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32)); target_call_event_callbacks(t, TARGET_EVENT_HALTED); } else { /* target didn't stop * I hope the poll() will catch it, but the deleted breakpoint is gone */ LOG_ERROR("%s target didn't stop after executing a single step", __func__); t->state = TARGET_RUNNING; return ERROR_FAIL; } /* try to re-apply the breakpoint, even of step failed * TODO: When a bp was set, we should try to stop the target - fix the return above */ if (bp != NULL/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. */ retval = x86_32_common_add_breakpoint(t, bp); } return retval; }