target/espressif: add algorithm support to execute code on target
[openocd.git] / src / target / espressif / esp32.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * ESP32 target API for OpenOCD *
5 * Copyright (C) 2016-2019 Espressif Systems Ltd. *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/time_support.h>
13 #include <target/target.h>
14 #include <target/target_type.h>
15 #include <target/smp.h>
16 #include <target/semihosting_common.h>
17 #include "assert.h"
18 #include "esp_xtensa_smp.h"
19
20 /*
21 This is a JTAG driver for the ESP32, the are two Tensilica cores inside
22 the ESP32 chip. For more information please have a look into ESP32 target
23 implementation.
24 */
25
26 /* ESP32 memory map */
27 #define ESP32_RTC_DATA_LOW 0x50000000
28 #define ESP32_RTC_DATA_HIGH 0x50002000
29 #define ESP32_DR_REG_LOW 0x3ff00000
30 #define ESP32_DR_REG_HIGH 0x3ff71000
31 #define ESP32_SYS_RAM_LOW 0x60000000UL
32 #define ESP32_SYS_RAM_HIGH (ESP32_SYS_RAM_LOW + 0x20000000UL)
33 #define ESP32_RTC_SLOW_MEM_BASE ESP32_RTC_DATA_LOW
34
35 /* ESP32 WDT */
36 #define ESP32_WDT_WKEY_VALUE 0x50d83aa1
37 #define ESP32_TIMG0_BASE 0x3ff5f000
38 #define ESP32_TIMG1_BASE 0x3ff60000
39 #define ESP32_TIMGWDT_CFG0_OFF 0x48
40 #define ESP32_TIMGWDT_PROTECT_OFF 0x64
41 #define ESP32_TIMG0WDT_CFG0 (ESP32_TIMG0_BASE + ESP32_TIMGWDT_CFG0_OFF)
42 #define ESP32_TIMG1WDT_CFG0 (ESP32_TIMG1_BASE + ESP32_TIMGWDT_CFG0_OFF)
43 #define ESP32_TIMG0WDT_PROTECT (ESP32_TIMG0_BASE + ESP32_TIMGWDT_PROTECT_OFF)
44 #define ESP32_TIMG1WDT_PROTECT (ESP32_TIMG1_BASE + ESP32_TIMGWDT_PROTECT_OFF)
45 #define ESP32_RTCCNTL_BASE 0x3ff48000
46 #define ESP32_RTCWDT_CFG_OFF 0x8C
47 #define ESP32_RTCWDT_PROTECT_OFF 0xA4
48 #define ESP32_RTCWDT_CFG (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_CFG_OFF)
49 #define ESP32_RTCWDT_PROTECT (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_PROTECT_OFF)
50
51 #define ESP32_TRACEMEM_BLOCK_SZ 0x4000
52
53 /* ESP32 dport regs */
54 #define ESP32_DR_REG_DPORT_BASE ESP32_DR_REG_LOW
55 #define ESP32_DPORT_APPCPU_CTRL_B_REG (ESP32_DR_REG_DPORT_BASE + 0x030)
56 #define ESP32_DPORT_APPCPU_CLKGATE_EN BIT(0)
57 /* ESP32 RTC regs */
58 #define ESP32_RTC_CNTL_SW_CPU_STALL_REG (ESP32_RTCCNTL_BASE + 0xac)
59 #define ESP32_RTC_CNTL_SW_CPU_STALL_DEF 0x0
60
61 /* 0 - don't care, 1 - TMS low, 2 - TMS high */
62 enum esp32_flash_bootstrap {
63 FBS_DONTCARE = 0,
64 FBS_TMSLOW,
65 FBS_TMSHIGH,
66 };
67
68 struct esp32_common {
69 struct esp_xtensa_smp_common esp_xtensa_smp;
70 enum esp32_flash_bootstrap flash_bootstrap;
71 };
72
73 static inline struct esp32_common *target_to_esp32(struct target *target)
74 {
75 return container_of(target->arch_info, struct esp32_common, esp_xtensa_smp);
76 }
77
78 /* Reset ESP32 peripherals.
79 * Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted,
80 * APP CPU is in reset
81 * How this works:
82 * 0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt
83 * 1. set CPU initial PC to 0x50000000 (ESP32_SMP_RTC_DATA_LOW) by clearing RTC_CNTL_{PRO,APP}CPU_STAT_VECTOR_SEL
84 * 2. load stub code into ESP32_SMP_RTC_DATA_LOW; once executed, stub code will disable watchdogs and
85 * make CPU spin in an idle loop.
86 * 3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit
87 * 4. wait for the OCD to be reset
88 * 5. halt the target and wait for it to be halted (at this point CPU is in the idle loop)
89 * 6. restore initial PC and the contents of ESP32_SMP_RTC_DATA_LOW
90 * TODO: some state of RTC_CNTL is not reset during SW_SYS_RST. Need to reset that manually. */
91
92 static const uint8_t esp32_reset_stub_code[] = {
93 #include "../../../contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc"
94 };
95
96 static int esp32_soc_reset(struct target *target)
97 {
98 int res;
99 struct target_list *head;
100 struct xtensa *xtensa;
101
102 LOG_DEBUG("start");
103 /* In order to write to peripheral registers, target must be halted first */
104 if (target->state != TARGET_HALTED) {
105 LOG_DEBUG("Target not halted before SoC reset, trying to halt it first");
106 xtensa_halt(target);
107 res = target_wait_state(target, TARGET_HALTED, 1000);
108 if (res != ERROR_OK) {
109 LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt");
110 res = xtensa_assert_reset(target);
111 if (res != ERROR_OK) {
112 LOG_ERROR(
113 "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)",
114 res);
115 return res;
116 }
117 alive_sleep(10);
118 xtensa_poll(target);
119 bool reset_halt_save = target->reset_halt;
120 target->reset_halt = true;
121 res = xtensa_deassert_reset(target);
122 target->reset_halt = reset_halt_save;
123 if (res != ERROR_OK) {
124 LOG_ERROR(
125 "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)",
126 res);
127 return res;
128 }
129 alive_sleep(10);
130 xtensa_poll(target);
131 xtensa_halt(target);
132 res = target_wait_state(target, TARGET_HALTED, 1000);
133 if (res != ERROR_OK) {
134 LOG_ERROR("Couldn't halt target before SoC reset");
135 return res;
136 }
137 }
138 }
139
140 if (target->smp) {
141 foreach_smp_target(head, target->smp_targets) {
142 xtensa = target_to_xtensa(head->target);
143 /* if any of the cores is stalled unstall them */
144 if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) {
145 LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!");
146 res = target_write_u32(target,
147 ESP32_RTC_CNTL_SW_CPU_STALL_REG,
148 ESP32_RTC_CNTL_SW_CPU_STALL_DEF);
149 if (res != ERROR_OK) {
150 LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!");
151 return res;
152 }
153 break; /* both cores are unstalled now, so exit the loop */
154 }
155 }
156 }
157
158 LOG_DEBUG("Loading stub code into RTC RAM");
159 uint8_t slow_mem_save[sizeof(esp32_reset_stub_code)];
160
161 /* Save contents of RTC_SLOW_MEM which we are about to overwrite */
162 res = target_read_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save);
163 if (res != ERROR_OK) {
164 LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res);
165 return res;
166 }
167
168 /* Write stub code into RTC_SLOW_MEM */
169 res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(esp32_reset_stub_code), esp32_reset_stub_code);
170 if (res != ERROR_OK) {
171 LOG_ERROR("Failed to write stub (%d)!", res);
172 return res;
173 }
174
175 LOG_DEBUG("Resuming the target");
176 xtensa = target_to_xtensa(target);
177 xtensa->suppress_dsr_errors = true;
178 res = xtensa_resume(target, 0, ESP32_RTC_SLOW_MEM_BASE + 4, 0, 0);
179 xtensa->suppress_dsr_errors = false;
180 if (res != ERROR_OK) {
181 LOG_ERROR("Failed to run stub (%d)!", res);
182 return res;
183 }
184 LOG_DEBUG("resume done, waiting for the target to come alive");
185
186 /* Wait for SoC to reset */
187 alive_sleep(100);
188 int64_t timeout = timeval_ms() + 100;
189 bool get_timeout = false;
190 while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) {
191 alive_sleep(10);
192 xtensa_poll(target);
193 if (timeval_ms() >= timeout) {
194 LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d",
195 target->state);
196 get_timeout = true;
197 break;
198 }
199 }
200
201 /* Halt the CPU again */
202 LOG_DEBUG("halting the target");
203 xtensa_halt(target);
204 res = target_wait_state(target, TARGET_HALTED, 1000);
205 if (res == ERROR_OK) {
206 LOG_DEBUG("restoring RTC_SLOW_MEM");
207 res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save);
208 if (res != ERROR_OK)
209 LOG_TARGET_ERROR(target, "Failed to restore contents of RTC_SLOW_MEM (%d)!", res);
210 } else {
211 LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be halted after SoC reset");
212 }
213
214 return get_timeout ? ERROR_TARGET_TIMEOUT : res;
215 }
216
217 static int esp32_disable_wdts(struct target *target)
218 {
219 /* TIMG1 WDT */
220 int res = target_write_u32(target, ESP32_TIMG0WDT_PROTECT, ESP32_WDT_WKEY_VALUE);
221 if (res != ERROR_OK) {
222 LOG_ERROR("Failed to write ESP32_TIMG0WDT_PROTECT (%d)!", res);
223 return res;
224 }
225 res = target_write_u32(target, ESP32_TIMG0WDT_CFG0, 0);
226 if (res != ERROR_OK) {
227 LOG_ERROR("Failed to write ESP32_TIMG0WDT_CFG0 (%d)!", res);
228 return res;
229 }
230 /* TIMG2 WDT */
231 res = target_write_u32(target, ESP32_TIMG1WDT_PROTECT, ESP32_WDT_WKEY_VALUE);
232 if (res != ERROR_OK) {
233 LOG_ERROR("Failed to write ESP32_TIMG1WDT_PROTECT (%d)!", res);
234 return res;
235 }
236 res = target_write_u32(target, ESP32_TIMG1WDT_CFG0, 0);
237 if (res != ERROR_OK) {
238 LOG_ERROR("Failed to write ESP32_TIMG1WDT_CFG0 (%d)!", res);
239 return res;
240 }
241 /* RTC WDT */
242 res = target_write_u32(target, ESP32_RTCWDT_PROTECT, ESP32_WDT_WKEY_VALUE);
243 if (res != ERROR_OK) {
244 LOG_ERROR("Failed to write ESP32_RTCWDT_PROTECT (%d)!", res);
245 return res;
246 }
247 res = target_write_u32(target, ESP32_RTCWDT_CFG, 0);
248 if (res != ERROR_OK) {
249 LOG_ERROR("Failed to write ESP32_RTCWDT_CFG (%d)!", res);
250 return res;
251 }
252 return ERROR_OK;
253 }
254
255 static int esp32_on_halt(struct target *target)
256 {
257 int ret = esp32_disable_wdts(target);
258 if (ret == ERROR_OK)
259 ret = esp_xtensa_smp_on_halt(target);
260 return ret;
261 }
262
263 static int esp32_arch_state(struct target *target)
264 {
265 return ERROR_OK;
266 }
267
268 static int esp32_virt2phys(struct target *target,
269 target_addr_t virtual, target_addr_t *physical)
270 {
271 if (physical) {
272 *physical = virtual;
273 return ERROR_OK;
274 }
275 return ERROR_FAIL;
276 }
277
278 /* The TDI pin is also used as a flash Vcc bootstrap pin. If we reset the CPU externally, the last state of the TDI pin
279 * can allow the power to an 1.8V flash chip to be raised to 3.3V, or the other way around. Users can use the
280 * esp32 flashbootstrap command to set a level, and this routine will make sure the tdi line will return to
281 * that when the jtag port is idle. */
282
283 static void esp32_queue_tdi_idle(struct target *target)
284 {
285 struct esp32_common *esp32 = target_to_esp32(target);
286 static uint32_t value;
287 uint8_t t[4] = { 0, 0, 0, 0 };
288
289 if (esp32->flash_bootstrap == FBS_TMSLOW)
290 /* Make sure tdi is 0 at the exit of queue execution */
291 value = 0;
292 else if (esp32->flash_bootstrap == FBS_TMSHIGH)
293 /* Make sure tdi is 1 at the exit of queue execution */
294 value = 1;
295 else
296 return;
297
298 /* Scan out 1 bit, do not move from IRPAUSE after we're done. */
299 buf_set_u32(t, 0, 1, value);
300 jtag_add_plain_ir_scan(1, t, NULL, TAP_IRPAUSE);
301 }
302
303 static int esp32_target_init(struct command_context *cmd_ctx, struct target *target)
304 {
305 return esp_xtensa_smp_target_init(cmd_ctx, target);
306 }
307
308 static const struct xtensa_debug_ops esp32_dbg_ops = {
309 .queue_enable = xtensa_dm_queue_enable,
310 .queue_reg_read = xtensa_dm_queue_reg_read,
311 .queue_reg_write = xtensa_dm_queue_reg_write
312 };
313
314 static const struct xtensa_power_ops esp32_pwr_ops = {
315 .queue_reg_read = xtensa_dm_queue_pwr_reg_read,
316 .queue_reg_write = xtensa_dm_queue_pwr_reg_write
317 };
318
319 static const struct esp_xtensa_smp_chip_ops esp32_chip_ops = {
320 .reset = esp32_soc_reset,
321 .on_halt = esp32_on_halt
322 };
323
324 static const struct esp_semihost_ops esp32_semihost_ops = {
325 .prepare = esp32_disable_wdts
326 };
327
328 static int esp32_target_create(struct target *target, Jim_Interp *interp)
329 {
330 struct xtensa_debug_module_config esp32_dm_cfg = {
331 .dbg_ops = &esp32_dbg_ops,
332 .pwr_ops = &esp32_pwr_ops,
333 .tap = target->tap,
334 .queue_tdi_idle = esp32_queue_tdi_idle,
335 .queue_tdi_idle_arg = target
336 };
337
338 struct esp32_common *esp32 = calloc(1, sizeof(struct esp32_common));
339 if (!esp32) {
340 LOG_ERROR("Failed to alloc memory for arch info!");
341 return ERROR_FAIL;
342 }
343
344 int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp,
345 &esp32_dm_cfg, &esp32_chip_ops, &esp32_semihost_ops);
346 if (ret != ERROR_OK) {
347 LOG_ERROR("Failed to init arch info!");
348 free(esp32);
349 return ret;
350 }
351 esp32->flash_bootstrap = FBS_DONTCARE;
352
353 /* Assume running target. If different, the first poll will fix this. */
354 target->state = TARGET_RUNNING;
355 target->debug_reason = DBG_REASON_NOTHALTED;
356 return ERROR_OK;
357 }
358
359 static COMMAND_HELPER(esp32_cmd_flashbootstrap_do, struct esp32_common *esp32)
360 {
361 int state = -1;
362
363 if (CMD_ARGC < 1) {
364 const char *st;
365 state = esp32->flash_bootstrap;
366 if (state == FBS_DONTCARE)
367 st = "Don't care";
368 else if (state == FBS_TMSLOW)
369 st = "Low (3.3V)";
370 else if (state == FBS_TMSHIGH)
371 st = "High (1.8V)";
372 else
373 st = "None";
374 command_print(CMD, "Current idle tms state: %s", st);
375 return ERROR_OK;
376 }
377
378 if (!strcasecmp(CMD_ARGV[0], "none"))
379 state = FBS_DONTCARE;
380 else if (!strcasecmp(CMD_ARGV[0], "1.8"))
381 state = FBS_TMSHIGH;
382 else if (!strcasecmp(CMD_ARGV[0], "3.3"))
383 state = FBS_TMSLOW;
384 else if (!strcasecmp(CMD_ARGV[0], "high"))
385 state = FBS_TMSHIGH;
386 else if (!strcasecmp(CMD_ARGV[0], "low"))
387 state = FBS_TMSLOW;
388
389 if (state == -1) {
390 command_print(CMD,
391 "Argument unknown. Please pick one of none, high, low, 1.8 or 3.3");
392 return ERROR_FAIL;
393 }
394 esp32->flash_bootstrap = state;
395 return ERROR_OK;
396 }
397
398 COMMAND_HANDLER(esp32_cmd_flashbootstrap)
399 {
400 struct target *target = get_current_target(CMD_CTX);
401
402 if (target->smp) {
403 struct target_list *head;
404 struct target *curr;
405 foreach_smp_target(head, target->smp_targets) {
406 curr = head->target;
407 int ret = CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do,
408 target_to_esp32(curr));
409 if (ret != ERROR_OK)
410 return ret;
411 }
412 return ERROR_OK;
413 }
414 return CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do,
415 target_to_esp32(target));
416 }
417
418 static const struct command_registration esp32_any_command_handlers[] = {
419 {
420 .name = "flashbootstrap",
421 .handler = esp32_cmd_flashbootstrap,
422 .mode = COMMAND_ANY,
423 .help =
424 "Set the idle state of the TMS pin, which at reset also is the voltage selector for the flash chip.",
425 .usage = "none|1.8|3.3|high|low",
426 },
427 COMMAND_REGISTRATION_DONE
428 };
429
430 static const struct command_registration esp32_command_handlers[] = {
431 {
432 .chain = esp_xtensa_smp_command_handlers,
433 },
434 {
435 .name = "esp",
436 .usage = "",
437 .chain = esp32_apptrace_command_handlers,
438 },
439 {
440 .name = "esp32",
441 .usage = "",
442 .chain = smp_command_handlers,
443 },
444 {
445 .name = "esp32",
446 .usage = "",
447 .chain = esp32_any_command_handlers,
448 },
449 {
450 .name = "arm",
451 .mode = COMMAND_ANY,
452 .help = "ARM Command Group",
453 .usage = "",
454 .chain = semihosting_common_handlers
455 },
456 COMMAND_REGISTRATION_DONE
457 };
458
459 /** Holds methods for Xtensa targets. */
460 struct target_type esp32_target = {
461 .name = "esp32",
462
463 .poll = esp_xtensa_smp_poll,
464 .arch_state = esp32_arch_state,
465
466 .halt = xtensa_halt,
467 .resume = esp_xtensa_smp_resume,
468 .step = esp_xtensa_smp_step,
469
470 .assert_reset = esp_xtensa_smp_assert_reset,
471 .deassert_reset = esp_xtensa_smp_deassert_reset,
472 .soft_reset_halt = esp_xtensa_smp_soft_reset_halt,
473
474 .virt2phys = esp32_virt2phys,
475 .mmu = xtensa_mmu_is_enabled,
476 .read_memory = xtensa_read_memory,
477 .write_memory = xtensa_write_memory,
478
479 .read_buffer = xtensa_read_buffer,
480 .write_buffer = xtensa_write_buffer,
481
482 .checksum_memory = xtensa_checksum_memory,
483
484 .get_gdb_arch = xtensa_get_gdb_arch,
485 .get_gdb_reg_list = xtensa_get_gdb_reg_list,
486
487 .add_breakpoint = esp_xtensa_breakpoint_add,
488 .remove_breakpoint = esp_xtensa_breakpoint_remove,
489
490 .add_watchpoint = esp_xtensa_smp_watchpoint_add,
491 .remove_watchpoint = esp_xtensa_smp_watchpoint_remove,
492
493 .target_create = esp32_target_create,
494 .init_target = esp32_target_init,
495 .examine = xtensa_examine,
496 .deinit_target = esp_xtensa_target_deinit,
497
498 .commands = esp32_command_handlers,
499 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)