Skip to content

Commit 8c0a1cd

Browse files
committed
RISC-V Semihosting 2 of 3: Refactor magic sequence detection
Refactor (clean up) the code in riscv_semihosting.c by moving the magic sequence detection to its own function. Cleanup the debug prints denoting the semihosting outcome so that they are easier to understand when reading the OpenOCD's verbose (debug) log. Use le_to_h_u32() to convert memory buffer to instruction code because RISC-V instructions are always little endian. (target_buffer_get_u32() was incorrect for that reason.) Change-Id: I3a3ce991336ceeeff023d459d0e28558059554e0 Signed-off-by: Jan Matyas <[email protected]>
1 parent eb9ba21 commit 8c0a1cd

File tree

1 file changed

+73
-28
lines changed

1 file changed

+73
-28
lines changed

src/target/riscv/riscv_semihosting.c

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,57 @@
3737
static int riscv_semihosting_setup(struct target *target, int enable);
3838
static int riscv_semihosting_post_result(struct target *target);
3939

40+
static int riscv_semihosting_detect_magic_sequence(struct target *target,
41+
const target_addr_t pc, bool *sequence_found)
42+
{
43+
assert(sequence_found);
44+
45+
/* The semihosting "magic" sequence must be the exact three instructions
46+
* listed below. All these instructions, including the ebreak, must be
47+
* uncompressed (4 bytes long). */
48+
const uint32_t magic[] = {
49+
0x01f01013, /* slli zero,zero,0x1f */
50+
0x00100073, /* ebreak */
51+
0x40705013 /* srai zero,zero,0x7 */
52+
};
53+
54+
LOG_TARGET_DEBUG(target, "Checking for RISC-V semihosting sequence "
55+
"at PC = 0x%" TARGET_PRIxADDR, pc);
56+
57+
/* Read three uncompressed instructions:
58+
* The previous, the current one (pointed to by PC) and the next one. */
59+
const target_addr_t sequence_start_address = pc - 4;
60+
for (int i = 0; i < 3; i++) {
61+
uint8_t buf[4];
62+
63+
/* Instruction memories may not support arbitrary read size.
64+
* Use any size that will work. */
65+
const target_addr_t address = sequence_start_address + (4 * i);
66+
int result = riscv_read_by_any_size(target, address, 4, buf);
67+
if (result != ERROR_OK) {
68+
*sequence_found = false;
69+
return result;
70+
}
71+
72+
/* RISC-V instruction layout in memory is always little endian,
73+
* regardless of the endianness of the whole system. */
74+
const uint32_t value = le_to_h_u32(buf);
75+
76+
LOG_TARGET_DEBUG(target, "compare 0x%08" PRIx32 " from 0x%" PRIx64 " against 0x%08" PRIx32,
77+
value, address, magic[i]);
78+
if (value != magic[i]) {
79+
LOG_TARGET_DEBUG(target, "Not a RISC-V semihosting sequence");
80+
*sequence_found = false;
81+
return ERROR_OK;
82+
}
83+
}
84+
85+
LOG_TARGET_DEBUG(target, "RISC-V semihosting sequence found "
86+
"at PC = 0x%" TARGET_PRIxADDR, pc);
87+
*sequence_found = true;
88+
return ERROR_OK;
89+
}
90+
4091
/**
4192
* Initialize RISC-V semihosting. Use common ARM code.
4293
*/
@@ -60,42 +111,32 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
60111
assert(semihosting);
61112

62113
if (!semihosting->is_active) {
63-
LOG_TARGET_DEBUG(target, " -> NONE (!semihosting->is_active)");
114+
LOG_TARGET_DEBUG(target, "Semihosting outcome: NONE (semihosting not enabled)");
64115
return SEMIHOSTING_NONE;
65116
}
66117

67118
riscv_reg_t pc;
68119
int result = riscv_reg_get(target, &pc, GDB_REGNO_PC);
69-
if (result != ERROR_OK)
120+
if (result != ERROR_OK) {
121+
LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (failed to read PC)");
70122
return SEMIHOSTING_ERROR;
123+
}
71124

