OpenOCD
riscv_semihosting.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2018 by Liviu Ionescu *
5  * ilg@livius.net *
6  * *
7  * Copyright (C) 2009 by Marvell Technology Group Ltd. *
8  * Written by Nicolas Pitre <nico@marvell.com> *
9  * *
10  * Copyright (C) 2010 by Spencer Oliver *
11  * spen@spen-soft.co.uk *
12  * *
13  * Copyright (C) 2016 by Square, Inc. *
14  * Steven Stallion <stallion@squareup.com> *
15  ***************************************************************************/
16 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <helper/log.h>
32 
33 #include "target/target.h"
34 #include "riscv.h"
35 
36 static int riscv_semihosting_setup(struct target *target, int enable);
37 static int riscv_semihosting_post_result(struct target *target);
38 
43 {
46 }
47 
56 enum semihosting_result riscv_semihosting(struct target *target, int *retval)
57 {
59  if (!semihosting) {
60  LOG_DEBUG(" -> NONE (!semihosting)");
61  return SEMIHOSTING_NONE;
62  }
63 
64  if (!semihosting->is_active) {
65  LOG_DEBUG(" -> NONE (!semihosting->is_active)");
66  return SEMIHOSTING_NONE;
67  }
68 
69  riscv_reg_t pc;
71  if (result != ERROR_OK)
72  return SEMIHOSTING_ERROR;
73 
74  uint8_t tmp_buf[12];
75 
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;
82  }
83 
84  /*
85  * The instructions that trigger a semihosting call,
86  * always uncompressed, should look like:
87  *
88  * 01f01013 slli zero,zero,0x1f
89  * 00100073 ebreak
90  * 40705013 srai zero,zero,0x7
91  */
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);
96 
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;
101  }
102 
103  /*
104  * Perform semihosting call if we are not waiting on a fileio
105  * operation to complete.
106  */
107  if (!semihosting->hit_fileio) {
108  /* RISC-V uses A0 and A1 to pass function arguments */
109  riscv_reg_t r0;
110  riscv_reg_t r1;
111 
113  if (result != ERROR_OK) {
114  LOG_DEBUG(" -> ERROR (couldn't read a0)");
115  return SEMIHOSTING_ERROR;
116  }
117 
119  if (result != ERROR_OK) {
120  LOG_DEBUG(" -> ERROR (couldn't read a1)");
121  return SEMIHOSTING_ERROR;
122  }
123 
124  semihosting->op = r0;
125  semihosting->param = r1;
127 
128  /* Check for ARM operation numbers. */
129  if ((semihosting->op >= 0 && semihosting->op <= 0x31) ||
130  (semihosting->op >= 0x100 && semihosting->op <= 0x107)) {
131 
132  *retval = semihosting_common(target);
133  if (*retval != ERROR_OK) {
134  LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op);
135  return SEMIHOSTING_ERROR;
136  }
137  } else {
138  /* Unknown operation number, not a semihosting call. */
139  LOG_DEBUG(" -> NONE (unknown operation number)");
140  return SEMIHOSTING_NONE;
141  }
142  }
143 
144  /* Resume right after the EBREAK 4 bytes instruction. */
145  *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4);
146  if (*retval != ERROR_OK)
147  return SEMIHOSTING_ERROR;
148 
149  /*
150  * Resume target if we are not waiting on a fileio
151  * operation to complete.
152  */
154  LOG_DEBUG(" -> HANDLED");
155  return SEMIHOSTING_HANDLED;
156  }
157 
158  LOG_DEBUG(" -> WAITING");
159  return SEMIHOSTING_WAITING;
160 }
161 
162 /* -------------------------------------------------------------------------
163  * Local functions. */
164 
169 static int riscv_semihosting_setup(struct target *target, int enable)
170 {
171  LOG_DEBUG("[%s] enable=%d", target_name(target), enable);
172 
174  if (semihosting)
175  semihosting->setup_time = clock();
176 
177  return ERROR_OK;
178 }
179 
181 {
183  if (!semihosting) {
184  /* If not enabled, silently ignored. */
185  return 0;
186  }
187 
188  LOG_DEBUG("0x%" PRIx64, semihosting->result);
190  return 0;
191 }
@ GDB_REGNO_A1
Definition: gdb_regs.h:21
@ GDB_REGNO_A0
Definition: gdb_regs.h:20
@ GDB_REGNO_PC
Definition: gdb_regs.h:45
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
static uint32_t ebreak(void) __attribute__((unused))
Definition: opcodes.h:219
unsigned int riscv_xlen(const struct target *target)
Definition: riscv.c:3207
int riscv_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value)
This function is called when the debug user wants to change the value of a register.
Definition: riscv.c:3308
int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Read one memory item using any memory access size that will work.
Definition: riscv.c:837
int riscv_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno regid)
Get register, from the cache if it's in there.
Definition: riscv.c:3334
uint64_t riscv_reg_t
Definition: riscv.h:41
static int riscv_semihosting_post_result(struct target *target)
void riscv_semihosting_init(struct target *target)
Initialize RISC-V semihosting.
enum semihosting_result riscv_semihosting(struct target *target, int *retval)
Check for and process a semihosting request using the ARM protocol).
static int riscv_semihosting_setup(struct target *target, int enable)
Called via semihosting->setup() later, after the target is known, usually on the first semihosting co...
int semihosting_common_init(struct target *target, void *setup, void *post_result)
Initialize common semihosting support.
int semihosting_common(struct target *target)
Portable implementation of ARM semihosting calls.
semihosting_result
@ SEMIHOSTING_ERROR
@ SEMIHOSTING_HANDLED
@ SEMIHOSTING_WAITING
@ SEMIHOSTING_NONE
bool is_resumable
Most are resumable, except the two exit calls.
bool hit_fileio
A flag reporting whether semihosting fileio operation is active.
size_t word_size_bytes
The Target (hart) word size; 8 for 64-bits targets.
int64_t result
The current semihosting result to be returned to the application.
bool is_active
A flag reporting whether semihosting is active.
int op
The current semihosting operation (R0 on ARM).
uint64_t param
The current semihosting parameter (R1 or ARM).
clock_t setup_time
The current time when 'execution starts'.
Definition: target.h:116
struct semihosting * semihosting
Definition: target.h:209
uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
Definition: target.c:316
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233