target/xtensa: add file-IO support
[openocd.git] / src / target / xtensa / xtensa_fileio.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Xtensa Target File-I/O Support for OpenOCD *
5 * Copyright (C) 2020-2023 Cadence Design Systems, Inc. *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "xtensa_chip.h"
13 #include "xtensa_fileio.h"
14 #include "xtensa.h"
15
16 #define XTENSA_SYSCALL(x) XT_INS_BREAK(x, 1, 14)
17 #define XTENSA_SYSCALL_SZ 3
18 #define XTENSA_SYSCALL_LEN_MAX 255
19
20
21 int xtensa_fileio_init(struct target *target)
22 {
23 char *idmem = malloc(XTENSA_SYSCALL_LEN_MAX + 1);
24 target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
25 if (!idmem || !target->fileio_info) {
26 LOG_TARGET_ERROR(target, "Out of memory!");
27 free(idmem);
28 free(target->fileio_info);
29 return ERROR_FAIL;
30 }
31 target->fileio_info->identifier = idmem;
32 return ERROR_OK;
33 }
34
35 /**
36 * Checks for and processes an Xtensa File-IO request.
37 *
38 * Return ERROR_OK if request was found and handled; or
39 * return ERROR_FAIL if no request was detected.
40 */
41 int xtensa_fileio_detect_proc(struct target *target)
42 {
43 struct xtensa *xtensa = target_to_xtensa(target);
44 int retval;
45
46 xtensa_reg_val_t dbg_cause = xtensa_cause_get(target);
47 if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0 || xtensa->halt_request)
48 return ERROR_FAIL;
49
50 uint8_t brk_insn_buf[sizeof(uint32_t)] = {0};
51 xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC);
52 retval = target_read_memory(target,
53 pc,
54 XTENSA_SYSCALL_SZ,
55 1,
56 (uint8_t *)brk_insn_buf);
57 if (retval != ERROR_OK) {
58 LOG_ERROR("Failed to read break instruction!");
59 return ERROR_FAIL;
60 }
61 if (buf_get_u32(brk_insn_buf, 0, 32) != XTENSA_SYSCALL(xtensa))
62 return ERROR_FAIL;
63
64 LOG_TARGET_DEBUG(target, "File-I/O: syscall breakpoint found at 0x%x", pc);
65 xtensa->proc_syscall = true;
66 return ERROR_OK;
67 }
68
69 int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
70 {
71 /* fill syscall parameters to file-I/O info */
72 if (!fileio_info) {
73 LOG_ERROR("File-I/O data structure uninitialized");
74 return ERROR_FAIL;
75 }
76
77 struct xtensa *xtensa = target_to_xtensa(target);
78 if (!xtensa->proc_syscall)
79 return ERROR_FAIL;
80
81 xtensa_reg_val_t syscall = xtensa_reg_get(target, XTENSA_SYSCALL_OP_REG);
82 xtensa_reg_val_t arg0 = xtensa_reg_get(target, XT_REG_IDX_A6);
83 xtensa_reg_val_t arg1 = xtensa_reg_get(target, XT_REG_IDX_A3);
84 xtensa_reg_val_t arg2 = xtensa_reg_get(target, XT_REG_IDX_A4);
85 xtensa_reg_val_t arg3 = xtensa_reg_get(target, XT_REG_IDX_A5);
86 int retval = ERROR_OK;
87
88 LOG_TARGET_DEBUG(target, "File-I/O: syscall 0x%x 0x%x 0x%x 0x%x 0x%x",
89 syscall, arg0, arg1, arg2, arg3);
90
91 switch (syscall) {
92 case XTENSA_SYSCALL_OPEN:
93 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "open");
94 fileio_info->param_1 = arg0; // pathp
95 fileio_info->param_2 = arg3; // len
96 fileio_info->param_3 = arg1; // flags
97 fileio_info->param_4 = arg2; // mode
98 break;
99 case XTENSA_SYSCALL_CLOSE:
100 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "close");
101 fileio_info->param_1 = arg0; // fd
102 break;
103 case XTENSA_SYSCALL_READ:
104 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "read");
105 fileio_info->param_1 = arg0; // fd
106 fileio_info->param_2 = arg1; // bufp
107 fileio_info->param_3 = arg2; // count
108 break;
109 case XTENSA_SYSCALL_WRITE:
110 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "write");
111 fileio_info->param_1 = arg0; // fd
112 fileio_info->param_2 = arg1; // bufp
113 fileio_info->param_3 = arg2; // count
114 break;
115 case XTENSA_SYSCALL_LSEEK:
116 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "lseek");
117 fileio_info->param_1 = arg0; // fd
118 fileio_info->param_2 = arg1; // offset
119 fileio_info->param_3 = arg2; // flags
120 break;
121 case XTENSA_SYSCALL_RENAME:
122 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "rename");
123 fileio_info->param_1 = arg0; // old pathp
124 fileio_info->param_2 = arg3; // old len
125 fileio_info->param_3 = arg1; // new pathp
126 fileio_info->param_4 = arg2; // new len
127 break;
128 case XTENSA_SYSCALL_UNLINK:
129 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unlink");
130 fileio_info->param_1 = arg0; // pathnamep
131 fileio_info->param_2 = arg1; // len
132 break;
133 case XTENSA_SYSCALL_STAT:
134 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "stat");
135 fileio_info->param_1 = arg0; // pathnamep
136 fileio_info->param_2 = arg2; // len
137 fileio_info->param_3 = arg1; // bufp
138 break;
139 case XTENSA_SYSCALL_FSTAT:
140 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "fstat");
141 fileio_info->param_1 = arg0; // fd
142 fileio_info->param_2 = arg1; // bufp
143 break;
144 case XTENSA_SYSCALL_GETTIMEOFDAY:
145 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "gettimeofday");
146 fileio_info->param_1 = arg0; // tvp
147 fileio_info->param_2 = arg1; // tzp
148 break;
149 case XTENSA_SYSCALL_ISATTY:
150 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "isatty");
151 fileio_info->param_1 = arg0; // fd
152 break;
153 case XTENSA_SYSCALL_SYSTEM:
154 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "system");
155 fileio_info->param_1 = arg0; // cmdp
156 fileio_info->param_2 = arg1; // len
157 break;
158 default:
159 snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unknown");
160 LOG_TARGET_DEBUG(target, "File-I/O: syscall unknown (%d), pc=0x%08X",
161 syscall, xtensa_reg_get(target, XT_REG_IDX_PC));
162 LOG_INFO("File-I/O: syscall unknown (%d), pc=0x%08X",
163 syscall, xtensa_reg_get(target, XT_REG_IDX_PC));
164 retval = ERROR_FAIL;
165 break;
166 }
167
168 return retval;
169 }
170
171 int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
172 {
173 struct xtensa *xtensa = target_to_xtensa(target);
174 if (!xtensa->proc_syscall)
175 return ERROR_FAIL;
176
177 LOG_TARGET_DEBUG(target, "File-I/O: syscall return code: 0x%x, errno: 0x%x , ctrl_c: %s",
178 retcode, fileio_errno, ctrl_c ? "true" : "false");
179
180 /* If interrupt was requested before FIO completion (ERRNO==4), halt and repeat
181 * syscall. Otherwise, set File-I/O Ax and underlying ARx registers, increment PC.
182 * NOTE: sporadic cases of ((ERRNO==4) && !ctrl_c) were observed; most have ctrl_c.
183 */
184 if (fileio_errno != 4) {
185 xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_RETVAL_REG, retcode);
186 xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_ERRNO_REG, fileio_errno);
187
188 xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC);
189 xtensa_reg_set(target, XT_REG_IDX_PC, pc + XTENSA_SYSCALL_SZ);
190 }
191
192 xtensa->proc_syscall = false;
193 xtensa->halt_request = true;
194 return ctrl_c ? ERROR_FAIL : ERROR_OK;
195 }

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)