jtag/core: Use 'bool' data type for 'bypass'
[openocd.git] / src / jtag / drivers / dmem.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /* Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ */
4
5 /**
6 * @file
7 * This file implements support for the Direct memory access to CoreSight
8 * Access Ports (APs) or emulate the same to access CoreSight debug registers
9 * directly.
10 */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include <sys/mman.h>
17
18 #include <helper/align.h>
19 #include <helper/types.h>
20 #include <helper/system.h>
21 #include <helper/time_support.h>
22 #include <helper/list.h>
23 #include <jtag/interface.h>
24
25 #include <target/arm_adi_v5.h>
26 #include <transport/transport.h>
27
28 struct dmem_emu_ap_info {
29 uint64_t ap_num;
30 /* Emulation mode AP state variables */
31 uint32_t apbap_tar;
32 uint32_t apbap_csw;
33 };
34
35 /*
36 * This bit tells if the transaction is coming in from jtag or not
37 * we just mask this out to emulate direct address access
38 */
39 #define ARM_APB_PADDR31 BIT(31)
40
41 static void *dmem_map_base, *dmem_virt_base_addr;
42 static size_t dmem_mapped_size;
43
44 /* Default dmem device. */
45 #define DMEM_DEV_PATH_DEFAULT "/dev/mem"
46 static char *dmem_dev_path;
47 static uint64_t dmem_dap_base_address;
48 static unsigned int dmem_dap_max_aps = 1;
49 static uint32_t dmem_dap_ap_offset = 0x100;
50
51 /* DAP error code. */
52 static int dmem_dap_retval = ERROR_OK;
53
54 /* AP Emulation Mode */
55 static uint64_t dmem_emu_base_address;
56 static uint64_t dmem_emu_size;
57 static void *dmem_emu_map_base, *dmem_emu_virt_base_addr;
58 static size_t dmem_emu_mapped_size;
59 #define DMEM_MAX_EMULATE_APS 5
60 static unsigned int dmem_emu_ap_count;
61 static struct dmem_emu_ap_info dmem_emu_ap_list[DMEM_MAX_EMULATE_APS];
62
63 /*
64 * This helper is used to determine the TAR increment size in bytes. The AP's
65 * CSW encoding for SIZE supports byte count decode using "1 << SIZE".
66 */
67 static uint32_t dmem_memap_tar_inc(uint32_t csw)
68 {
69 if ((csw & CSW_ADDRINC_MASK) != 0)
70 return 1 << (csw & CSW_SIZE_MASK);
71 return 0;
72 }
73
74 /*
75 * EMULATION MODE: In Emulation MODE, we assume the following:
76 * TCL still describes as system is operational from the view of AP (ex. jtag)
77 * However, the hardware doesn't permit direct memory access to these APs
78 * (only permitted via JTAG).
79 *
80 * So, the access to these APs have to be decoded to a memory map
81 * access which we can directly access.
82 *
83 * A few TI processors have this issue.
84 */
85 static bool dmem_is_emulated_ap(struct adiv5_ap *ap, unsigned int *idx)
86 {
87 for (unsigned int i = 0; i < dmem_emu_ap_count; i++) {
88 if (ap->ap_num == dmem_emu_ap_list[i].ap_num) {
89 *idx = i;
90 return true;
91 }
92 }
93 return false;
94 }
95
96 static void dmem_emu_set_ap_reg(uint64_t addr, uint32_t val)
97 {
98 addr &= ~ARM_APB_PADDR31;
99
100 *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr) = val;
101 }
102
103 static uint32_t dmem_emu_get_ap_reg(uint64_t addr)
104 {
105 uint32_t val;
106
107 addr &= ~ARM_APB_PADDR31;
108
109 val = *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr);
110
111 return val;
112 }
113
114 static int dmem_emu_ap_q_read(unsigned int ap_idx, unsigned int reg, uint32_t *data)
115 {
116 uint64_t addr;
117 int ret = ERROR_OK;
118 struct dmem_emu_ap_info *ap_info = &dmem_emu_ap_list[ap_idx];
119
120 switch (reg) {
121 case ADIV5_MEM_AP_REG_CSW:
122 *data = ap_info->apbap_csw;
123 break;
124 case ADIV5_MEM_AP_REG_TAR:
125 *data = ap_info->apbap_tar;
126 break;
127 case ADIV5_MEM_AP_REG_CFG:
128 *data = 0;
129 break;
130 case ADIV5_MEM_AP_REG_BASE:
131 *data = 0;
132 break;
133 case ADIV5_AP_REG_IDR:
134 *data = 0;
135 break;
136 case ADIV5_MEM_AP_REG_BD0:
137 case ADIV5_MEM_AP_REG_BD1:
138 case ADIV5_MEM_AP_REG_BD2:
139 case ADIV5_MEM_AP_REG_BD3:
140 addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C);
141
142 *data = dmem_emu_get_ap_reg(addr);
143
144 break;
145 case ADIV5_MEM_AP_REG_DRW:
146 addr = ap_info->apbap_tar;
147
148 *data = dmem_emu_get_ap_reg(addr);
149
150 ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw);
151 break;
152 default:
153 LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg);
154 ret = ERROR_FAIL;
155 break;
156 }
157
158 /* Track the last error code. */
159 if (ret != ERROR_OK)
160 dmem_dap_retval = ret;
161
162 return ret;
163 }
164
165 static int dmem_emu_ap_q_write(unsigned int ap_idx, unsigned int reg, uint32_t data)
166 {
167 uint64_t addr;
168 int ret = ERROR_OK;
169 struct dmem_emu_ap_info *ap_info = &dmem_emu_ap_list[ap_idx];
170
171 switch (reg) {
172 case ADIV5_MEM_AP_REG_CSW:
173 /*
174 * This implementation only supports 32-bit accesses.
175 * Force this by ensuring CSW_SIZE field indicates 32-BIT.
176 */
177 ap_info->apbap_csw = ((data & ~CSW_SIZE_MASK) | CSW_32BIT);
178 break;
179 case ADIV5_MEM_AP_REG_TAR:
180 /*
181 * This implementation only supports 32-bit accesses.
182 * Force LS 2-bits of TAR to 00b
183 */
184 ap_info->apbap_tar = (data & ~0x3);
185 break;
186
187 case ADIV5_MEM_AP_REG_CFG:
188 case ADIV5_MEM_AP_REG_BASE:
189 case ADIV5_AP_REG_IDR:
190 /* We don't use this, so we don't need to store */
191 break;
192
193 case ADIV5_MEM_AP_REG_BD0:
194 case ADIV5_MEM_AP_REG_BD1:
195 case ADIV5_MEM_AP_REG_BD2:
196 case ADIV5_MEM_AP_REG_BD3:
197 addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C);
198
199 dmem_emu_set_ap_reg(addr, data);
200
201 break;
202 case ADIV5_MEM_AP_REG_DRW:
203 addr = ap_info->apbap_tar;
204 dmem_emu_set_ap_reg(addr, data);
205
206 ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw);
207 break;
208 default:
209 LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg);
210 ret = EINVAL;
211 break;
212 }
213
214 /* Track the last error code. */
215 if (ret != ERROR_OK)
216 dmem_dap_retval = ret;
217
218 return ret;
219 }
220
221 /* AP MODE */
222 static uint32_t dmem_get_ap_reg_offset(struct adiv5_ap *ap, unsigned int reg)
223 {
224 return (dmem_dap_ap_offset * ap->ap_num) + reg;
225 }
226
227 static void dmem_set_ap_reg(struct adiv5_ap *ap, unsigned int reg, uint32_t val)
228 {
229 *(volatile uint32_t *)((uintptr_t)dmem_virt_base_addr +
230 dmem_get_ap_reg_offset(ap, reg)) = val;
231 }
232
233 static uint32_t dmem_get_ap_reg(struct adiv5_ap *ap, unsigned int reg)
234 {
235 return *(volatile uint32_t *)((uintptr_t)dmem_virt_base_addr +
236 dmem_get_ap_reg_offset(ap, reg));
237 }
238
239 static int dmem_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data)
240 {
241 if (!data)
242 return ERROR_OK;
243
244 switch (reg) {
245 case DP_CTRL_STAT:
246 *data = CDBGPWRUPACK | CSYSPWRUPACK;
247 break;
248
249 default:
250 *data = 0;
251 break;
252 }
253
254 return ERROR_OK;
255 }
256
257 static int dmem_dp_q_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data)
258 {
259 return ERROR_OK;
260 }
261
262 static int dmem_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data)
263 {
264 unsigned int idx;
265
266 if (is_adiv6(ap->dap)) {
267 static bool error_flagged;
268
269 if (!error_flagged)
270 LOG_ERROR("ADIv6 dap not supported by dmem dap-direct mode");
271
272 error_flagged = true;
273
274 return ERROR_FAIL;
275 }
276
277 if (dmem_is_emulated_ap(ap, &idx))
278 return dmem_emu_ap_q_read(idx, reg, data);
279
280 *data = dmem_get_ap_reg(ap, reg);
281
282 return ERROR_OK;
283 }
284
285 static int dmem_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data)
286 {
287 unsigned int idx;
288
289 if (is_adiv6(ap->dap)) {
290 static bool error_flagged;
291
292 if (!error_flagged)
293 LOG_ERROR("ADIv6 dap not supported by dmem dap-direct mode");
294
295 error_flagged = true;
296
297 return ERROR_FAIL;
298 }
299
300 if (dmem_is_emulated_ap(ap, &idx))
301 return dmem_emu_ap_q_write(idx, reg, data);
302
303 dmem_set_ap_reg(ap, reg, data);
304
305 return ERROR_OK;
306 }
307
308 static int dmem_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
309 {
310 return ERROR_OK;
311 }
312
313 static int dmem_dp_run(struct adiv5_dap *dap)
314 {
315 int retval = dmem_dap_retval;
316
317 /* Clear the error code. */
318 dmem_dap_retval = ERROR_OK;
319
320 return retval;
321 }
322
323 static int dmem_connect(struct adiv5_dap *dap)
324 {
325 return ERROR_OK;
326 }
327
328 COMMAND_HANDLER(dmem_dap_device_command)
329 {
330 if (CMD_ARGC != 1)
331 return ERROR_COMMAND_SYNTAX_ERROR;
332
333 free(dmem_dev_path);
334 dmem_dev_path = strdup(CMD_ARGV[0]);
335
336 return ERROR_OK;
337 }
338
339 COMMAND_HANDLER(dmem_dap_base_address_command)
340 {
341 if (CMD_ARGC != 1)
342 return ERROR_COMMAND_SYNTAX_ERROR;
343
344 COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], dmem_dap_base_address);
345
346 return ERROR_OK;
347 }
348
349 COMMAND_HANDLER(dmem_dap_max_aps_command)
350 {
351 if (CMD_ARGC != 1)
352 return ERROR_COMMAND_SYNTAX_ERROR;
353
354 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dmem_dap_max_aps);
355
356 return ERROR_OK;
357 }
358
359 COMMAND_HANDLER(dmem_dap_ap_offset_command)
360 {
361 if (CMD_ARGC != 1)
362 return ERROR_COMMAND_SYNTAX_ERROR;
363
364 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dmem_dap_ap_offset);
365
366 return ERROR_OK;
367 }
368
369 COMMAND_HANDLER(dmem_emu_base_address_command)
370 {
371 if (CMD_ARGC != 2)
372 return ERROR_COMMAND_SYNTAX_ERROR;
373
374 COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], dmem_emu_base_address);
375 COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], dmem_emu_size);
376
377 return ERROR_OK;
378 }
379
380 COMMAND_HANDLER(dmem_emu_ap_list_command)
381 {
382 uint64_t em_ap;
383
384 if (CMD_ARGC < 1 || CMD_ARGC > DMEM_MAX_EMULATE_APS)
385 return ERROR_COMMAND_SYNTAX_ERROR;
386
387 for (unsigned int i = 0; i < CMD_ARGC; i++) {
388 COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], em_ap);
389 dmem_emu_ap_list[i].ap_num = em_ap;
390 }
391
392 dmem_emu_ap_count = CMD_ARGC;
393
394 return ERROR_OK;
395 }
396
397 COMMAND_HANDLER(dmem_dap_config_info_command)
398 {
399 if (CMD_ARGC != 0)
400 return ERROR_COMMAND_SYNTAX_ERROR;
401
402 command_print(CMD, "dmem (Direct Memory) AP Adapter Configuration:");
403 command_print(CMD, " Device : %s",
404 dmem_dev_path ? dmem_dev_path : DMEM_DEV_PATH_DEFAULT);
405 command_print(CMD, " Base Address : 0x%" PRIx64, dmem_dap_base_address);
406 command_print(CMD, " Max APs : %u", dmem_dap_max_aps);
407 command_print(CMD, " AP offset : 0x%08" PRIx32, dmem_dap_ap_offset);
408 command_print(CMD, " Emulated AP Count : %u", dmem_emu_ap_count);
409
410 if (dmem_emu_ap_count) {
411 command_print(CMD, " Emulated AP details:");
412 command_print(CMD, " Emulated address : 0x%" PRIx64, dmem_emu_base_address);
413 command_print(CMD, " Emulated size : 0x%" PRIx64, dmem_emu_size);
414 for (unsigned int i = 0; i < dmem_emu_ap_count; i++)
415 command_print(CMD, " Emulated AP [%u] : %" PRIx64, i,
416 dmem_emu_ap_list[i].ap_num);
417 }
418 return ERROR_OK;
419 }
420
421 static const struct command_registration dmem_dap_subcommand_handlers[] = {
422 {
423 .name = "info",
424 .handler = dmem_dap_config_info_command,
425 .mode = COMMAND_ANY,
426 .help = "print the config info",
427 .usage = "",
428 },
429 {
430 .name = "device",
431 .handler = dmem_dap_device_command,
432 .mode = COMMAND_CONFIG,
433 .help = "set the dmem memory access device (default: /dev/mem)",
434 .usage = "device_path",
435 },
436 {
437 .name = "base_address",
438 .handler = dmem_dap_base_address_command,
439 .mode = COMMAND_CONFIG,
440 .help = "set the dmem dap AP memory map base address",
441 .usage = "base_address",
442 },
443 {
444 .name = "ap_address_offset",
445 .handler = dmem_dap_ap_offset_command,
446 .mode = COMMAND_CONFIG,
447 .help = "set the offsets of each ap index",
448 .usage = "offset_address",
449 },
450 {
451 .name = "max_aps",
452 .handler = dmem_dap_max_aps_command,
453 .mode = COMMAND_CONFIG,
454 .help = "set the maximum number of APs this will support",
455 .usage = "n",
456 },
457 {
458 .name = "emu_ap_list",
459 .handler = dmem_emu_ap_list_command,
460 .mode = COMMAND_CONFIG,
461 .help = "set the list of AP indices to be emulated (upto max)",
462 .usage = "n",
463 },
464 {
465 .name = "emu_base_address_range",
466 .handler = dmem_emu_base_address_command,
467 .mode = COMMAND_CONFIG,
468 .help = "set the base address and size of emulated AP range (all emulated APs access this range)",
469 .usage = "base_address address_window_size",
470 },
471 COMMAND_REGISTRATION_DONE
472 };
473
474 static const struct command_registration dmem_dap_command_handlers[] = {
475 {
476 .name = "dmem",
477 .mode = COMMAND_ANY,
478 .help = "Perform dmem (Direct Memory) DAP management and configuration",
479 .chain = dmem_dap_subcommand_handlers,
480 .usage = "",
481 },
482 COMMAND_REGISTRATION_DONE
483 };
484
485 static int dmem_dap_init(void)
486 {
487 char *path = dmem_dev_path ? dmem_dev_path : DMEM_DEV_PATH_DEFAULT;
488 uint32_t dmem_total_memory_window_size;
489 long page_size = sysconf(_SC_PAGESIZE);
490 size_t dmem_mapped_start, dmem_mapped_end;
491 long start_delta;
492 int dmem_fd;
493
494 if (!dmem_dap_base_address) {
495 LOG_ERROR("dmem DAP Base address NOT set? value is 0");
496 return ERROR_FAIL;
497 }
498
499 dmem_fd = open(path, O_RDWR | O_SYNC);
500 if (dmem_fd == -1) {
501 LOG_ERROR("Unable to open %s", path);
502 return ERROR_FAIL;
503 }
504
505 dmem_total_memory_window_size = (dmem_dap_max_aps + 1) * dmem_dap_ap_offset;
506
507 dmem_mapped_start = dmem_dap_base_address;
508 dmem_mapped_end = dmem_dap_base_address + dmem_total_memory_window_size;
509 /* mmap() requires page aligned offsets */
510 dmem_mapped_start = ALIGN_DOWN(dmem_mapped_start, page_size);
511 dmem_mapped_end = ALIGN_UP(dmem_mapped_end, page_size);
512
513 dmem_mapped_size = dmem_mapped_end - dmem_mapped_start;
514 start_delta = dmem_mapped_start - dmem_dap_base_address;
515
516 dmem_map_base = mmap(NULL,
517 dmem_mapped_size,
518 (PROT_READ | PROT_WRITE),
519 MAP_SHARED, dmem_fd,
520 dmem_mapped_start);
521 if (dmem_map_base == MAP_FAILED) {
522 LOG_ERROR("Mapping address 0x%lx for 0x%lx bytes failed!",
523 dmem_mapped_start, dmem_mapped_size);
524 goto error_fail;
525 }
526
527 dmem_virt_base_addr = (void *)((uintptr_t)dmem_map_base + start_delta);
528
529 /* Lets Map the emulated address if necessary */
530 if (dmem_emu_ap_count) {
531 dmem_mapped_start = dmem_emu_base_address;
532 dmem_mapped_end = dmem_emu_base_address + dmem_emu_size;
533 /* mmap() requires page aligned offsets */
534 dmem_mapped_start = ALIGN_DOWN(dmem_mapped_start, page_size);
535 dmem_mapped_end = ALIGN_UP(dmem_mapped_end, page_size);
536
537 dmem_emu_mapped_size = dmem_mapped_end - dmem_mapped_start;
538 start_delta = dmem_mapped_start - dmem_emu_base_address;
539
540 dmem_emu_map_base = mmap(NULL,
541 dmem_emu_mapped_size,
542 (PROT_READ | PROT_WRITE),
543 MAP_SHARED, dmem_fd,
544 dmem_mapped_start);
545 if (dmem_emu_map_base == MAP_FAILED) {
546 LOG_ERROR("Mapping EMU address 0x%lx for 0x%lx bytes failed!",
547 dmem_emu_base_address, dmem_emu_size);
548 goto error_fail;
549 }
550 dmem_emu_virt_base_addr = (void *)((uintptr_t)dmem_emu_map_base +
551 start_delta);
552 }
553
554 close(dmem_fd);
555 return ERROR_OK;
556
557 error_fail:
558 close(dmem_fd);
559 return ERROR_FAIL;
560 }
561
562 static int dmem_dap_quit(void)
563 {
564 if (munmap(dmem_map_base, dmem_mapped_size) == -1)
565 LOG_ERROR("%s: Failed to unmap mapped memory!", __func__);
566
567 if (dmem_emu_ap_count
568 && munmap(dmem_emu_map_base, dmem_emu_mapped_size) == -1)
569 LOG_ERROR("%s: Failed to unmap emu mapped memory!", __func__);
570
571 return ERROR_OK;
572 }
573
574 static int dmem_dap_reset(int req_trst, int req_srst)
575 {
576 return ERROR_OK;
577 }
578
579 static int dmem_dap_speed(int speed)
580 {
581 return ERROR_OK;
582 }
583
584 static int dmem_dap_khz(int khz, int *jtag_speed)
585 {
586 *jtag_speed = khz;
587 return ERROR_OK;
588 }
589
590 static int dmem_dap_speed_div(int speed, int *khz)
591 {
592 *khz = speed;
593 return ERROR_OK;
594 }
595
596 /* DAP operations. */
597 static const struct dap_ops dmem_dap_ops = {
598 .connect = dmem_connect,
599 .queue_dp_read = dmem_dp_q_read,
600 .queue_dp_write = dmem_dp_q_write,
601 .queue_ap_read = dmem_ap_q_read,
602 .queue_ap_write = dmem_ap_q_write,
603 .queue_ap_abort = dmem_ap_q_abort,
604 .run = dmem_dp_run,
605 };
606
607 static const char *const dmem_dap_transport[] = { "dapdirect_swd", NULL };
608
609 struct adapter_driver dmem_dap_adapter_driver = {
610 .name = "dmem",
611 .transports = dmem_dap_transport,
612 .commands = dmem_dap_command_handlers,
613
614 .init = dmem_dap_init,
615 .quit = dmem_dap_quit,
616 .reset = dmem_dap_reset,
617 .speed = dmem_dap_speed,
618 .khz = dmem_dap_khz,
619 .speed_div = dmem_dap_speed_div,
620
621 .dap_swd_ops = &dmem_dap_ops,
622 };

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)