Skip to content

Commit 88fe568

Browse files
authored
Merge pull request #1199 from JanMatCodasip/jm-codasip/semihosting-2-refactor-magic-seq-detection
RISC-V Semihosting 2 of 3: Refactor magic sequence detection
2 parents 2210897 + 8c0a1cd commit 88fe568

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)