Пример #1
0
static int avr32_ap7k_poll(struct target *target)
{
	uint32_t ds;
	int retval;
	struct avr32_ap7k_common *ap7k = target_to_ap7k(target);

	retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds);
	if (retval != ERROR_OK)
		return retval;

	/* check for processor halted */
	if (ds & OCDREG_DS_DBA) {
		if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) {
			target->state = TARGET_HALTED;

			retval = avr32_ap7k_debug_entry(target);
			if (retval != ERROR_OK)
				return retval;

			target_call_event_callbacks(target, TARGET_EVENT_HALTED);
		} else if (target->state == TARGET_DEBUG_RUNNING) {
			target->state = TARGET_HALTED;

			retval = avr32_ap7k_debug_entry(target);
			if (retval != ERROR_OK)
				return retval;

			target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
		}
	} else
		target->state = TARGET_RUNNING;


	return ERROR_OK;
}
Пример #2
0
int arc_ocd_poll(struct target *target)
{
	uint32_t status;
	struct arc32_common *arc32 = target_to_arc32(target);

	/* gdb calls continuously through this arc_poll() function  */
	CHECK_RETVAL(arc_jtag_status(&arc32->jtag_info, &status));

	/* check for processor halted */
	if (status & ARC_JTAG_STAT_RU) {
		target->state = TARGET_RUNNING;
	} else {
		if ((target->state == TARGET_RUNNING) ||
			(target->state == TARGET_RESET)) {

			target->state = TARGET_HALTED;
			LOG_DEBUG("ARC core is halted or in reset.");

			CHECK_RETVAL(arc_dbg_debug_entry(target));

			target_call_event_callbacks(target, TARGET_EVENT_HALTED);
		} else if (target->state == TARGET_DEBUG_RUNNING) {

			target->state = TARGET_HALTED;
			LOG_DEBUG("ARC core is in debug running mode");

			CHECK_RETVAL(arc_dbg_debug_entry(target));

			target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
		}
	}

	return ERROR_OK;
}
Пример #3
0
/* poll current target status */
static int arm11_poll(struct target *target)
{
	int retval;
	struct arm11_common *arm11 = target_to_arm11(target);

	CHECK_RETVAL(arm11_check_init(arm11));

	if (arm11->dscr & DSCR_CORE_HALTED) {
		if (target->state != TARGET_HALTED) {
			enum target_state old_state = target->state;

			LOG_DEBUG("enter TARGET_HALTED");
			retval = arm11_debug_entry(arm11);
			if (retval != ERROR_OK)
				return retval;

			target_call_event_callbacks(target,
				(old_state == TARGET_DEBUG_RUNNING)
				? TARGET_EVENT_DEBUG_HALTED
				: TARGET_EVENT_HALTED);
		}
	} else {
		if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) {
			LOG_DEBUG("enter TARGET_RUNNING");
			target->state                   = TARGET_RUNNING;
			target->debug_reason    = DBG_REASON_NOTHALTED;
		}
	}

	return ERROR_OK;
}
Пример #4
0
int arm926ejs_soft_reset_halt(struct target *target)
{
	int retval = ERROR_OK;
	struct arm926ejs_common *arm926ejs = target_to_arm926(target);
	struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
	struct arm *arm = &arm7_9->arm;
	struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];

	retval = target_halt(target);
	if (retval != ERROR_OK)
		return retval;

	int64_t then = timeval_ms();
	int timeout;
	while (!(timeout = ((timeval_ms()-then) > 1000))) {
		if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) {
			embeddedice_read_reg(dbg_stat);
			retval = jtag_execute_queue();
			if (retval != ERROR_OK)
				return retval;
		} else
			break;
		if (debug_level >= 1) {
			/* do not eat all CPU, time out after 1 se*/
			alive_sleep(100);
		} else
			keep_alive();
	}
	if (timeout) {
		LOG_ERROR("Failed to halt CPU after 1 sec");
		return ERROR_TARGET_TIMEOUT;
	}

	target->state = TARGET_HALTED;

	/* SVC, ARM state, IRQ and FIQ disabled */
	uint32_t cpsr;

	cpsr = buf_get_u32(arm->cpsr->value, 0, 32);
	cpsr &= ~0xff;
	cpsr |= 0xd3;
	arm_set_cpsr(arm, cpsr);
	arm->cpsr->dirty = 1;

	/* start fetching from 0x0 */
	buf_set_u32(arm->pc->value, 0, 32, 0x0);
	arm->pc->dirty = 1;
	arm->pc->valid = 1;

	retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1);
	if (retval != ERROR_OK)
		return retval;
	arm926ejs->armv4_5_mmu.mmu_enabled = 0;
	arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
	arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;

	return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
