gdb_server: support File-I/O Remote Protocol Extension
[openocd.git] / src / target / nds32_v3m.c
1 /***************************************************************************
2 * Copyright (C) 2013 Andes Technology *
3 * Hsiangkai Wang <hkwang@andestech.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "breakpoints.h"
26 #include "nds32_cmd.h"
27 #include "nds32_aice.h"
28 #include "nds32_v3m.h"
29 #include "nds32_v3_common.h"
30
31 static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
32 {
33 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
34 struct aice_port_s *aice = target_to_aice(target);
35 struct breakpoint *bp;
36 unsigned brp_num = nds32_v3m->n_hbr - 1;
37
38 for (bp = target->breakpoints; bp; bp = bp->next) {
39 if (bp->type == BKPT_SOFT) {
40 /* already set at nds32_v3m_add_breakpoint() */
41 continue;
42 } else if (bp->type == BKPT_HARD) {
43 /* set address */
44 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
45 /* set mask */
46 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
47
48 if (nds32_v3m->nds32.memory.address_translation)
49 /* enable breakpoint (virtual address) */
50 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
51 else
52 /* enable breakpoint (physical address) */
53 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
54
55 LOG_DEBUG("Add hardware BP %d at %08" PRIx32, brp_num,
56 bp->address);
57
58 brp_num--;
59 } else {
60 return ERROR_FAIL;
61 }
62 }
63
64 return ERROR_OK;
65 }
66
67 static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
68 {
69 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
70 struct aice_port_s *aice = target_to_aice(target);
71 struct breakpoint *bp;
72 unsigned brp_num = nds32_v3m->n_hbr - 1;
73
74 for (bp = target->breakpoints; bp; bp = bp->next) {
75 if (bp->type == BKPT_SOFT)
76 continue;
77 else if (bp->type == BKPT_HARD)
78 /* disable breakpoint */
79 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
80 else
81 return ERROR_FAIL;
82
83 LOG_DEBUG("Remove hardware BP %d at %08" PRIx32, brp_num,
84 bp->address);
85
86 brp_num--;
87 }
88
89 return ERROR_OK;
90 }
91
92 static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
93 {
94 struct aice_port_s *aice = target_to_aice(target);
95 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
96 struct watchpoint *wp;
97 int32_t wp_num = 0;
98 uint32_t wp_config = 0;
99 bool ld_stop, st_stop;
100
101 if (nds32_v3m->nds32.global_stop)
102 ld_stop = st_stop = false;
103
104 for (wp = target->watchpoints; wp; wp = wp->next) {
105
106 if (wp_num < nds32_v3m->used_n_wp) {
107 wp->mask = wp->length - 1;
108 if ((wp->address % wp->length) != 0)
109 wp->mask = (wp->mask << 1) + 1;
110
111 if (wp->rw == WPT_READ)
112 wp_config = 0x3;
113 else if (wp->rw == WPT_WRITE)
114 wp_config = 0x5;
115 else if (wp->rw == WPT_ACCESS)
116 wp_config = 0x7;
117
118 /* set/unset physical address bit of BPCn according to PSW.DT */
119 if (nds32_v3m->nds32.memory.address_translation == false)
120 wp_config |= 0x8;
121
122 /* set address */
123 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
124 wp->address - (wp->address % wp->length));
125 /* set mask */
126 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
127 /* enable watchpoint */
128 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
129
130 LOG_DEBUG("Add hardware wathcpoint %d at %08" PRIx32
131 " mask %08" PRIx32, wp_num,
132 wp->address, wp->mask);
133
134 wp_num++;
135 } else if (nds32_v3m->nds32.global_stop) {
136 if (wp->rw == WPT_READ)
137 ld_stop = true;
138 else if (wp->rw == WPT_WRITE)
139 st_stop = true;
140 else if (wp->rw == WPT_ACCESS)
141 ld_stop = st_stop = true;
142 }
143 }
144
145 if (nds32_v3m->nds32.global_stop) {
146 uint32_t edm_ctl;
147 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
148 if (ld_stop)
149 edm_ctl |= 0x10;
150 if (st_stop)
151 edm_ctl |= 0x20;
152 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
153 }
154
155 return ERROR_OK;
156 }
157
158 static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
159 {
160 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
161 struct aice_port_s *aice = target_to_aice(target);
162 struct watchpoint *wp;
163 int32_t wp_num = 0;
164 bool clean_global_stop = false;
165
166 for (wp = target->watchpoints; wp; wp = wp->next) {
167
168 if (wp_num < nds32_v3m->used_n_wp) {
169 /* disable watchpoint */
170 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
171
172 LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32
173 " mask %08" PRIx32, wp_num,
174 wp->address, wp->mask);
175 wp_num++;
176 } else if (nds32_v3m->nds32.global_stop) {
177 clean_global_stop = true;
178 }
179 }
180
181 if (clean_global_stop) {
182 uint32_t edm_ctl;
183 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
184 edm_ctl = edm_ctl & (~0x30);
185 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
186 }
187
188 return ERROR_OK;
189 }
190
191 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
192 {
193 uint32_t val_ir0;
194 uint32_t value;
195
196 /* Save interrupt level */
197 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
198 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
199
200 if (nds32_reach_max_interrupt_level(nds32))
201 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %d. -->",
202 nds32->current_interrupt_level);
203
204 /* backup $ir6 to avoid suppressed exception overwrite */
205 nds32_get_mapped_reg(nds32, IR6, &value);
206
207 return ERROR_OK;
208 }
209
210 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
211 {
212 uint32_t value;
213
214 /* get backup value from cache */
215 /* then set back to make the register dirty */
216 nds32_get_mapped_reg(nds32, IR0, &value);
217 nds32_set_mapped_reg(nds32, IR0, value);
218
219 nds32_get_mapped_reg(nds32, IR6, &value);
220 nds32_set_mapped_reg(nds32, IR6, value);
221
222 return ERROR_OK;
223 }
224
225 static int nds32_v3m_deassert_reset(struct target *target)
226 {
227 int retval;
228
229 CHECK_RETVAL(nds32_poll(target));
230
231 if (target->state != TARGET_HALTED) {
232 /* reset only */
233 LOG_WARNING("%s: ran after reset and before halt ...",
234 target_name(target));
235 retval = target_halt(target);
236 if (retval != ERROR_OK)
237 return retval;
238 /* call target_poll() to avoid "Halt timed out" */
239 CHECK_RETVAL(target_poll(target));
240 } else {
241 jtag_poll_set_enabled(false);
242 }
243
244 return ERROR_OK;
245 }
246
247 static int nds32_v3m_add_breakpoint(struct target *target,
248 struct breakpoint *breakpoint)
249 {
250 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
251 struct nds32 *nds32 = &(nds32_v3m->nds32);
252 int result;
253
254 if (breakpoint->type == BKPT_HARD) {
255 /* check hardware resource */
256 if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
257 LOG_WARNING("<-- TARGET WARNING! Insert too many "
258 "hardware breakpoints/watchpoints! "
259 "The limit of combined hardware "
260 "breakpoints/watchpoints is %d. -->",
261 nds32_v3m->n_hbr);
262 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
263 "hardware breakpoint: %d, hardware "
264 "watchpoints: %d. -->",
265 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
266 nds32_v3m->used_n_wp);
267 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
268 }
269
270 /* update next place to put hardware breakpoint */
271 nds32_v3m->next_hbr_index--;
272
273 /* hardware breakpoint insertion occurs before 'continue' actually */
274 return ERROR_OK;
275 } else if (breakpoint->type == BKPT_SOFT) {
276 result = nds32_add_software_breakpoint(target, breakpoint);
277 if (ERROR_OK != result) {
278 /* auto convert to hardware breakpoint if failed */
279 if (nds32->auto_convert_hw_bp) {
280 /* convert to hardware breakpoint */
281 breakpoint->type = BKPT_HARD;
282
283 return nds32_v3m_add_breakpoint(target, breakpoint);
284 }
285 }
286
287 return result;
288 } else /* unrecognized breakpoint type */
289 return ERROR_FAIL;
290
291 return ERROR_OK;
292 }
293
294 static int nds32_v3m_remove_breakpoint(struct target *target,
295 struct breakpoint *breakpoint)
296 {
297 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
298
299 if (breakpoint->type == BKPT_HARD) {
300 if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
301 return ERROR_FAIL;
302
303 /* update next place to put hardware breakpoint */
304 nds32_v3m->next_hbr_index++;
305
306 /* hardware breakpoint removal occurs after 'halted' actually */
307 return ERROR_OK;
308 } else if (breakpoint->type == BKPT_SOFT) {
309 return nds32_remove_software_breakpoint(target, breakpoint);
310 } else /* unrecognized breakpoint type */
311 return ERROR_FAIL;
312
313 return ERROR_OK;
314 }
315
316 static int nds32_v3m_add_watchpoint(struct target *target,
317 struct watchpoint *watchpoint)
318 {
319 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
320
321 /* check hardware resource */
322 if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
323 /* No hardware resource */
324 if (nds32_v3m->nds32.global_stop) {
325 LOG_WARNING("<-- TARGET WARNING! The number of "
326 "watchpoints exceeds the hardware "
327 "resources. Stop at every load/store "
328 "instruction to check for watchpoint matches. -->");
329 return ERROR_OK;
330 }
331
332 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
333 "watchpoints! The limit of hardware watchpoints "
334 "is %d. -->", nds32_v3m->n_hwp);
335 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
336 "hardware watchpoint: %d. -->",
337 nds32_v3m->used_n_wp);
338 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
339 }
340
341 if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
342 /* No hardware resource */
343 if (nds32_v3m->nds32.global_stop) {
344 LOG_WARNING("<-- TARGET WARNING! The number of "
345 "watchpoints exceeds the hardware "
346 "resources. Stop at every load/store "
347 "instruction to check for watchpoint matches. -->");
348 return ERROR_OK;
349 }
350
351 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
352 "breakpoints/watchpoints! The limit of combined "
353 "hardware breakpoints/watchpoints is %d. -->",
354 nds32_v3m->n_hbr);
355 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
356 "hardware breakpoint: %d, hardware "
357 "watchpoints: %d. -->",
358 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
359 nds32_v3m->used_n_wp);
360 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
361 }
362
363 /* update next place to put hardware watchpoint */
364 nds32_v3m->next_hwp_index++;
365 nds32_v3m->used_n_wp++;
366
367 return ERROR_OK;
368 }
369
370 static int nds32_v3m_remove_watchpoint(struct target *target,
371 struct watchpoint *watchpoint)
372 {
373 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
374
375 if (nds32_v3m->next_hwp_index <= 0) {
376 if (nds32_v3m->nds32.global_stop)
377 return ERROR_OK;
378
379 return ERROR_FAIL;
380 }
381
382 /* update next place to put hardware watchpoint */
383 nds32_v3m->next_hwp_index--;
384 nds32_v3m->used_n_wp--;
385
386 return ERROR_OK;
387 }
388
389 struct nds32_v3_common_callback nds32_v3m_common_callback = {
390 .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
391 .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
392 .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
393 .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
394 .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
395 .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
396 };
397
398 static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
399 {
400 struct nds32_v3m_common *nds32_v3m;
401
402 nds32_v3m = calloc(1, sizeof(*nds32_v3m));
403 if (!nds32_v3m)
404 return ERROR_FAIL;
405
406 nds32_v3_common_register_callback(&nds32_v3m_common_callback);
407 nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
408
409 return ERROR_OK;
410 }
411
412 /* talk to the target and set things up */
413 static int nds32_v3m_examine(struct target *target)
414 {
415 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
416 struct nds32 *nds32 = &(nds32_v3m->nds32);
417 struct aice_port_s *aice = target_to_aice(target);
418
419 if (!target_was_examined(target)) {
420 CHECK_RETVAL(nds32_edm_config(nds32));
421
422 if (nds32->reset_halt_as_examine)
423 CHECK_RETVAL(nds32_reset_halt(nds32));
424 }
425
426 uint32_t edm_cfg;
427 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
428
429 /* get the number of hardware breakpoints */
430 nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
431 nds32_v3m->used_n_wp = 0;
432
433 /* get the number of hardware watchpoints */
434 /* If the WP field is hardwired to zero, it means this is a
435 * simple breakpoint. Otherwise, if the WP field is writable
436 * then it means this is a regular watchpoints. */
437 nds32_v3m->n_hwp = 0;
438 for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
439 /** check the hardware breakpoint is simple or not */
440 uint32_t tmp_value;
441 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
442 aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
443
444 if (tmp_value)
445 nds32_v3m->n_hwp++;
446 }
447 /* hardware breakpoint is inserted from high index to low index */
448 nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
449 /* hardware watchpoint is inserted from low index to high index */
450 nds32_v3m->next_hwp_index = 0;
451
452 LOG_INFO("%s: total hardware breakpoint %d (simple breakpoint %d)",
453 target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
454 LOG_INFO("%s: total hardware watchpoint %d", target_name(target), nds32_v3m->n_hwp);
455
456 nds32->target->state = TARGET_RUNNING;
457 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
458
459 target_set_examined(target);
460
461 return ERROR_OK;
462 }
463
464 /** Holds methods for NDS32 V3m targets. */
465 struct target_type nds32_v3m_target = {
466 .name = "nds32_v3m",
467
468 .poll = nds32_poll,
469 .arch_state = nds32_arch_state,
470
471 .target_request_data = nds32_v3_target_request_data,
472
473 .halt = nds32_halt,
474 .resume = nds32_resume,
475 .step = nds32_step,
476
477 .assert_reset = nds32_assert_reset,
478 .deassert_reset = nds32_v3m_deassert_reset,
479 .soft_reset_halt = nds32_v3_soft_reset_halt,
480
481 /* register access */
482 .get_gdb_reg_list = nds32_get_gdb_reg_list,
483
484 /* memory access */
485 .read_buffer = nds32_v3_read_buffer,
486 .write_buffer = nds32_v3_write_buffer,
487 .read_memory = nds32_v3_read_memory,
488 .write_memory = nds32_v3_write_memory,
489
490 .checksum_memory = nds32_v3_checksum_memory,
491
492 /* breakpoint/watchpoint */
493 .add_breakpoint = nds32_v3m_add_breakpoint,
494 .remove_breakpoint = nds32_v3m_remove_breakpoint,
495 .add_watchpoint = nds32_v3m_add_watchpoint,
496 .remove_watchpoint = nds32_v3m_remove_watchpoint,
497 .hit_watchpoint = nds32_v3_hit_watchpoint,
498
499 /* MMU */
500 .mmu = nds32_mmu,
501 .virt2phys = nds32_virtual_to_physical,
502 .read_phys_memory = nds32_read_phys_memory,
503 .write_phys_memory = nds32_write_phys_memory,
504
505 .run_algorithm = nds32_v3_run_algorithm,
506
507 .commands = nds32_command_handlers,
508 .target_create = nds32_v3m_target_create,
509 .init_target = nds32_v3_init_target,
510 .examine = nds32_v3m_examine,
511
512 .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
513 .gdb_fileio_end = nds32_gdb_fileio_end,
514 };

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)