Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RISC-V Semihosting 2 of 3: Refactor magic sequence detection #1199

Open
wants to merge 3 commits into
base: riscv
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 60 additions & 34 deletions src/target/riscv/riscv_semihosting.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,52 @@
static int riscv_semihosting_setup(struct target *target, int enable);
static int riscv_semihosting_post_result(struct target *target);

static int riscv_semihosting_detect_magic_sequence(struct target *target,
const target_addr_t pc, bool *sequence_found)
{
assert(sequence_found);

const uint32_t magic[] = {
0x01f01013, /* slli zero,zero,0x1f */
0x00100073, /* ebreak */
0x40705013 /* srai zero,zero,0x7 */
};

LOG_TARGET_DEBUG(target, "Checking for RISC-V semihosting sequence "
"at PC = 0x%" TARGET_PRIxADDR, pc);

/* Read three uncompressed instructions:
* The previous, the current one (pointed to by PC) and the next one. */
const target_addr_t sequence_start_address = pc - 4;
for (int i = 0; i < 3; i++) {
uint8_t buf[4];

/* Instruction memories may not support arbitrary read size.
* Use any size that will work. */
const target_addr_t address = sequence_start_address + (4 * i);
int result = riscv_read_by_any_size(target, address, 4, buf);
if (result != ERROR_OK) {
*sequence_found = false;
return result;
}

const uint32_t value = target_buffer_get_u32(target, buf);

LOG_TARGET_DEBUG(target, "compare 0x%08" PRIx32 " from 0x%" PRIx64 " against 0x%08" PRIx32,
value, address, magic[i]);
if (value != magic[i]) {
LOG_TARGET_DEBUG(target, "Not a RISC-V semihosting sequence");
*sequence_found = false;
return ERROR_OK;
}
}

LOG_TARGET_DEBUG(target, "RISC-V semihosting sequence found "
"at PC = 0x%" TARGET_PRIxADDR, pc);
*sequence_found = true;
return ERROR_OK;
}

/**
* Initialize RISC-V semihosting. Use common ARM code.
*/
Expand All @@ -57,10 +103,7 @@ void riscv_semihosting_init(struct target *target)
enum semihosting_result riscv_semihosting(struct target *target, int *retval)
{
struct semihosting *semihosting = target->semihosting;
if (!semihosting) {
LOG_TARGET_DEBUG(target, " -> NONE (!semihosting)");
return SEMIHOSTING_NONE;
}
assert(semihosting);

if (!semihosting->is_active) {
LOG_TARGET_DEBUG(target, " -> NONE (!semihosting->is_active)");
Expand All @@ -72,33 +115,19 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
if (result != ERROR_OK)
return SEMIHOSTING_ERROR;

/*
* The instructions that trigger a semihosting call,
* always uncompressed, should look like:
*/
uint32_t magic[] = {
0x01f01013, /* slli zero,zero,0x1f */
0x00100073, /* ebreak */
0x40705013 /* srai zero,zero,0x7 */
};
bool sequence_found;
*retval = riscv_semihosting_detect_magic_sequence(target, pc, &sequence_found);
if (*retval != ERROR_OK)
return SEMIHOSTING_ERROR;

/* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */
for (int i = 0; i < 3; i++) {
uint8_t buf[4];
/* Instruction memories may not support arbitrary read size. Use any size that will work. */
target_addr_t address = (pc - 4) + 4 * i;
*retval = riscv_read_by_any_size(target, address, 4, buf);
if (*retval != ERROR_OK)
return SEMIHOSTING_ERROR;
uint32_t value = target_buffer_get_u32(target, buf);
LOG_TARGET_DEBUG(target, "compare 0x%08x from 0x%" PRIx64 " against 0x%08x",
value, address, magic[i]);
if (value != magic[i]) {
LOG_TARGET_DEBUG(target, " -> NONE (no magic)");
return SEMIHOSTING_NONE;
}
if (!sequence_found) {
LOG_TARGET_DEBUG(target, " -> NONE (no magic)");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe move this printout inside riscv_semihosting_detect_magic_sequence?

		if (result != ERROR_OK) {
			*sequence_found = false;
			return result;
		}

Having context-dependent printout like this is somewhat confusing.

return SEMIHOSTING_NONE;
}

/* Otherwise we have a semihosting call (and semihosting is enabled).
* Proceed with the semihosting. */

/*
* Perform semihosting call if we are not waiting on a fileio
* operation to complete.
Expand Down Expand Up @@ -170,19 +199,16 @@ static int riscv_semihosting_setup(struct target *target, int enable)
LOG_TARGET_DEBUG(target, "enable=%d", enable);

struct semihosting *semihosting = target->semihosting;
if (semihosting)
semihosting->setup_time = clock();
assert(semihosting);

semihosting->setup_time = clock();
return ERROR_OK;
}

static int riscv_semihosting_post_result(struct target *target)
{
struct semihosting *semihosting = target->semihosting;
if (!semihosting) {
/* If not enabled, silently ignored. */
return 0;
}
assert(semihosting);

LOG_TARGET_DEBUG(target, "Result: 0x%" PRIx64, semihosting->result);
riscv_reg_set(target, GDB_REGNO_A0, semihosting->result);
Expand Down
Loading