OpenOCD
esp_xtensa_algorithm.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Module to run arbitrary code on Xtensa using OpenOCD *
5  * Copyright (C) 2019 Espressif Systems Ltd. *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <target/xtensa/xtensa.h>
13 #include "esp_xtensa_algorithm.h"
14 
15 static int esp_xtensa_algo_init(struct target *target, struct esp_algorithm_run_data *run,
16  uint32_t num_args, va_list ap);
17 static int esp_xtensa_algo_cleanup(struct target *target, struct esp_algorithm_run_data *run);
18 static const uint8_t *esp_xtensa_stub_tramp_get(struct target *target, size_t *size);
19 
20 const struct esp_algorithm_hw xtensa_algo_hw = {
22  .algo_cleanup = esp_xtensa_algo_cleanup,
23  .stub_tramp_get = esp_xtensa_stub_tramp_get,
24 };
25 
26 /* Generated from contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.S */
27 static const uint8_t esp_xtensa_stub_tramp_win[] = {
28 #include "../../../contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.inc"
29 };
30 
31 static const uint8_t *esp_xtensa_stub_tramp_get(struct target *target, size_t *size)
32 {
34 
35  if (!xtensa->core_config->windowed) {
36  LOG_ERROR("Running stubs is not supported for cores without windowed registers option!");
37  return NULL;
38  }
41 }
42 
44 {
45  uint32_t stack_addr = run->stub.stack_addr;
46 
47  LOG_TARGET_DEBUG(target, "Check stack addr 0x%x", stack_addr);
48  if (stack_addr & 0xFUL) {
49  stack_addr &= ~0xFUL;
50  LOG_TARGET_DEBUG(target, "Adjust stack addr to 0x%x", stack_addr);
51  }
52  stack_addr -= 16;
53  struct reg_param *params = run->reg_args.params;
54  init_reg_param(&params[0], "a0", 32, PARAM_OUT); /*TODO: move to tramp */
55  init_reg_param(&params[1], "a1", 32, PARAM_OUT);
56  init_reg_param(&params[2], "a8", 32, PARAM_OUT);
57  init_reg_param(&params[3], "windowbase", 32, PARAM_OUT); /*TODO: move to tramp */
58  init_reg_param(&params[4], "windowstart", 32, PARAM_OUT); /*TODO: move to tramp */
59  init_reg_param(&params[5], "ps", 32, PARAM_OUT);
60  buf_set_u32(params[0].value, 0, 32, 0); /* a0 TODO: move to tramp */
61  buf_set_u32(params[1].value, 0, 32, stack_addr); /* a1 */
62  buf_set_u32(params[2].value, 0, 32, run->stub.entry); /* a8 */
63  buf_set_u32(params[3].value, 0, 32, 0x0); /* initial window base TODO: move to tramp */
64  buf_set_u32(params[4].value, 0, 32, 0x1); /* initial window start TODO: move to tramp */
65  buf_set_u32(params[5].value, 0, 32, 0x60025); /* enable WOE, UM and debug interrupts level (6) */
66  return ERROR_OK;
67 }
68 
69 static int esp_xtensa_algo_init(struct target *target, struct esp_algorithm_run_data *run,
70  uint32_t num_args, va_list ap)
71 {
72  enum xtensa_mode core_mode = XT_MODE_ANY;
73  static const char *const arg_regs[] = { "a2", "a3", "a4", "a5", "a6" };
74 
75  if (!run)
76  return ERROR_FAIL;
77 
78  if (num_args > ARRAY_SIZE(arg_regs)) {
79  LOG_ERROR("Too many algo user args %u! Max %zu args are supported.", num_args, ARRAY_SIZE(arg_regs));
80  return ERROR_FAIL;
81  }
82 
83  struct xtensa_algorithm *ainfo = calloc(1, sizeof(struct xtensa_algorithm));
84  if (!ainfo) {
85  LOG_ERROR("Unable to allocate memory");
86  return ERROR_FAIL;
87  }
88 
89  if (run->arch_info) {
90  struct xtensa_algorithm *xtensa_algo = run->arch_info;
91  core_mode = xtensa_algo->core_mode;
92  }
93 
95  run->reg_args.count = run->reg_args.first_user_param + num_args;
96  if (num_args == 0)
97  run->reg_args.count++; /* a2 reg is used as the 1st arg and return code */
98  LOG_DEBUG("reg params count %d (%d/%d).",
99  run->reg_args.count,
101  num_args);
102  run->reg_args.params = calloc(run->reg_args.count, sizeof(struct reg_param));
103  if (!run->reg_args.params) {
104  free(ainfo);
105  LOG_ERROR("Unable to allocate memory");
106  return ERROR_FAIL;
107  }
108 
110 
112 
113  if (num_args > 0) {
114  uint32_t arg = va_arg(ap, uint32_t);
115  esp_algorithm_user_arg_set_uint(run, 0, arg);
116  LOG_DEBUG("Set arg[0] = %d (%s)", arg, run->reg_args.params[run->reg_args.first_user_param + 0].reg_name);
117  } else {
119  }
120 
121  for (unsigned int i = 1; i < num_args; i++) {
122  uint32_t arg = va_arg(ap, uint32_t);
123  init_reg_param(&run->reg_args.params[run->reg_args.first_user_param + i], (char *)arg_regs[i], 32, PARAM_OUT);
124  esp_algorithm_user_arg_set_uint(run, i, arg);
125  LOG_DEBUG("Set arg[%d] = %d (%s)", i, arg, run->reg_args.params[run->reg_args.first_user_param + i].reg_name);
126  }
127 
128  ainfo->core_mode = core_mode;
129  run->stub.ainfo = ainfo;
130  return ERROR_OK;
131 }
132 
134 {
135  free(run->stub.ainfo);
136  for (uint32_t i = 0; i < run->reg_args.count; i++)
138  free(run->reg_args.params);
139  return ERROR_OK;
140 }
void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction)
Definition: algorithm.c:29
void destroy_reg_param(struct reg_param *param)
Definition: algorithm.c:37
@ PARAM_OUT
Definition: algorithm.h:16
@ PARAM_IN_OUT
Definition: algorithm.h:17
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 void esp_algorithm_user_arg_set_uint(struct esp_algorithm_run_data *run, int arg_num, uint64_t val)
Set the value of an argument passed via registers to the stub main function.
static int esp_xtensa_algo_cleanup(struct target *target, struct esp_algorithm_run_data *run)
static int esp_xtensa_algo_init(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, va_list ap)
static const uint8_t esp_xtensa_stub_tramp_win[]
static int esp_xtensa_algo_regs_init_start(struct target *target, struct esp_algorithm_run_data *run)
const struct esp_algorithm_hw xtensa_algo_hw
static const uint8_t * esp_xtensa_stub_tramp_get(struct target *target, size_t *size)
#define ESP_XTENSA_STUB_ARGS_FUNC_START
Index of the first user-defined algo arg.
#define ERROR_FAIL
Definition: log.h:170
#define LOG_TARGET_DEBUG(target, fmt_str,...)
Definition: log.h:149
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
int(* algo_init)(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, va_list ap)
struct reg_param * params
Algorithm register params.
uint32_t first_user_param
The first several reg_params can be used by stub itself (e.g.
uint32_t count
Number of register params.
Algorithm run data.
struct esp_algorithm_reg_args reg_args
Algorithm register arguments.
void * arch_info
Algorithm arch-specific info.
struct esp_algorithm_stub stub
Stub.
target_addr_t stack_addr
Address of the target buffer for stack.
void * ainfo
Algorithm's arch-specific info.
target_addr_t entry
Entry addr.
uint8_t * value
Definition: algorithm.h:30
const char * reg_name
Definition: algorithm.h:28
Definition: target.h:116
Xtensa algorithm data.
Definition: xtensa.h:228
enum xtensa_mode core_mode
User can set this to specify which core mode algorithm should be run in.
Definition: xtensa.h:230
bool windowed
Definition: xtensa.h:171
Represents a generic Xtensa core.
Definition: xtensa.h:241
struct xtensa_config * core_config
Definition: xtensa.h:244
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16
Holds the interface to Xtensa cores.
static struct xtensa * target_to_xtensa(struct target *target)
Definition: xtensa.h:290
xtensa_mode
Definition: xtensa.h:209
@ XT_MODE_ANY
Definition: xtensa.h:214