1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2018 by Liviu Ionescu *
7 * Copyright (C) 2009 by Marvell Technology Group Ltd. *
8 * Written by Nicolas Pitre <nico@marvell.com> *
10 * Copyright (C) 2010 by Spencer Oliver *
11 * spen@spen-soft.co.uk *
13 * Copyright (C) 2016 by Square, Inc. *
14 * Steven Stallion <stallion@squareup.com> *
15 ***************************************************************************/
19 * Hold RISC-V semihosting support.
21 * The RISC-V code is inspired from ARM semihosting.
23 * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf
31 #include <helper/log.h>
33 #include "target/target.h"
36 static int riscv_semihosting_setup(struct target *target, int enable);
37 static int riscv_semihosting_post_result(struct target *target);
40 * Initialize RISC-V semihosting. Use common ARM code.
42 void riscv_semihosting_init(struct target *target)
44 semihosting_common_init(target, riscv_semihosting_setup,
45 riscv_semihosting_post_result);
49 * Check for and process a semihosting request using the ARM protocol). This
50 * is meant to be called when the target is stopped due to a debug mode entry.
52 * @param target Pointer to the target to process.
53 * @param retval Pointer to a location where the return code will be stored
54 * @return non-zero value if a request was processed or an error encountered
56 enum semihosting_result riscv_semihosting(struct target *target, int *retval)
58 struct semihosting *semihosting = target->semihosting;
60 LOG_DEBUG(" -> NONE (!semihosting)");
61 return SEMIHOSTING_NONE;
64 if (!semihosting->is_active) {
65 LOG_DEBUG(" -> NONE (!semihosting->is_active)");
66 return SEMIHOSTING_NONE;
70 int result = riscv_get_register(target, &pc, GDB_REGNO_PC);
71 if (result != ERROR_OK)
72 return SEMIHOSTING_ERROR;
76 /* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */
77 for (int i = 0; i < 3; i++) {
78 /* Instruction memories may not support arbitrary read size. Use any size that will work. */
79 *retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i);
80 if (*retval != ERROR_OK)
81 return SEMIHOSTING_ERROR;
85 * The instructions that trigger a semihosting call,
86 * always uncompressed, should look like:
88 * 01f01013 slli zero,zero,0x1f
90 * 40705013 srai zero,zero,0x7
92 uint32_t pre = target_buffer_get_u32(target, tmp_buf);
93 uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4);
94 uint32_t post = target_buffer_get_u32(target, tmp_buf + 8);
95 LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc);
97 if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
98 /* Not the magic sequence defining semihosting. */
99 LOG_DEBUG(" -> NONE (no magic)");
100 return SEMIHOSTING_NONE;
104 * Perform semihosting call if we are not waiting on a fileio
105 * operation to complete.
107 if (!semihosting->hit_fileio) {
108 /* RISC-V uses A0 and A1 to pass function arguments */
112 result = riscv_get_register(target, &r0, GDB_REGNO_A0);
113 if (result != ERROR_OK) {
114 LOG_DEBUG(" -> ERROR (couldn't read a0)");
115 return SEMIHOSTING_ERROR;
118 result = riscv_get_register(target, &r1, GDB_REGNO_A1);
119 if (result != ERROR_OK) {
120 LOG_DEBUG(" -> ERROR (couldn't read a1)");
121 return SEMIHOSTING_ERROR;
124 semihosting->op = r0;
125 semihosting->param = r1;
126 semihosting->word_size_bytes = riscv_xlen(target) / 8;
128 /* Check for ARM operation numbers. */
129 if ((semihosting->op >= 0 && semihosting->op <= 0x31) ||
130 (semihosting->op >= 0x100 && semihosting->op <= 0x107)) {
132 *retval = semihosting_common(target);
133 if (*retval != ERROR_OK) {
134 LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op);
135 return SEMIHOSTING_ERROR;
138 /* Unknown operation number, not a semihosting call. */
139 LOG_DEBUG(" -> NONE (unknown operation number)");
140 return SEMIHOSTING_NONE;
145 * Resume target if we are not waiting on a fileio
146 * operation to complete.
148 if (semihosting->is_resumable && !semihosting->hit_fileio) {
149 /* Resume right after the EBREAK 4 bytes instruction. */
150 *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4);
151 if (*retval != ERROR_OK)
152 return SEMIHOSTING_ERROR;
154 LOG_DEBUG(" -> HANDLED");
155 return SEMIHOSTING_HANDLED;
158 LOG_DEBUG(" -> WAITING");
159 return SEMIHOSTING_WAITING;
162 /* -------------------------------------------------------------------------
163 * Local functions. */
166 * Called via semihosting->setup() later, after the target is known,
167 * usually on the first semihosting command.
169 static int riscv_semihosting_setup(struct target *target, int enable)
171 LOG_DEBUG("[%s] enable=%d", target_name(target), enable);
173 struct semihosting *semihosting = target->semihosting;
175 semihosting->setup_time = clock();
180 static int riscv_semihosting_post_result(struct target *target)
182 struct semihosting *semihosting = target->semihosting;
184 /* If not enabled, silently ignored. */
188 LOG_DEBUG("0x%" PRIx64, semihosting->result);
189 riscv_set_register(target, GDB_REGNO_A0, semihosting->result);