OpenOCD
arm_semihosting.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2009 by Marvell Technology Group Ltd. *
5  * Written by Nicolas Pitre <nico@marvell.com> *
6  * *
7  * Copyright (C) 2010 by Spencer Oliver *
8  * spen@spen-soft.co.uk *
9  * *
10  * Copyright (C) 2016 by Square, Inc. *
11  * Steven Stallion <stallion@squareup.com> *
12  * *
13  * Copyright (C) 2018 by Liviu Ionescu *
14  * <ilg@livius.net> *
15  ***************************************************************************/
16 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "arm.h"
34 #include "armv4_5.h"
35 #include "arm7_9_common.h"
36 #include "armv7m.h"
37 #include "armv7a.h"
38 #include "armv8.h"
39 #include "cortex_m.h"
40 #include "register.h"
41 #include "arm_opcodes.h"
42 #include "target_type.h"
43 #include "arm_semihosting.h"
44 #include <helper/binarybuffer.h>
45 #include <helper/log.h>
46 #include <sys/stat.h>
47 
48 static int arm_semihosting_resume(struct target *target, int *retval)
49 {
51  struct armv8_common *armv8 = target_to_armv8(target);
53  *retval = target_resume(target, 1, 0, 0, 0);
54  if (*retval != ERROR_OK) {
55  LOG_ERROR("Failed to resume target");
56  return 0;
57  }
58  } else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP)
60  } else {
61  *retval = target_resume(target, 1, 0, 0, 0);
62  if (*retval != ERROR_OK) {
63  LOG_ERROR("Failed to resume target");
64  return 0;
65  }
66  }
67  return 1;
68 }
69 
70 static int post_result(struct target *target)
71 {
72  struct arm *arm = target_to_arm(target);
73 
74  if (!target->semihosting)
75  return ERROR_FAIL;
76 
77  /* REVISIT this looks wrong ... ARM11 and Cortex-A8
78  * should work this way at least sometimes.
79  */
82  uint32_t spsr;
83 
84  /* return value in R0 */
86  arm->core_cache->reg_list[0].dirty = true;
87 
88  /* LR --> PC */
90  buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32));
91  arm->core_cache->reg_list[15].dirty = true;
92 
93  /* saved PSR --> current PSR */
94  spsr = buf_get_u32(arm->spsr->value, 0, 32);
95 
96  /* REVISIT should this be arm_set_cpsr(arm, spsr)
97  * instead of a partially unrolled version?
98  */
99 
100  buf_set_u32(arm->cpsr->value, 0, 32, spsr);
101  arm->cpsr->dirty = true;
102  arm->core_mode = spsr & 0x1f;
103  if (spsr & 0x20)
105 
106  } else if (is_armv8(target_to_armv8(target))) {
107  if (arm->core_state == ARM_STATE_AARCH64) {
108  /* return value in R0 */
110  arm->core_cache->reg_list[0].dirty = true;
111 
112  uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64);
113  buf_set_u64(arm->pc->value, 0, 64, pc + 4);
114  arm->pc->dirty = true;
115  } else if (arm->core_state == ARM_STATE_ARM) {
116  /* return value in R0 */
118  arm->core_cache->reg_list[0].dirty = true;
119 
120  uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32);
121  buf_set_u32(arm->pc->value, 0, 32, pc + 4);
122  arm->pc->dirty = true;
123  } else if (arm->core_state == ARM_STATE_THUMB) {
124  /* return value in R0 */
126  arm->core_cache->reg_list[0].dirty = true;
127 
128  uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32);
129  buf_set_u32(arm->pc->value, 0, 32, pc + 2);
130  arm->pc->dirty = true;
131  }
132  } else {
133  /* resume execution, this will be pc+2 to skip over the
134  * bkpt instruction */
135 
136  /* return result in R0 */
138  arm->core_cache->reg_list[0].dirty = true;
139  }
140 
141  return ERROR_OK;
142 }
143 
151 {
152  struct arm *arm = target_to_arm(target);
153  assert(arm->setup_semihosting);
155 
156  return ERROR_OK;
157 }
158 
172 int arm_semihosting(struct target *target, int *retval)
173 {
174  struct arm *arm = target_to_arm(target);
175  struct armv7a_common *armv7a = target_to_armv7a(target);
176  uint32_t pc, lr, spsr;
177  struct reg *r;
178 
180  if (!semihosting)
181  return 0;
182 
183  if (!semihosting->is_active)
184  return 0;
185 
187  is_armv7a(armv7a)) {
188  uint32_t vbar = 0x00000000;
189 
190  if (arm->core_mode != ARM_MODE_SVC)
191  return 0;
192 
193  if (is_armv7a(armv7a)) {
194  struct arm_dpm *dpm = armv7a->arm.dpm;
195 
196  *retval = dpm->prepare(dpm);
197  if (*retval == ERROR_OK) {
198  *retval = dpm->instr_read_data_r0(dpm,
199  ARMV4_5_MRC(15, 0, 0, 12, 0, 0),
200  &vbar);
201 
202  dpm->finish(dpm);
203 
204  if (*retval != ERROR_OK)
205  return 1;
206  } else {
207  return 1;
208  }
209  }
210 
211  /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
212  r = arm->pc;
213  pc = buf_get_u32(r->value, 0, 32);
214  if (pc != (vbar + 0x00000008) && pc != 0xffff0008)
215  return 0;
216 
217  r = arm_reg_current(arm, 14);
218  lr = buf_get_u32(r->value, 0, 32);
219 
220  /* Core-specific code should make sure SPSR is retrieved
221  * when the above checks pass...
222  */
223  if (!arm->spsr->valid) {
224  LOG_ERROR("SPSR not valid!");
225  *retval = ERROR_FAIL;
226  return 1;
227  }
228 
229  spsr = buf_get_u32(arm->spsr->value, 0, 32);
230 
231  /* check instruction that triggered this trap */
232  if (spsr & (1 << 5)) {
233  /* was in Thumb (or ThumbEE) mode */
234  uint8_t insn_buf[2];
235  uint16_t insn;
236 
237  *retval = target_read_memory(target, lr-2, 2, 1, insn_buf);
238  if (*retval != ERROR_OK)
239  return 1;
240  insn = target_buffer_get_u16(target, insn_buf);
241 
242  /* SVC 0xab */
243  if (insn != 0xDFAB)
244  return 0;
245  } else if (spsr & (1 << 24)) {
246  /* was in Jazelle mode */
247  return 0;
248  } else {
249  /* was in ARM mode */
250  uint8_t insn_buf[4];
251  uint32_t insn;
252 
253  *retval = target_read_memory(target, lr-4, 4, 1, insn_buf);
254  if (*retval != ERROR_OK)
255  return 1;
256  insn = target_buffer_get_u32(target, insn_buf);
257 
258  /* SVC 0x123456 */
259  if (insn != 0xEF123456)
260  return 0;
261  }
262  } else if (is_armv7m(target_to_armv7m(target))) {
263  uint16_t insn;
264 
266  return 0;
267 
268  r = arm->pc;
269  pc = buf_get_u32(r->value, 0, 32);
270 
271  pc &= ~1;
272  *retval = target_read_u16(target, pc, &insn);
273  if (*retval != ERROR_OK)
274  return 1;
275 
276  /* bkpt 0xAB */
277  if (insn != 0xBEAB)
278  return 0;
279  } else if (is_armv8(target_to_armv8(target))) {
281  return 0;
282 
283  /* According to ARM Semihosting for AArch32 and AArch64:
284  * The HLT encodings are new in version 2.0 of the semihosting specification.
285  * Where possible, have semihosting callers continue to use the previously
286  * existing trap instructions to ensure compatibility with legacy semihosting
287  * implementations.
288  * These trap instructions are HLT for A64, SVC on A+R profile A32 or T32,
289  * and BKPT on M profile.
290  * However, it is necessary to change from SVC to HLT instructions to support
291  * AArch32 semihosting properly in a mixed AArch32/AArch64 system. */
292 
293  if (arm->core_state == ARM_STATE_AARCH64) {
294  uint32_t insn = 0;
295  r = arm->pc;
296  uint64_t pc64 = buf_get_u64(r->value, 0, 64);
297  *retval = target_read_u32(target, pc64, &insn);
298 
299  if (*retval != ERROR_OK)
300  return 1;
301 
302  /* HLT 0xF000 */
303  if (insn != 0xD45E0000)
304  return 0;
305  } else if (arm->core_state == ARM_STATE_ARM) {
306  r = arm->pc;
307  pc = buf_get_u32(r->value, 0, 32);
308 
309  /* A32 instruction => check for HLT 0xF000 (0xE10F0070) */
310  uint32_t insn = 0;
311 
312  *retval = target_read_u32(target, pc, &insn);
313 
314  if (*retval != ERROR_OK)
315  return 1;
316 
317  /* HLT 0xF000*/
318  if (insn != 0xE10F0070)
319  return 0;
320  } else if (arm->core_state == ARM_STATE_THUMB) {
321  r = arm->pc;
322  pc = buf_get_u32(r->value, 0, 32);
323 
324  /* T32 instruction => check for HLT 0x3C (0xBABC) */
325  uint16_t insn = 0;
326  *retval = target_read_u16(target, pc, &insn);
327 
328  if (*retval != ERROR_OK)
329  return 1;
330 
331  /* HLT 0x3C*/
332  if (insn != 0xBABC)
333  return 0;
334  } else
335  return 1;
336  } else {
337  LOG_ERROR("Unsupported semi-hosting Target");
338  return 0;
339  }
340 
341  /* Perform semihosting if we are not waiting on a fileio
342  * operation to complete.
343  */
344  if (!semihosting->hit_fileio) {
347  /* Read op and param from register x0 and x1 respectively. */
351  } else {
352  /* Read op and param from register r0 and r1 respectively. */
356  }
357 
358  /* Check for ARM operation numbers. */
359  if ((semihosting->op >= 0 && semihosting->op <= 0x31) ||
360  (semihosting->op >= 0x100 && semihosting->op <= 0x107)) {
361 
362  *retval = semihosting_common(target);
363  if (*retval != ERROR_OK) {
364  LOG_ERROR("Failed semihosting operation (0x%02X)",
365  semihosting->op);
366  return 0;
367  }
368  } else {
369  /* Unknown operation number, not a semihosting call. */
370  return 0;
371  }
372  }
373 
374  /* Resume if target it is resumable and we are not waiting on a fileio
375  * operation to complete:
376  */
378  return arm_semihosting_resume(target, retval);
379 
380  return 0;
381 }
static struct arm7_9_common * target_to_arm7_9(struct target *target)
static bool is_arm7_9(struct arm7_9_common *arm7_9)
Holds the interface to ARM cores.
@ ARM_MODE_SVC
Definition: arm.h:78
@ ARM_STATE_THUMB
Definition: arm.h:144
@ ARM_STATE_ARM
Definition: arm.h:143
@ ARM_STATE_AARCH64
Definition: arm.h:147
static struct arm * target_to_arm(struct target *target)
Convert target handle to generic ARM target state handle.
Definition: arm.h:243
struct reg * arm_reg_current(struct arm *arm, unsigned regnum)
Returns handle to the register currently mapped to a given number.
Definition: armv4_5.c:502
Macros used to generate various ARM or Thumb opcodes.
#define ARMV4_5_MRC(cp, op1, rd, crn, crm, op2)
Definition: arm_opcodes.h:186
int arm_semihosting(struct target *target, int *retval)
Checks for and processes an ARM semihosting request.
int arm_semihosting_init(struct target *target)
Initialize ARM semihosting support.
static int post_result(struct target *target)
static int arm_semihosting_resume(struct target *target, int *retval)
static struct armv7a_common * target_to_armv7a(struct target *target)
Definition: armv7a.h:122
static bool is_armv7a(struct armv7a_common *armv7a)
Definition: armv7a.h:127
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:260
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:248
static struct armv8_common * target_to_armv8(struct target *target)
Definition: armv8.h:228
@ ARMV8_RUNCONTROL_RESUME
Definition: armv8.h:106
@ ARMV8_RUNCONTROL_STEP
Definition: armv8.h:108
static bool is_armv8(struct armv8_common *armv8)
Definition: armv8.h:233
Support functions to access arbitrary bits in a byte array.
static void buf_set_u64(uint8_t *_buffer, unsigned first, unsigned num, uint64_t value)
Sets num bits in _buffer, starting at the first bit, using the bits in value.
Definition: binarybuffer.h:60
static uint32_t buf_get_u32(const uint8_t *_buffer, unsigned first, unsigned num)
Retrieves num bits from _buffer, starting at the first bit, returning the bits in a 32-bit word.
Definition: binarybuffer.h:98
static void buf_set_u32(uint8_t *_buffer, unsigned first, unsigned num, uint32_t value)
Sets num bits in _buffer, starting at the first bit, using the bits in value.
Definition: binarybuffer.h:30
static uint64_t buf_get_u64(const uint8_t *_buffer, unsigned first, unsigned num)
Retrieves num bits from _buffer, starting at the first bit, returning the bits in a 64-bit word.
Definition: binarybuffer.h:127
#define ERROR_FAIL
Definition: log.h:161
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define ERROR_OK
Definition: log.h:155
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.
This wraps an implementation of DPM primitives.
Definition: arm_dpm.h:47
int(* finish)(struct arm_dpm *dpm)
Invoke after a series of instruction operations.
Definition: arm_dpm.h:57
int(* prepare)(struct arm_dpm *dpm)
Invoke before a series of instruction operations.
Definition: arm_dpm.h:54
int(* instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data)
Runs one instruction, reading data from r0 after execution.
Definition: arm_dpm.h:92
Represents a generic ARM core, with standard application registers.
Definition: arm.h:167
enum arm_mode core_mode
Record the current core mode: SVC, USR, or some other mode.
Definition: arm.h:188
struct reg * cpsr
Handle to the CPSR/xPSR; valid in all core modes.
Definition: arm.h:176
struct reg * pc
Handle to the PC; valid in all core modes.
Definition: arm.h:173
int(* setup_semihosting)(struct target *target, int enable)
Definition: arm.h:199
struct reg_cache * core_cache
Definition: arm.h:170
struct arm_dpm * dpm
Handle for the debug module, if one is present.
Definition: arm.h:205
struct reg * spsr
Handle to the SPSR; valid only in core modes with an SPSR.
Definition: arm.h:179
enum arm_state core_state
Record the current core state: ARM, Thumb, or otherwise.
Definition: arm.h:191
struct arm arm
Definition: armv7a.h:92
enum run_control_op last_run_control_op
Definition: armv8.h:209
struct reg * reg_list
Definition: register.h:147
Definition: register.h:111
bool valid
Definition: register.h:126
uint8_t * value
Definition: register.h:122
bool dirty
Definition: register.h:124
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).
Definition: target.h:120
struct semihosting * semihosting
Definition: target.h:210
enum target_debug_reason debug_reason
Definition: target.h:159
int target_read_u16(struct target *target, target_addr_t address, uint16_t *value)
Definition: target.c:2640
int target_read_u32(struct target *target, target_addr_t address, uint32_t *value)
Definition: target.c:2616
uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer)
Definition: target.c:393
int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
Read count items of size bytes from the memory of target at the address given.
Definition: target.c:1306
uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
Definition: target.c:375
int target_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution)
Make the target (re)start executing using its saved execution context (possibly with some modificatio...
Definition: target.c:634
@ DBG_REASON_SINGLESTEP
Definition: target.h:77
@ DBG_REASON_BREAKPOINT
Definition: target.h:74