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