target/riscv: Early exit magic sequence checks in riscv_semihosting

When halted we don't need to read all 3 instructions before deciding the
sequence doesn't match.

Change-Id: I9f8345960ce27e859265af901a368166a70b9fde
Signed-off-by: Tim Newsome <tim@sifive.com>
This commit is contained in:
Tim Newsome 2023-06-15 10:34:51 -07:00
parent c6e0716ac9
commit ebfd43c84f
1 changed files with 20 additions and 22 deletions

View File

@ -71,33 +71,31 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
if (result != ERROR_OK)
return SEMIHOSTING_ERROR;
uint8_t tmp_buf[12];
/* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */
for (int i = 0; i < 3; i++) {
/* Instruction memories may not support arbitrary read size. Use any size that will work. */
*retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i);
if (*retval != ERROR_OK)
return SEMIHOSTING_ERROR;
}
/*
* The instructions that trigger a semihosting call,
* always uncompressed, should look like:
*
* 01f01013 slli zero,zero,0x1f
* 00100073 ebreak
* 40705013 srai zero,zero,0x7
*/
uint32_t pre = target_buffer_get_u32(target, tmp_buf);
uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4);
uint32_t post = target_buffer_get_u32(target, tmp_buf + 8);
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc);
uint32_t magic[] = {
0x01f01013, /* slli zero,zero,0x1f */
0x00100073, /* ebreak */
0x40705013 /* srai zero,zero,0x7 */
};
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
/* Not the magic sequence defining semihosting. */
LOG_DEBUG(" -> NONE (no magic)");
return SEMIHOSTING_NONE;
/* 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_DEBUG(" -> NONE (no magic)");
return SEMIHOSTING_NONE;
}
}
/*