Пример #5
0
/* target execution control */
static int arm11_halt(struct target *target)
{
	struct arm11_common *arm11 = target_to_arm11(target);

	LOG_DEBUG("target->state: %s",
		target_state_name(target));

	if (target->state == TARGET_UNKNOWN)
	{
		arm11->simulate_reset_on_next_halt = true;
	}

	if (target->state == TARGET_HALTED)
	{
		LOG_DEBUG("target was already halted");
		return ERROR_OK;
	}

	arm11_add_IR(arm11, ARM11_HALT, TAP_IDLE);

	CHECK_RETVAL(jtag_execute_queue());

	int i = 0;

	while (1)
	{
		CHECK_RETVAL(arm11_read_DSCR(arm11));

		if (arm11->dscr & DSCR_CORE_HALTED)
			break;


		long long then = 0;
		if (i == 1000)
		{
			then = timeval_ms();
		}
		if (i >= 1000)
		{
			if ((timeval_ms()-then) > 1000)
			{
				LOG_WARNING("Timeout (1000ms) waiting for instructions to complete");
				return ERROR_FAIL;
			}
		}
		i++;
	}

	enum target_state old_state	= target->state;

	CHECK_RETVAL(arm11_debug_entry(arm11));

	CHECK_RETVAL(
		target_call_event_callbacks(target,
			old_state == TARGET_DEBUG_RUNNING ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED));

	return ERROR_OK;
}
Пример #6
0
/* we need to expose the update to be able to complete the reset at SoC level */
int lakemont_update_after_probemode_entry(struct target *t)
{
	if (save_context(t) != ERROR_OK)
		return ERROR_FAIL;
	if (halt_prep(t) != ERROR_OK)
		return ERROR_FAIL;
	t->state = TARGET_HALTED;

	return target_call_event_callbacks(t, TARGET_EVENT_HALTED);
}
Пример #7
0
static int do_resume(struct target *t)
{
	/* needs proper handling later */
	t->state = TARGET_DEBUG_RUNNING;
	if (restore_context(t) != ERROR_OK)
		return ERROR_FAIL;
	if (exit_probemode(t) != ERROR_OK)
		return ERROR_FAIL;
	t->state = TARGET_RUNNING;

	t->debug_reason = DBG_REASON_NOTHALTED;
	LOG_USER("target running");

	return target_call_event_callbacks(t, TARGET_EVENT_RESUMED);
}
Пример #8
0
static int xtensa_resume(struct target *target,
			 int current,
			 uint32_t address,
			 int handle_breakpoints,
			 int debug_execution)
{
	struct xtensa_common *xtensa = target_to_xtensa(target);
	uint8_t buf[4];
	int res;

	LOG_DEBUG("%s current=%d address=%04" PRIx32, __func__, current, address);

	if (target->state != TARGET_HALTED) {
		LOG_WARNING("%s: target not halted", __func__);
		return ERROR_TARGET_NOT_HALTED;
	}

	if(address && !current) {
		buf_set_u32(buf, 0, 32, address);
		xtensa_set_core_reg(&xtensa->core_cache->reg_list[XT_REG_IDX_PC], buf);
	}
	xtensa_restore_context(target);
	register_cache_invalidate(xtensa->core_cache);
	
	res = xtensa_tap_queue_cpu_inst(target, XT_INS_ISYNC);
	if (res != ERROR_OK)
		return res;
	
	res = jtag_execute_queue();
	if (res != ERROR_OK)
		return res;

	res = xtensa_tap_exec(target, TAP_INS_LOAD_DI, XT_INS_RFDO_1, 0);
	if(res != ERROR_OK) {
		LOG_ERROR("Failed to issue LoadDI instruction. Can't resume.");
		return ERROR_FAIL;
	}

	target->debug_reason = DBG_REASON_NOTHALTED;
	if (!debug_execution)
		target->state = TARGET_RUNNING;
	else
		target->state = TARGET_DEBUG_RUNNING;
	res = target_call_event_callbacks(target, TARGET_EVENT_RESUMED);

	return res;
}
Пример #9
0
static int or1k_resume_or_step(struct target *target, int current,
			       uint32_t address, int handle_breakpoints,
			       int debug_execution, int step)
{
	struct or1k_common *or1k = target_to_or1k(target);
	struct or1k_du *du_core = or1k_to_du(or1k);
	struct breakpoint *breakpoint = NULL;
	uint32_t resume_pc;
	uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM];

	LOG_DEBUG("Addr: 0x%" PRIx32 ", stepping: %s, handle breakpoints %s\n",
		  address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no");

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (!debug_execution)
		target_free_all_working_areas(target);

	/* current ? continue on current pc : continue at <address> */
	if (!current)
		buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0,
			    32, address);

	int retval = or1k_restore_context(target);
	if (retval != ERROR_OK) {
		LOG_ERROR("Error while calling or1k_restore_context");
		return retval;
	}

	/* read debug registers (starting from DMR1 register) */
	retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD,
					     OR1K_DEBUG_REG_NUM, debug_reg_list);
	if (retval != ERROR_OK) {
		LOG_ERROR("Error while reading debug registers");
		return retval;
	}

	/* Clear Debug Reason Register (DRR) */
	debug_reg_list[OR1K_DEBUG_REG_DRR] = 0;

	/* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */
	debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB;
	if (step)
		/* Set the single step trigger in Debug Mode Register 1 (DMR1) */
		debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT;
	else
		/* Clear the single step trigger in Debug Mode Register 1 (DMR1) */
		debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT);

	/* Set traps to be handled by the debug unit in the Debug Stop
	   Register (DSR). Check if we have any software breakpoints in
	   place before setting this value - the kernel, for instance,
	   relies on l.trap instructions not stalling the processor ! */
	if (is_any_soft_breakpoint(target) == true)
		debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE;

	/* Write debug registers (starting from DMR1 register) */
	retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD,
					      OR1K_DEBUG_REG_NUM, debug_reg_list);
	if (retval != ERROR_OK) {
		LOG_ERROR("Error while writing back debug registers");
		return retval;
	}

	resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value,
				0, 32);

	/* The front-end may request us not to handle breakpoints */
	if (handle_breakpoints) {
		/* Single step past breakpoint at current address */
		breakpoint = breakpoint_find(target, resume_pc);
		if (breakpoint) {
			LOG_DEBUG("Unset breakpoint at 0x%08" PRIx32, breakpoint->address);
			retval = or1k_remove_breakpoint(target, breakpoint);
			if (retval != ERROR_OK)
				return retval;
		}
	}

	/* Unstall time */
	retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_UNSTALL);
	if (retval != ERROR_OK) {
		LOG_ERROR("Error while unstalling the CPU");
		return retval;
	}

	if (step)
		target->debug_reason = DBG_REASON_SINGLESTEP;
	else
		target->debug_reason = DBG_REASON_NOTHALTED;

	/* Registers are now invalid */
	register_cache_invalidate(or1k->core_cache);

	if (!debug_execution) {
		target->state = TARGET_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
		LOG_DEBUG("Target resumed at 0x%08" PRIx32, resume_pc);
	} else {
		target->state = TARGET_DEBUG_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
		LOG_DEBUG("Target debug resumed at 0x%08" PRIx32, resume_pc);
	}

	return ERROR_OK;
}
Пример #10
0
static int or1k_poll(struct target *target)
{
	int retval;
	int running;

	retval = or1k_is_cpu_running(target, &running);
	if (retval != ERROR_OK) {
		LOG_ERROR("Error while calling or1k_is_cpu_running");
		return retval;
	}

	/* check for processor halted */
	if (!running) {
		/* It's actually stalled, so update our software's state */
		if ((target->state == TARGET_RUNNING) ||
		    (target->state == TARGET_RESET)) {

			target->state = TARGET_HALTED;

			retval = or1k_debug_entry(target);
			if (retval != ERROR_OK) {
				LOG_ERROR("Error while calling or1k_debug_entry");
				return retval;
			}

			target_call_event_callbacks(target,
						    TARGET_EVENT_HALTED);
		} else if (target->state == TARGET_DEBUG_RUNNING) {
			target->state = TARGET_HALTED;

			retval = or1k_debug_entry(target);
			if (retval != ERROR_OK) {
				LOG_ERROR("Error while calling or1k_debug_entry");
				return retval;
			}

			target_call_event_callbacks(target,
						    TARGET_EVENT_DEBUG_HALTED);
		}
	} else { /* ... target is running */

		/* If target was supposed to be stalled, stall it again */
		if  (target->state == TARGET_HALTED) {

			target->state = TARGET_RUNNING;

			retval = or1k_halt(target);
			if (retval != ERROR_OK) {
				LOG_ERROR("Error while calling or1k_halt");
				return retval;
			}

			retval = or1k_debug_entry(target);
			if (retval != ERROR_OK) {
				LOG_ERROR("Error while calling or1k_debug_entry");
				return retval;
			}

			target_call_event_callbacks(target,
						    TARGET_EVENT_DEBUG_HALTED);
		}

		target->state = TARGET_RUNNING;

	}

	return ERROR_OK;
}
Пример #11
0
static int xtensa_poll(struct target *target)
{
	struct xtensa_common *xtensa = target_to_xtensa(target);
	struct reg *reg;
	uint32_t dosr;
	int res;

	/* OCD guide 2.9.2 points out no reliable way to detect core reset.

	   So, even though this ENABLE_OCD is nearly always a No-Op, we send it
	   on every poll just in case the target has reset and gone back to Running state
	   (in which case this moves it to OCD Run State. */
	res = xtensa_tap_queue(target, TAP_INS_ENABLE_OCD, NULL, NULL);
	if(res != ERROR_OK) {
		LOG_ERROR("Failed to queue EnableOCD instruction.");
		return ERROR_FAIL;
	}

	res = xtensa_tap_exec(target, TAP_INS_READ_DOSR, 0, &dosr);
	if(res != ERROR_OK) {
		LOG_ERROR("Failed to read DOSR. Not Xtensa OCD?");
		return ERROR_FAIL;
	}

	if(dosr & (DOSR_IN_OCD_MODE)) {
		if (target->state != TARGET_HALTED)
		{
			if (target->state != TARGET_UNKNOWN && (dosr & DOSR_EXCEPTION) == 0)
			{
				LOG_WARNING("%s: DOSR has set InOCDMode without the Exception flag. Unexpected. DOSR=0x%02x",
					__func__,
					dosr);
			}
			int state = target->state;

			xtensa->state = XT_OCD_HALT;
			target->state = TARGET_HALTED;
			register_cache_invalidate(xtensa->core_cache);
			xtensa_save_context(target);

			if (state == TARGET_DEBUG_RUNNING)
			{
				target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
			}
			else
			{
				//target->debug_reason is checked in gdb_last_signal() that is invoked as a result of calling target_call_event_callbacks() below.
				//Unless we specify it, GDB will get confused and report the stop to the user on its internal breakpoints.
				uint32_t dbgcause = buf_get_u32(xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].value, 0, 32);
				if (dbgcause & 0x20)	//Debug interrupt
					target->debug_reason = DBG_REASON_DBGRQ;
				else if (dbgcause & 0x01) //ICOUNT match
					target->debug_reason = DBG_REASON_SINGLESTEP;
				else
					target->debug_reason = DBG_REASON_BREAKPOINT;
				
				target_call_event_callbacks(target, TARGET_EVENT_HALTED);
			}

			LOG_DEBUG("target->state: %s", target_state_name(target));
			reg = &xtensa->core_cache->reg_list[XT_REG_IDX_PC];
			LOG_INFO("halted: PC: 0x%" PRIx32, buf_get_u32(reg->value, 0, 32));
			reg = &xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE];
			LOG_INFO("debug cause: 0x%" PRIx32, buf_get_u32(reg->value, 0, 32));
		}
		else
		{
			if (s_FeedWatchdogDuringStops)
				xtensa_feed_esp8266_watchdog(target);
		}
	} else if(target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING){
		xtensa->state = XT_OCD_RUN;
		target->state = TARGET_RUNNING;
	}
	return ERROR_OK;
}
Пример #12
0
static int arm11_resume(struct target *target, int current,
		uint32_t address, int handle_breakpoints, int debug_execution)
{
	//	  LOG_DEBUG("current %d  address %08x  handle_breakpoints %d  debug_execution %d",
	//	current, address, handle_breakpoints, debug_execution);

	struct arm11_common *arm11 = target_to_arm11(target);

	LOG_DEBUG("target->state: %s",
		target_state_name(target));


	if (target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	address = arm11_nextpc(arm11, current, address);

	LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : "");

	/* clear breakpoints/watchpoints and VCR*/
	CHECK_RETVAL(arm11_sc7_clear_vbw(arm11));

	if (!debug_execution)
		target_free_all_working_areas(target);

	/* Should we skip over breakpoints matching the PC? */
	if (handle_breakpoints) {
		struct breakpoint *bp;

		for (bp = target->breakpoints; bp; bp = bp->next)
		{
			if (bp->address == address)
			{
				LOG_DEBUG("must step over %08" PRIx32 "", bp->address);
				arm11_step(target, 1, 0, 0);
				break;
			}
		}
	}

	/* activate all breakpoints */
	if (true) {
		struct breakpoint *bp;
		unsigned brp_num = 0;

		for (bp = target->breakpoints; bp; bp = bp->next)
		{
			struct arm11_sc7_action	brp[2];

			brp[0].write	= 1;
			brp[0].address	= ARM11_SC7_BVR0 + brp_num;
			brp[0].value	= bp->address;
			brp[1].write	= 1;
			brp[1].address	= ARM11_SC7_BCR0 + brp_num;
			brp[1].value	= 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21);

			CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp)));

			LOG_DEBUG("Add BP %d at %08" PRIx32, brp_num,
					bp->address);

			brp_num++;
		}

		if (arm11->vcr)
			CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr));
	}

	/* activate all watchpoints and breakpoints */
	CHECK_RETVAL(arm11_leave_debug_state(arm11, true));

	arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE);

	CHECK_RETVAL(jtag_execute_queue());

	int i = 0;
	while (1)
	{
		CHECK_RETVAL(arm11_read_DSCR(arm11));

		LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr);

		if (arm11->dscr & DSCR_CORE_RESTARTED)
			break;


		long long then = 0;
		if (i == 1000)
		{
			then = timeval_ms();
		}
		if (i >= 1000)
		{
			if ((timeval_ms()-then) > 1000)
			{
				LOG_WARNING("Timeout (1000ms) waiting for instructions to complete");
				return ERROR_FAIL;
			}
		}
		i++;
	}

	target->debug_reason = DBG_REASON_NOTHALTED;
	if (!debug_execution)
		target->state = TARGET_RUNNING;
	else
		target->state = TARGET_DEBUG_RUNNING;
	CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));

	return ERROR_OK;
}
Пример #13
0
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;
}
Пример #14
0
static int do_semihosting(struct target *target)
{
	struct arm *arm = target_to_arm(target);
	uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
	uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
	uint8_t params[16];
	int retval, result;

	/*
	 * TODO: lots of security issues are not considered yet, such as:
	 * - no validation on target provided file descriptors
	 * - no safety checks on opened/deleted/renamed file paths
	 * Beware the target app you use this support with.
	 *
	 * TODO: explore mapping requests to GDB's "File-I/O Remote
	 * Protocol Extension" ... when GDB is active.
	 */
	switch (r0) {
	case 0x01:	/* SYS_OPEN */
		retval = target_read_memory(target, r1, 4, 3, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			uint32_t m = target_buffer_get_u32(target, params+4);
			uint32_t l = target_buffer_get_u32(target, params+8);
			if (l <= 255 && m <= 11) {
				uint8_t fn[256];
				retval = target_read_memory(target, a, 1, l, fn);
				if (retval != ERROR_OK)
					return retval;
				fn[l] = 0;
				if (strcmp((char *)fn, ":tt") == 0) {
					if (m < 4)
						result = dup(STDIN_FILENO);
					else
						result = dup(STDOUT_FILENO);
				} else {
					/* cygwin requires the permission setting
					 * otherwise it will fail to reopen a previously
					 * written file */
					result = open((char *)fn, open_modeflags[m], 0644);
				}
				arm->semihosting_errno =  errno;
			} else {
				result = -1;
				arm->semihosting_errno = EINVAL;
			}
		}
		break;

	case 0x02:	/* SYS_CLOSE */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			result = close(fd);
			arm->semihosting_errno = errno;
		}
		break;

	case 0x03:	/* SYS_WRITEC */
		{
			unsigned char c;
			retval = target_read_memory(target, r1, 1, 1, &c);
			if (retval != ERROR_OK)
				return retval;
			putchar(c);
			result = 0;
		}
		break;

	case 0x04:	/* SYS_WRITE0 */
		do {
			unsigned char c;
			retval = target_read_memory(target, r1++, 1, 1, &c);
			if (retval != ERROR_OK)
				return retval;
			if (!c)
				break;
			putchar(c);
		} while (1);
		result = 0;
		break;

	case 0x05:	/* SYS_WRITE */
		retval = target_read_memory(target, r1, 4, 3, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			uint32_t a = target_buffer_get_u32(target, params+4);
			size_t l = target_buffer_get_u32(target, params+8);
			uint8_t *buf = malloc(l);
			if (!buf) {
				result = -1;
				arm->semihosting_errno = ENOMEM;
			} else {
				retval = target_read_buffer(target, a, l, buf);
				if (retval != ERROR_OK) {
					free(buf);
					return retval;
				}
				result = write(fd, buf, l);
				arm->semihosting_errno = errno;
				if (result >= 0)
					result = l - result;
				free(buf);
			}
		}
		break;

	case 0x06:	/* SYS_READ */
		retval = target_read_memory(target, r1, 4, 3, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			uint32_t a = target_buffer_get_u32(target, params+4);
			ssize_t l = target_buffer_get_u32(target, params+8);
			uint8_t *buf = malloc(l);
			if (!buf) {
				result = -1;
				arm->semihosting_errno = ENOMEM;
			} else {
				result = read(fd, buf, l);
				arm->semihosting_errno = errno;
				if (result >= 0) {
					retval = target_write_buffer(target, a, result, buf);
					if (retval != ERROR_OK) {
						free(buf);
						return retval;
					}
					result = l - result;
				}
				free(buf);
			}
		}
		break;

	case 0x07:	/* SYS_READC */
		result = getchar();
		break;

	case 0x08:	/* SYS_ISERROR */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		result = (target_buffer_get_u32(target, params+0) != 0);
		break;

	case 0x09:	/* SYS_ISTTY */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		result = isatty(target_buffer_get_u32(target, params+0));
		break;

	case 0x0a:	/* SYS_SEEK */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			off_t pos = target_buffer_get_u32(target, params+4);
			result = lseek(fd, pos, SEEK_SET);
			arm->semihosting_errno = errno;
			if (result == pos)
				result = 0;
		}
		break;

	case 0x0c:	/* SYS_FLEN */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			struct stat buf;
			result = fstat(fd, &buf);
			if (result == -1) {
				arm->semihosting_errno = errno;
				result = -1;
				break;
			}
			result = buf.st_size;
		}
		break;

	case 0x0e:	/* SYS_REMOVE */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			uint32_t l = target_buffer_get_u32(target, params+4);
			if (l <= 255) {
				uint8_t fn[256];
				retval = target_read_memory(target, a, 1, l, fn);
				if (retval != ERROR_OK)
					return retval;
				fn[l] = 0;
				result = remove((char *)fn);
				arm->semihosting_errno =  errno;
			} else {
				result = -1;
				arm->semihosting_errno = EINVAL;
			}
		}
		break;

	case 0x0f:	/* SYS_RENAME */
		retval = target_read_memory(target, r1, 4, 4, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a1 = target_buffer_get_u32(target, params+0);
			uint32_t l1 = target_buffer_get_u32(target, params+4);
			uint32_t a2 = target_buffer_get_u32(target, params+8);
			uint32_t l2 = target_buffer_get_u32(target, params+12);
			if (l1 <= 255 && l2 <= 255) {
				uint8_t fn1[256], fn2[256];
				retval = target_read_memory(target, a1, 1, l1, fn1);
				if (retval != ERROR_OK)
					return retval;
				retval = target_read_memory(target, a2, 1, l2, fn2);
				if (retval != ERROR_OK)
					return retval;
				fn1[l1] = 0;
				fn2[l2] = 0;
				result = rename((char *)fn1, (char *)fn2);
				arm->semihosting_errno =  errno;
			} else {
				result = -1;
				arm->semihosting_errno = EINVAL;
			}
		}
		break;

	case 0x11:	/* SYS_TIME */
		result = time(NULL);
		break;

	case 0x13:	/* SYS_ERRNO */
		result = arm->semihosting_errno;
		break;

	case 0x15:	/* SYS_GET_CMDLINE */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			uint32_t l = target_buffer_get_u32(target, params+4);
			char *arg = "foobar";
			uint32_t s = strlen(arg) + 1;
			if (l < s)
				result = -1;
			else {
				retval = target_write_buffer(target, a, s, (uint8_t *)arg);
				if (retval != ERROR_OK)
					return retval;
				result = 0;
			}
		}
		break;

	case 0x16:	/* SYS_HEAPINFO */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			/* tell the remote we have no idea */
			memset(params, 0, 4*4);
			retval = target_write_memory(target, a, 4, 4, params);
			if (retval != ERROR_OK)
				return retval;
			result = 0;
		}
		break;

	case 0x18:	/* angel_SWIreason_ReportException */
		switch (r1) {
		case 0x20026:	/* ADP_Stopped_ApplicationExit */
			fprintf(stderr, "semihosting: *** application exited ***\n");
			break;
		case 0x20000:	/* ADP_Stopped_BranchThroughZero */
		case 0x20001:	/* ADP_Stopped_UndefinedInstr */
		case 0x20002:	/* ADP_Stopped_SoftwareInterrupt */
		case 0x20003:	/* ADP_Stopped_PrefetchAbort */
		case 0x20004:	/* ADP_Stopped_DataAbort */
		case 0x20005:	/* ADP_Stopped_AddressException */
		case 0x20006:	/* ADP_Stopped_IRQ */
		case 0x20007:	/* ADP_Stopped_FIQ */
		case 0x20020:	/* ADP_Stopped_BreakPoint */
		case 0x20021:	/* ADP_Stopped_WatchPoint */
		case 0x20022:	/* ADP_Stopped_StepComplete */
		case 0x20023:	/* ADP_Stopped_RunTimeErrorUnknown */
		case 0x20024:	/* ADP_Stopped_InternalError */
		case 0x20025:	/* ADP_Stopped_UserInterruption */
		case 0x20027:	/* ADP_Stopped_StackOverflow */
		case 0x20028:	/* ADP_Stopped_DivisionByZero */
		case 0x20029:	/* ADP_Stopped_OSSpecific */
		default:
			fprintf(stderr, "semihosting: exception %#x\n",
					(unsigned) r1);
		}
		return target_call_event_callbacks(target, TARGET_EVENT_HALTED);

	case 0x12:	/* SYS_SYSTEM */
		/* Provide SYS_SYSTEM functionality.  Uses the
		 * libc system command, there may be a reason *NOT*
		 * to use this, but as I can't think of one, I
		 * implemented it this way.
		 */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t len = target_buffer_get_u32(target, params+4);
			uint32_t c_ptr = target_buffer_get_u32(target, params);
			uint8_t cmd[256];
			if (len > 255) {
				result = -1;
				arm->semihosting_errno = EINVAL;
			} else {
				memset(cmd, 0x0, 256);
				retval = target_read_memory(target, c_ptr, 1, len, cmd);
				if (retval != ERROR_OK)
					return retval;
				else
					result = system((const char *)cmd);
			}
		}
		break;
	case 0x0d:	/* SYS_TMPNAM */
	case 0x10:	/* SYS_CLOCK */
	case 0x17:	/* angel_SWIreason_EnterSVC */
	case 0x30:	/* SYS_ELAPSED */
	case 0x31:	/* SYS_TICKFREQ */
	default:
		fprintf(stderr, "semihosting: unsupported call %#x\n",
				(unsigned) r0);
		result = -1;
		arm->semihosting_errno = ENOTSUP;
	}

	/* resume execution to the original mode */

	/* REVISIT this looks wrong ... ARM11 and Cortex-A8
	 * should work this way at least sometimes.
	 */
	if (is_arm7_9(target_to_arm7_9(target))) {
		uint32_t spsr;

		/* return value in R0 */
		buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
		arm->core_cache->reg_list[0].dirty = 1;

		/* LR --> PC */
		buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32,
			buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32));
		arm->core_cache->reg_list[15].dirty = 1;

		/* saved PSR --> current PSR */
		spsr = buf_get_u32(arm->spsr->value, 0, 32);

		/* REVISIT should this be arm_set_cpsr(arm, spsr)
		 * instead of a partially unrolled version?
		 */

		buf_set_u32(arm->cpsr->value, 0, 32, spsr);
		arm->cpsr->dirty = 1;
		arm->core_mode = spsr & 0x1f;
		if (spsr & 0x20)
			arm->core_state = ARM_STATE_THUMB;

	} else {
		/* resume execution, this will be pc+2 to skip over the
		 * bkpt instruction */

		/* return result in R0 */
		buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
		arm->core_cache->reg_list[0].dirty = 1;
	}

	return target_resume(target, 1, 0, 0, 0);
}
Пример #15
0
static int do_semihosting(struct target *target)
{
	struct arm *arm = target_to_arm(target);
	struct gdb_fileio_info *fileio_info = target->fileio_info;
	uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
	uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
	uint8_t params[16];
	int retval;

	/*
	 * TODO: lots of security issues are not considered yet, such as:
	 * - no validation on target provided file descriptors
	 * - no safety checks on opened/deleted/renamed file paths
	 * Beware the target app you use this support with.
	 *
	 * TODO: unsupported semihosting fileio operations could be
	 * implemented if we had a small working area at our disposal.
	 */
	switch ((arm->semihosting_op = r0)) {
	case 0x01:	/* SYS_OPEN */
		retval = target_read_memory(target, r1, 4, 3, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			uint32_t m = target_buffer_get_u32(target, params+4);
			uint32_t l = target_buffer_get_u32(target, params+8);
			uint8_t fn[256];
			retval = target_read_memory(target, a, 1, l, fn);
			if (retval != ERROR_OK)
				return retval;
			fn[l] = 0;
			if (arm->is_semihosting_fileio) {
				if (strcmp((char *)fn, ":tt") == 0)
					arm->semihosting_result = 0;
				else {
					arm->semihosting_hit_fileio = true;
					fileio_info->identifier = "open";
					fileio_info->param_1 = a;
					fileio_info->param_2 = l;
					fileio_info->param_3 = open_modeflags[m];
					fileio_info->param_4 = 0644;
				}
			} else {
				if (l <= 255 && m <= 11) {
					if (strcmp((char *)fn, ":tt") == 0) {
						if (m < 4)
							arm->semihosting_result = dup(STDIN_FILENO);
						else
							arm->semihosting_result = dup(STDOUT_FILENO);
					} else {
						/* cygwin requires the permission setting
						 * otherwise it will fail to reopen a previously
						 * written file */
						arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644);
					}
					arm->semihosting_errno =  errno;
				} else {
					arm->semihosting_result = -1;
					arm->semihosting_errno = EINVAL;
				}
			}
		}
		break;

	case 0x02:	/* SYS_CLOSE */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "close";
				fileio_info->param_1 = fd;
			} else {
				arm->semihosting_result = close(fd);
				arm->semihosting_errno = errno;
			}
		}
		break;

	case 0x03:	/* SYS_WRITEC */
		if (arm->is_semihosting_fileio) {
			arm->semihosting_hit_fileio = true;
			fileio_info->identifier = "write";
			fileio_info->param_1 = 1;
			fileio_info->param_2 = r1;
			fileio_info->param_3 = 1;
		} else {
			unsigned char c;
			retval = target_read_memory(target, r1, 1, 1, &c);
			if (retval != ERROR_OK)
				return retval;
			putchar(c);
			arm->semihosting_result = 0;
		}
		break;

	case 0x04:	/* SYS_WRITE0 */
		if (arm->is_semihosting_fileio) {
			size_t count = 0;
			for (uint32_t a = r1;; a++) {
				unsigned char c;
				retval = target_read_memory(target, a, 1, 1, &c);
				if (retval != ERROR_OK)
					return retval;
				if (c == '\0')
					break;
				count++;
			}
			arm->semihosting_hit_fileio = true;
			fileio_info->identifier = "write";
			fileio_info->param_1 = 1;
			fileio_info->param_2 = r1;
			fileio_info->param_3 = count;
		} else {
			do {
				unsigned char c;
				retval = target_read_memory(target, r1++, 1, 1, &c);
				if (retval != ERROR_OK)
					return retval;
				if (!c)
					break;
				putchar(c);
			} while (1);
			arm->semihosting_result = 0;
		}
		break;

	case 0x05:	/* SYS_WRITE */
		retval = target_read_memory(target, r1, 4, 3, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			uint32_t a = target_buffer_get_u32(target, params+4);
			size_t l = target_buffer_get_u32(target, params+8);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "write";
				fileio_info->param_1 = fd;
				fileio_info->param_2 = a;
				fileio_info->param_3 = l;
			} else {
				uint8_t *buf = malloc(l);
				if (!buf) {
					arm->semihosting_result = -1;
					arm->semihosting_errno = ENOMEM;
				} else {
					retval = target_read_buffer(target, a, l, buf);
					if (retval != ERROR_OK) {
						free(buf);
						return retval;
					}
					arm->semihosting_result = write(fd, buf, l);
					arm->semihosting_errno = errno;
					if (arm->semihosting_result >= 0)
						arm->semihosting_result = l - arm->semihosting_result;
					free(buf);
				}
			}
		}
		break;

	case 0x06:	/* SYS_READ */
		retval = target_read_memory(target, r1, 4, 3, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			uint32_t a = target_buffer_get_u32(target, params+4);
			ssize_t l = target_buffer_get_u32(target, params+8);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "read";
				fileio_info->param_1 = fd;
				fileio_info->param_2 = a;
				fileio_info->param_3 = l;
			} else {
				uint8_t *buf = malloc(l);
				if (!buf) {
					arm->semihosting_result = -1;
					arm->semihosting_errno = ENOMEM;
				} else {
					arm->semihosting_result = read(fd, buf, l);
					arm->semihosting_errno = errno;
					if (arm->semihosting_result >= 0) {
						retval = target_write_buffer(target, a, arm->semihosting_result, buf);
						if (retval != ERROR_OK) {
							free(buf);
							return retval;
						}
						arm->semihosting_result = l - arm->semihosting_result;
					}
					free(buf);
				}
			}
		}
		break;

	case 0x07:	/* SYS_READC */
		if (arm->is_semihosting_fileio) {
			LOG_ERROR("SYS_READC not supported by semihosting fileio");
			return ERROR_FAIL;
		}
		arm->semihosting_result = getchar();
		break;

	case 0x08:	/* SYS_ISERROR */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0);
		break;

	case 0x09:	/* SYS_ISTTY */
		if (arm->is_semihosting_fileio) {
			arm->semihosting_hit_fileio = true;
			fileio_info->identifier = "isatty";
			fileio_info->param_1 = r1;
		} else {
			retval = target_read_memory(target, r1, 4, 1, params);
			if (retval != ERROR_OK)
				return retval;
			arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0));
		}
		break;

	case 0x0a:	/* SYS_SEEK */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			off_t pos = target_buffer_get_u32(target, params+4);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "lseek";
				fileio_info->param_1 = fd;
				fileio_info->param_2 = pos;
				fileio_info->param_3 = SEEK_SET;
			} else {
				arm->semihosting_result = lseek(fd, pos, SEEK_SET);
				arm->semihosting_errno = errno;
				if (arm->semihosting_result == pos)
					arm->semihosting_result = 0;
			}
		}
		break;

	case 0x0c:	/* SYS_FLEN */
		if (arm->is_semihosting_fileio) {
			LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
			return ERROR_FAIL;
		}
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			int fd = target_buffer_get_u32(target, params+0);
			struct stat buf;
			arm->semihosting_result = fstat(fd, &buf);
			if (arm->semihosting_result == -1) {
				arm->semihosting_errno = errno;
				arm->semihosting_result = -1;
				break;
			}
			arm->semihosting_result = buf.st_size;
		}
		break;

	case 0x0e:	/* SYS_REMOVE */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			uint32_t l = target_buffer_get_u32(target, params+4);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "unlink";
				fileio_info->param_1 = a;
				fileio_info->param_2 = l;
			} else {
				if (l <= 255) {
					uint8_t fn[256];
					retval = target_read_memory(target, a, 1, l, fn);
					if (retval != ERROR_OK)
						return retval;
					fn[l] = 0;
					arm->semihosting_result = remove((char *)fn);
					arm->semihosting_errno =  errno;
				} else {
					arm->semihosting_result = -1;
					arm->semihosting_errno = EINVAL;
				}
			}
		}
		break;

	case 0x0f:	/* SYS_RENAME */
		retval = target_read_memory(target, r1, 4, 4, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a1 = target_buffer_get_u32(target, params+0);
			uint32_t l1 = target_buffer_get_u32(target, params+4);
			uint32_t a2 = target_buffer_get_u32(target, params+8);
			uint32_t l2 = target_buffer_get_u32(target, params+12);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "rename";
				fileio_info->param_1 = a1;
				fileio_info->param_2 = l1;
				fileio_info->param_3 = a2;
				fileio_info->param_4 = l2;
			} else {
				if (l1 <= 255 && l2 <= 255) {
					uint8_t fn1[256], fn2[256];
					retval = target_read_memory(target, a1, 1, l1, fn1);
					if (retval != ERROR_OK)
						return retval;
					retval = target_read_memory(target, a2, 1, l2, fn2);
					if (retval != ERROR_OK)
						return retval;
					fn1[l1] = 0;
					fn2[l2] = 0;
					arm->semihosting_result = rename((char *)fn1, (char *)fn2);
					arm->semihosting_errno =  errno;
				} else {
					arm->semihosting_result = -1;
					arm->semihosting_errno = EINVAL;
				}
			}
		}
		break;

	case 0x11:	/* SYS_TIME */
		arm->semihosting_result = time(NULL);
		break;

	case 0x13:	/* SYS_ERRNO */
		arm->semihosting_result = arm->semihosting_errno;
		break;

	case 0x15:	/* SYS_GET_CMDLINE */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			uint32_t l = target_buffer_get_u32(target, params+4);
			char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : "";
			uint32_t s = strlen(arg) + 1;
			if (l < s)
				arm->semihosting_result = -1;
			else {
				retval = target_write_buffer(target, a, s, (uint8_t *)arg);
				if (retval != ERROR_OK)
					return retval;
				arm->semihosting_result = 0;
			}
		}
		break;

	case 0x16:	/* SYS_HEAPINFO */
		retval = target_read_memory(target, r1, 4, 1, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t a = target_buffer_get_u32(target, params+0);
			/* tell the remote we have no idea */
			memset(params, 0, 4*4);
			retval = target_write_memory(target, a, 4, 4, params);
			if (retval != ERROR_OK)
				return retval;
			arm->semihosting_result = 0;
		}
		break;

	case 0x18:	/* angel_SWIreason_ReportException */
		switch (r1) {
		case 0x20026:	/* ADP_Stopped_ApplicationExit */
			fprintf(stderr, "semihosting: *** application exited ***\n");
			break;
		case 0x20000:	/* ADP_Stopped_BranchThroughZero */
		case 0x20001:	/* ADP_Stopped_UndefinedInstr */
		case 0x20002:	/* ADP_Stopped_SoftwareInterrupt */
		case 0x20003:	/* ADP_Stopped_PrefetchAbort */
		case 0x20004:	/* ADP_Stopped_DataAbort */
		case 0x20005:	/* ADP_Stopped_AddressException */
		case 0x20006:	/* ADP_Stopped_IRQ */
		case 0x20007:	/* ADP_Stopped_FIQ */
		case 0x20020:	/* ADP_Stopped_BreakPoint */
		case 0x20021:	/* ADP_Stopped_WatchPoint */
		case 0x20022:	/* ADP_Stopped_StepComplete */
		case 0x20023:	/* ADP_Stopped_RunTimeErrorUnknown */
		case 0x20024:	/* ADP_Stopped_InternalError */
		case 0x20025:	/* ADP_Stopped_UserInterruption */
		case 0x20027:	/* ADP_Stopped_StackOverflow */
		case 0x20028:	/* ADP_Stopped_DivisionByZero */
		case 0x20029:	/* ADP_Stopped_OSSpecific */
		default:
			fprintf(stderr, "semihosting: exception %#x\n",
					(unsigned) r1);
		}
		return target_call_event_callbacks(target, TARGET_EVENT_HALTED);

	case 0x12:	/* SYS_SYSTEM */
		/* Provide SYS_SYSTEM functionality.  Uses the
		 * libc system command, there may be a reason *NOT*
		 * to use this, but as I can't think of one, I
		 * implemented it this way.
		 */
		retval = target_read_memory(target, r1, 4, 2, params);
		if (retval != ERROR_OK)
			return retval;
		else {
			uint32_t len = target_buffer_get_u32(target, params+4);
			uint32_t c_ptr = target_buffer_get_u32(target, params);
			if (arm->is_semihosting_fileio) {
				arm->semihosting_hit_fileio = true;
				fileio_info->identifier = "system";
				fileio_info->param_1 = c_ptr;
				fileio_info->param_2 = len;
			} else {
				uint8_t cmd[256];
				if (len > 255) {
					arm->semihosting_result = -1;
					arm->semihosting_errno = EINVAL;
				} else {
					memset(cmd, 0x0, 256);
					retval = target_read_memory(target, c_ptr, 1, len, cmd);
					if (retval != ERROR_OK)
						return retval;
					else
						arm->semihosting_result = system((const char *)cmd);
				}
			}
		}
		break;
	case 0x0d:	/* SYS_TMPNAM */
	case 0x10:	/* SYS_CLOCK */
	case 0x17:	/* angel_SWIreason_EnterSVC */
	case 0x30:	/* SYS_ELAPSED */
	case 0x31:	/* SYS_TICKFREQ */
	default:
		fprintf(stderr, "semihosting: unsupported call %#x\n",
				(unsigned) r0);
		arm->semihosting_result = -1;
		arm->semihosting_errno = ENOTSUP;
	}

	return ERROR_OK;
}
Пример #16
0
static int avr32_ap7k_resume(struct target *target, int current,
	uint32_t address, int handle_breakpoints, int debug_execution)
{
	struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
	struct breakpoint *breakpoint = NULL;
	uint32_t resume_pc;
	int retval;

	if (target->state != TARGET_HALTED) {
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (!debug_execution) {
		target_free_all_working_areas(target);
		/*
		avr32_ap7k_enable_breakpoints(target);
		avr32_ap7k_enable_watchpoints(target);
		*/
	}

	/* current = 1: continue on current pc, otherwise continue at <address> */
	if (!current) {
#if 0
		if (retval != ERROR_OK)
			return retval;
#endif
	}

	resume_pc = buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32);
	avr32_ap7k_restore_context(target);

	/* the front-end may request us not to handle breakpoints */
	if (handle_breakpoints) {
		/* Single step past breakpoint at current address */
		breakpoint = breakpoint_find(target, resume_pc);
		if (breakpoint) {
			LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
#if 0
			avr32_ap7k_unset_breakpoint(target, breakpoint);
			avr32_ap7k_single_step_core(target);
			avr32_ap7k_set_breakpoint(target, breakpoint);
#endif
		}
	}

#if 0
	/* enable interrupts if we are running */
	avr32_ap7k_enable_interrupts(target, !debug_execution);

	/* exit debug mode */
	mips_ejtag_exit_debug(ejtag_info);
#endif


	retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC,
			OCDREG_DC_DBR);
	if (retval != ERROR_OK)
		return retval;

	retval = avr32_jtag_exec(&ap7k->jtag, RETD);
	if (retval != ERROR_OK)
		return retval;

	target->debug_reason = DBG_REASON_NOTHALTED;

	/* registers are now invalid */
	register_cache_invalidate(ap7k->core_cache);

	if (!debug_execution) {
		target->state = TARGET_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
		LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
	} else {
		target->state = TARGET_DEBUG_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
		LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
	}

	return ERROR_OK;
}
Пример #17
0
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;
}
Пример #18
0
int armv7m_trace_tpiu_config(struct target *target)
{
	struct armv7m_common *armv7m = target_to_armv7m(target);
	struct armv7m_trace_config *trace_config = &armv7m->trace_config;
	int prescaler;
	int retval;

	target_unregister_timer_callback(armv7m_poll_trace, target);


	retval = adapter_config_trace(trace_config->config_type == INTERNAL,
				      trace_config->pin_protocol,
				      trace_config->port_size,
				      &trace_config->trace_freq);
	if (retval != ERROR_OK)
		return retval;

	if (!trace_config->trace_freq) {
		LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
		return ERROR_FAIL;
	}

	prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;

	if (trace_config->traceclkin_freq % trace_config->trace_freq) {
		prescaler++;
		int trace_freq = trace_config->traceclkin_freq / prescaler;
		LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead",
			  trace_config->trace_freq, trace_config->traceclkin_freq,
			  trace_freq);
		trace_config->trace_freq = trace_freq;
		retval = adapter_config_trace(trace_config->config_type == INTERNAL,
					      trace_config->pin_protocol,
					      trace_config->port_size,
					      &trace_config->trace_freq);
		if (retval != ERROR_OK)
			return retval;
	}

	retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
	if (retval != ERROR_OK)
		return retval;

	uint32_t ffcr;
	retval = target_read_u32(target, TPIU_FFCR, &ffcr);
	if (retval != ERROR_OK)
		return retval;
	if (trace_config->formatter)
		ffcr |= (1 << 1);
	else
		ffcr &= ~(1 << 1);
	retval = target_write_u32(target, TPIU_FFCR, ffcr);
	if (retval != ERROR_OK)
		return retval;

	if (trace_config->config_type == INTERNAL)
		target_register_timer_callback(armv7m_poll_trace, 1, 1, target);

	target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);

	return ERROR_OK;
}
Пример #19
0
static int arm11_step(struct target *target, int current,
		uint32_t address, int handle_breakpoints)
{
	LOG_DEBUG("target->state: %s",
		target_state_name(target));

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target was not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	struct arm11_common *arm11 = target_to_arm11(target);

	address = arm11_nextpc(arm11, current, address);

	LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : "");


	/** \todo TODO: Thumb not supported here */

	uint32_t	next_instruction;

	CHECK_RETVAL(arm11_read_memory_word(arm11, address, &next_instruction));

	/* skip over BKPT */
	if ((next_instruction & 0xFFF00070) == 0xe1200070)
	{
		address = arm11_nextpc(arm11, 0, address + 4);
		LOG_DEBUG("Skipping BKPT");
	}
	/* skip over Wait for interrupt / Standby */
	/* mcr	15, 0, r?, cr7, cr0, {4} */
	else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90)
	{
		address = arm11_nextpc(arm11, 0, address + 4);
		LOG_DEBUG("Skipping WFI");
	}
	/* ignore B to self */
	else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe)
	{
		LOG_DEBUG("Not stepping jump to self");
	}
	else
	{
		/** \todo TODO: check if break-/watchpoints make any sense at all in combination
		* with this. */

		/** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively
		* the VCR might be something worth looking into. */


		/* Set up breakpoint for stepping */

		struct arm11_sc7_action	brp[2];

		brp[0].write	= 1;
		brp[0].address	= ARM11_SC7_BVR0;
		brp[1].write	= 1;
		brp[1].address	= ARM11_SC7_BCR0;

		if (arm11->hardware_step)
		{
			/* Hardware single stepping ("instruction address
			 * mismatch") is used if enabled.  It's not quite
			 * exactly "run one instruction"; "branch to here"
			 * loops won't break, neither will some other cases,
			 * but it's probably the best default.
			 *
			 * Hardware single stepping isn't supported on v6
			 * debug modules.  ARM1176 and v7 can support it...
			 *
			 * FIXME Thumb stepping likely needs to use 0x03
			 * or 0xc0 byte masks, not 0x0f.
			 */
			 brp[0].value	= address;
			 brp[1].value	= 0x1 | (3 << 1) | (0x0F << 5)
					| (0 << 14) | (0 << 16) | (0 << 20)
					| (2 << 21);
		} else
		{
			/* Sets a breakpoint on the next PC, as calculated
			 * by instruction set simulation.
			 *
			 * REVISIT stepping Thumb on ARM1156 requires Thumb2
			 * support from the simulator.
			 */
			uint32_t next_pc;
			int retval;

			retval = arm_simulate_step(target, &next_pc);
			if (retval != ERROR_OK)
				return retval;

			brp[0].value	= next_pc;
			brp[1].value	= 0x1 | (3 << 1) | (0x0F << 5)
					| (0 << 14) | (0 << 16) | (0 << 20)
					| (0 << 21);
		}

		CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp)));

		/* resume */


		if (arm11->step_irq_enable)
			/* this disable should be redundant ... */
			arm11->dscr &= ~DSCR_INT_DIS;
		else
			arm11->dscr |= DSCR_INT_DIS;


		CHECK_RETVAL(arm11_leave_debug_state(arm11, handle_breakpoints));

		arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE);

		CHECK_RETVAL(jtag_execute_queue());

		/* wait for halt */
		int i = 0;

		while (1)
		{
			const uint32_t mask = DSCR_CORE_RESTARTED
					| DSCR_CORE_HALTED;

			CHECK_RETVAL(arm11_read_DSCR(arm11));
			LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr);

			if ((arm11->dscr & mask) == mask)
				break;

			long long then = 0;
			if (i == 1000)
			{
				then = timeval_ms();
			}
			if (i >= 1000)
			{
				if ((timeval_ms()-then) > 1000)
				{
					LOG_WARNING("Timeout (1000ms) waiting for instructions to complete");
					return ERROR_FAIL;
				}
			}
			i++;
		}

		/* clear breakpoint */
		CHECK_RETVAL(arm11_sc7_clear_vbw(arm11));

		/* save state */
		CHECK_RETVAL(arm11_debug_entry(arm11));

		/* restore default state */
		arm11->dscr &= ~DSCR_INT_DIS;

	}

	target->debug_reason = DBG_REASON_SINGLESTEP;

	CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));

	return ERROR_OK;
}
Пример #20
0
static int or1k_resume_or_step(struct target *target, int current,
			       uint32_t address, int handle_breakpoints, 
			       int debug_execution, int step)
{
	struct or1k_common *or1k = target_to_or1k(target);
	struct breakpoint *breakpoint = NULL;
	uint32_t resume_pc;
	int retval;

	LOG_DEBUG(" - ");
	LOG_DEBUG(" addr: 0x%x, stepping: %d, handle breakpoints %d\n",
		  address, step, handle_breakpoints);

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (!debug_execution)
	{
		target_free_all_working_areas(target);
	}

	/* current ? continue on current pc : continue at <address> */
	if (!current)
	{
		buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0,
			    32, address);
	}

	if (!step) {
		or1k_restore_context(target);
	}

	uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM];
	/* read debug registers (starting from DMR1 register) */
	or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list);
	/* Clear Debug Reason Register (DRR) */
	debug_reg_list[OR1K_DEBUG_REG_DRR] = 0;
	/* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */
	debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB;
	if (step)
		/* Set the single step trigger in Debug Mode Register 1 (DMR1) */
		debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT;
	else
		/* Clear the single step trigger in Debug Mode Register 1 (DMR1) */
		debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT);

	/* Set traps to be handled by the debug unit in the Debug Stop 
	   Register (DSR) */
	/* TODO - check if we have any software breakpoints in place before
	   setting this value - the kernel, for instance, relies on l.trap
	   instructions not stalling the processor! */
	debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE;
	/* write debug registers (starting from DMR1 register) */
	or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list);

	resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value,
				0, 32);
	/* the front-end may request us not to handle breakpoints */
	if (handle_breakpoints)
	{
		/* Single step past breakpoint at current address */
		if ((breakpoint = breakpoint_find(target, resume_pc)))
		{
			LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
#if 0
			/* Do appropriate things here to remove breakpoint. */
#endif
		}
	}
	/* Unstall time */

	/* Mohor debug if, clearing control register unstalls */
	retval = or1k_jtag_write_cpu_cr(&or1k->jtag, 0, 0);
	if (retval != ERROR_OK)
		return retval;

	if (step)
		target->debug_reason = DBG_REASON_SINGLESTEP;
	else
		target->debug_reason = DBG_REASON_NOTHALTED;

	/* registers are now invalid */
	register_cache_invalidate(or1k->core_cache);

	if (!debug_execution)
	{
		target->state = TARGET_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
		LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
	}
	else
	{
		target->state = TARGET_DEBUG_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
		LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
	}
	
	return ERROR_OK;
}