72-
/*
73-
* The instructions that trigger a semihosting call,
74-
* always uncompressed, should look like:
75-
*/
76-
uint32_t magic[] = {
77-
0x01f01013, /* slli zero,zero,0x1f */
78-
0x00100073, /* ebreak */
79-
0x40705013 /* srai zero,zero,0x7 */
80-
};
125+
bool sequence_found;
126+
*retval = riscv_semihosting_detect_magic_sequence(target, pc, &sequence_found);
127+
if (*retval != ERROR_OK) {
128+
LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (during magic seq. detection)");
129+
return SEMIHOSTING_ERROR;
130+
}
81131

82-
/* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */
83-
for (int i = 0; i < 3; i++) {
84-
uint8_t buf[4];
85-
/* Instruction memories may not support arbitrary read size. Use any size that will work. */
86-
target_addr_t address = (pc - 4) + 4 * i;
87-
*retval = riscv_read_by_any_size(target, address, 4, buf);
88-
if (*retval != ERROR_OK)
89-
return SEMIHOSTING_ERROR;
90-
uint32_t value = target_buffer_get_u32(target, buf);
91-
LOG_TARGET_DEBUG(target, "compare 0x%08x from 0x%" PRIx64 " against 0x%08x",
92-
value, address, magic[i]);
93-
if (value != magic[i]) {
94-
LOG_TARGET_DEBUG(target, " -> NONE (no magic)");
95-
return SEMIHOSTING_NONE;
96-
}
132+
if (!sequence_found) {
133+
LOG_TARGET_DEBUG(target, "Semihosting outcome: NONE (no magic sequence)");
134+
return SEMIHOSTING_NONE;
97135
}
98136

137+
/* Otherwise we have a semihosting call (and semihosting is enabled).
138+
* Proceed with the semihosting. */
139+
99140
/*
100141
* Perform semihosting call if we are not waiting on a fileio
101142
* operation to complete.
@@ -108,12 +149,14 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
108149
result = riscv_reg_get(target, &r0, GDB_REGNO_A0);
109150
if (result != ERROR_OK) {
110151
LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a0)");
152+
LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (failed to read a0)");
111153
return SEMIHOSTING_ERROR;
112154
}
113155

114156
result = riscv_reg_get(target, &r1, GDB_REGNO_A1);
115157
if (result != ERROR_OK) {
116158
LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a1)");
159+
LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (failed to read a1)");
117160
return SEMIHOSTING_ERROR;
118161
}
119162

@@ -128,11 +171,13 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
128171
*retval = semihosting_common(target);
129172
if (*retval != ERROR_OK) {
130173
LOG_TARGET_ERROR(target, "Failed semihosting operation (0x%02X)", semihosting->op);
174+
LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (error during semihosting processing)");
131175
return SEMIHOSTING_ERROR;
132176
}
133177
} else {
134178
/* Unknown operation number, not a semihosting call. */
135179
LOG_TARGET_ERROR(target, "Unknown semihosting operation requested (op = 0x%x)", semihosting->op);
180+
LOG_TARGET_DEBUG(target, "Semihosting outcome: NONE (unknown semihosting opcode)");
136181
return SEMIHOSTING_NONE;
137182
}
138183
}
@@ -147,11 +192,11 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
147192
* operation to complete.
148193
*/
149194
if (semihosting->is_resumable && !semihosting->hit_fileio) {
150-
LOG_TARGET_DEBUG(target, " -> HANDLED");
195+
LOG_TARGET_DEBUG(target, "Semihosting outcome: HANDLED");
151196
return SEMIHOSTING_HANDLED;
152197
}
153198

154-
LOG_TARGET_DEBUG(target, " -> WAITING");
199+
LOG_TARGET_DEBUG(target, "Semihosting outcome: WAITING");
155200
return SEMIHOSTING_WAITING;
156201
}
157202

0 commit comments

Comments
 (0)