]>
Commit | Line | Data |
---|---|---|
95799e36 BM |
1 | /* |
2 | * QEMU RISC-V Native Debug Support | |
3 | * | |
4 | * Copyright (c) 2022 Wind River Systems, Inc. | |
5 | * | |
6 | * Author: | |
7 | * Bin Meng <bin.meng@windriver.com> | |
8 | * | |
9 | * This provides the native debug support via the Trigger Module, as defined | |
10 | * in the RISC-V Debug Specification: | |
11 | * https://github.com/riscv/riscv-debug-spec/raw/master/riscv-debug-stable.pdf | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify it | |
14 | * under the terms and conditions of the GNU General Public License, | |
15 | * version 2 or later, as published by the Free Software Foundation. | |
16 | * | |
17 | * This program is distributed in the hope it will be useful, but WITHOUT | |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
20 | * more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License along with | |
23 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
24 | */ | |
25 | ||
26 | #include "qemu/osdep.h" | |
27 | #include "qemu/log.h" | |
28 | #include "qapi/error.h" | |
29 | #include "cpu.h" | |
30 | #include "trace.h" | |
31 | #include "exec/exec-all.h" | |
2c9d7471 | 32 | #include "exec/helper-proto.h" |
5a4ae64c | 33 | #include "sysemu/cpu-timers.h" |
95799e36 BM |
34 | |
35 | /* | |
36 | * The following M-mode trigger CSRs are implemented: | |
37 | * | |
38 | * - tselect | |
39 | * - tdata1 | |
40 | * - tdata2 | |
41 | * - tdata3 | |
31b9798d | 42 | * - tinfo |
95799e36 | 43 | * |
c472c142 | 44 | * The following triggers are initialized by default: |
95799e36 BM |
45 | * |
46 | * Index | Type | tdata mapping | Description | |
47 | * ------+------+------------------------+------------ | |
48 | * 0 | 2 | tdata1, tdata2 | Address / Data Match | |
49 | * 1 | 2 | tdata1, tdata2 | Address / Data Match | |
50 | */ | |
51 | ||
52 | /* tdata availability of a trigger */ | |
53 | typedef bool tdata_avail[TDATA_NUM]; | |
54 | ||
a42bd001 FC |
55 | static tdata_avail tdata_mapping[TRIGGER_TYPE_NUM] = { |
56 | [TRIGGER_TYPE_NO_EXIST] = { false, false, false }, | |
57 | [TRIGGER_TYPE_AD_MATCH] = { true, true, true }, | |
58 | [TRIGGER_TYPE_INST_CNT] = { true, false, true }, | |
59 | [TRIGGER_TYPE_INT] = { true, true, true }, | |
60 | [TRIGGER_TYPE_EXCP] = { true, true, true }, | |
61 | [TRIGGER_TYPE_AD_MATCH6] = { true, true, true }, | |
62 | [TRIGGER_TYPE_EXT_SRC] = { true, false, false }, | |
63 | [TRIGGER_TYPE_UNAVAIL] = { true, true, true } | |
95799e36 BM |
64 | }; |
65 | ||
66 | /* only breakpoint size 1/2/4/8 supported */ | |
67 | static int access_size[SIZE_NUM] = { | |
68 | [SIZE_ANY] = 0, | |
69 | [SIZE_1B] = 1, | |
70 | [SIZE_2B] = 2, | |
71 | [SIZE_4B] = 4, | |
72 | [SIZE_6B] = -1, | |
73 | [SIZE_8B] = 8, | |
74 | [6 ... 15] = -1, | |
75 | }; | |
76 | ||
a42bd001 FC |
77 | static inline target_ulong extract_trigger_type(CPURISCVState *env, |
78 | target_ulong tdata1) | |
79 | { | |
80 | switch (riscv_cpu_mxl(env)) { | |
81 | case MXL_RV32: | |
82 | return extract32(tdata1, 28, 4); | |
83 | case MXL_RV64: | |
84 | case MXL_RV128: | |
85 | return extract64(tdata1, 60, 4); | |
86 | default: | |
87 | g_assert_not_reached(); | |
88 | } | |
89 | } | |
90 | ||
91 | static inline target_ulong get_trigger_type(CPURISCVState *env, | |
92 | target_ulong trigger_index) | |
93 | { | |
9495c488 | 94 | return extract_trigger_type(env, env->tdata1[trigger_index]); |
a42bd001 FC |
95 | } |
96 | ||
d1c11141 FC |
97 | static trigger_action_t get_trigger_action(CPURISCVState *env, |
98 | target_ulong trigger_index) | |
99 | { | |
100 | target_ulong tdata1 = env->tdata1[trigger_index]; | |
101 | int trigger_type = get_trigger_type(env, trigger_index); | |
102 | trigger_action_t action = DBG_ACTION_NONE; | |
103 | ||
104 | switch (trigger_type) { | |
105 | case TRIGGER_TYPE_AD_MATCH: | |
106 | action = (tdata1 & TYPE2_ACTION) >> 12; | |
107 | break; | |
c472c142 FC |
108 | case TRIGGER_TYPE_AD_MATCH6: |
109 | action = (tdata1 & TYPE6_ACTION) >> 12; | |
110 | break; | |
d1c11141 FC |
111 | case TRIGGER_TYPE_INST_CNT: |
112 | case TRIGGER_TYPE_INT: | |
113 | case TRIGGER_TYPE_EXCP: | |
d1c11141 FC |
114 | case TRIGGER_TYPE_EXT_SRC: |
115 | qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", | |
116 | trigger_type); | |
117 | break; | |
118 | case TRIGGER_TYPE_NO_EXIST: | |
119 | case TRIGGER_TYPE_UNAVAIL: | |
120 | qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", | |
121 | trigger_type); | |
122 | break; | |
123 | default: | |
124 | g_assert_not_reached(); | |
125 | } | |
126 | ||
127 | return action; | |
128 | } | |
129 | ||
9d5a84db FC |
130 | static inline target_ulong build_tdata1(CPURISCVState *env, |
131 | trigger_type_t type, | |
132 | bool dmode, target_ulong data) | |
95799e36 BM |
133 | { |
134 | target_ulong tdata1; | |
135 | ||
136 | switch (riscv_cpu_mxl(env)) { | |
137 | case MXL_RV32: | |
9d5a84db FC |
138 | tdata1 = RV32_TYPE(type) | |
139 | (dmode ? RV32_DMODE : 0) | | |
140 | (data & RV32_DATA_MASK); | |
95799e36 BM |
141 | break; |
142 | case MXL_RV64: | |
d1d85412 | 143 | case MXL_RV128: |
9d5a84db FC |
144 | tdata1 = RV64_TYPE(type) | |
145 | (dmode ? RV64_DMODE : 0) | | |
146 | (data & RV64_DATA_MASK); | |
95799e36 BM |
147 | break; |
148 | default: | |
149 | g_assert_not_reached(); | |
150 | } | |
151 | ||
152 | return tdata1; | |
153 | } | |
154 | ||
155 | bool tdata_available(CPURISCVState *env, int tdata_index) | |
156 | { | |
a42bd001 FC |
157 | int trigger_type = get_trigger_type(env, env->trigger_cur); |
158 | ||
95799e36 BM |
159 | if (unlikely(tdata_index >= TDATA_NUM)) { |
160 | return false; | |
161 | } | |
162 | ||
a42bd001 | 163 | return tdata_mapping[trigger_type][tdata_index]; |
95799e36 BM |
164 | } |
165 | ||
166 | target_ulong tselect_csr_read(CPURISCVState *env) | |
167 | { | |
168 | return env->trigger_cur; | |
169 | } | |
170 | ||
171 | void tselect_csr_write(CPURISCVState *env, target_ulong val) | |
172 | { | |
6ea8d3fc FC |
173 | if (val < RV_MAX_TRIGGERS) { |
174 | env->trigger_cur = val; | |
175 | } | |
95799e36 BM |
176 | } |
177 | ||
178 | static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, | |
179 | trigger_type_t t) | |
180 | { | |
181 | uint32_t type, dmode; | |
182 | target_ulong tdata1; | |
183 | ||
184 | switch (riscv_cpu_mxl(env)) { | |
185 | case MXL_RV32: | |
186 | type = extract32(val, 28, 4); | |
187 | dmode = extract32(val, 27, 1); | |
188 | tdata1 = RV32_TYPE(t); | |
189 | break; | |
190 | case MXL_RV64: | |
d1d85412 | 191 | case MXL_RV128: |
95799e36 BM |
192 | type = extract64(val, 60, 4); |
193 | dmode = extract64(val, 59, 1); | |
194 | tdata1 = RV64_TYPE(t); | |
195 | break; | |
196 | default: | |
197 | g_assert_not_reached(); | |
198 | } | |
199 | ||
200 | if (type != t) { | |
201 | qemu_log_mask(LOG_GUEST_ERROR, | |
202 | "ignoring type write to tdata1 register\n"); | |
203 | } | |
a42bd001 | 204 | |
95799e36 BM |
205 | if (dmode != 0) { |
206 | qemu_log_mask(LOG_UNIMP, "debug mode is not supported\n"); | |
207 | } | |
208 | ||
209 | return tdata1; | |
210 | } | |
211 | ||
212 | static inline void warn_always_zero_bit(target_ulong val, target_ulong mask, | |
213 | const char *msg) | |
214 | { | |
215 | if (val & mask) { | |
216 | qemu_log_mask(LOG_UNIMP, "%s bit is always zero\n", msg); | |
217 | } | |
218 | } | |
219 | ||
d1c11141 FC |
220 | static void do_trigger_action(CPURISCVState *env, target_ulong trigger_index) |
221 | { | |
222 | trigger_action_t action = get_trigger_action(env, trigger_index); | |
223 | ||
224 | switch (action) { | |
225 | case DBG_ACTION_NONE: | |
226 | break; | |
227 | case DBG_ACTION_BP: | |
228 | riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); | |
229 | break; | |
230 | case DBG_ACTION_DBG_MODE: | |
231 | case DBG_ACTION_TRACE0: | |
232 | case DBG_ACTION_TRACE1: | |
233 | case DBG_ACTION_TRACE2: | |
234 | case DBG_ACTION_TRACE3: | |
235 | case DBG_ACTION_EXT_DBG0: | |
236 | case DBG_ACTION_EXT_DBG1: | |
237 | qemu_log_mask(LOG_UNIMP, "action: %d is not supported\n", action); | |
238 | break; | |
239 | default: | |
240 | g_assert_not_reached(); | |
241 | } | |
242 | } | |
243 | ||
9495c488 FC |
244 | /* type 2 trigger */ |
245 | ||
95799e36 BM |
246 | static uint32_t type2_breakpoint_size(CPURISCVState *env, target_ulong ctrl) |
247 | { | |
66997c42 | 248 | uint32_t sizelo, sizehi = 0; |
95799e36 BM |
249 | |
250 | if (riscv_cpu_mxl(env) == MXL_RV64) { | |
251 | sizehi = extract32(ctrl, 21, 2); | |
252 | } | |
253 | sizelo = extract32(ctrl, 16, 2); | |
66997c42 | 254 | return (sizehi << 2) | sizelo; |
95799e36 BM |
255 | } |
256 | ||
257 | static inline bool type2_breakpoint_enabled(target_ulong ctrl) | |
258 | { | |
259 | bool mode = !!(ctrl & (TYPE2_U | TYPE2_S | TYPE2_M)); | |
260 | bool rwx = !!(ctrl & (TYPE2_LOAD | TYPE2_STORE | TYPE2_EXEC)); | |
261 | ||
262 | return mode && rwx; | |
263 | } | |
264 | ||
265 | static target_ulong type2_mcontrol_validate(CPURISCVState *env, | |
266 | target_ulong ctrl) | |
267 | { | |
268 | target_ulong val; | |
269 | uint32_t size; | |
270 | ||
271 | /* validate the generic part first */ | |
272 | val = tdata1_validate(env, ctrl, TRIGGER_TYPE_AD_MATCH); | |
273 | ||
274 | /* validate unimplemented (always zero) bits */ | |
275 | warn_always_zero_bit(ctrl, TYPE2_MATCH, "match"); | |
276 | warn_always_zero_bit(ctrl, TYPE2_CHAIN, "chain"); | |
277 | warn_always_zero_bit(ctrl, TYPE2_ACTION, "action"); | |
278 | warn_always_zero_bit(ctrl, TYPE2_TIMING, "timing"); | |
279 | warn_always_zero_bit(ctrl, TYPE2_SELECT, "select"); | |
280 | warn_always_zero_bit(ctrl, TYPE2_HIT, "hit"); | |
281 | ||
282 | /* validate size encoding */ | |
283 | size = type2_breakpoint_size(env, ctrl); | |
284 | if (access_size[size] == -1) { | |
285 | qemu_log_mask(LOG_UNIMP, "access size %d is not supported, using SIZE_ANY\n", | |
286 | size); | |
287 | } else { | |
288 | val |= (ctrl & TYPE2_SIZELO); | |
289 | if (riscv_cpu_mxl(env) == MXL_RV64) { | |
290 | val |= (ctrl & TYPE2_SIZEHI); | |
291 | } | |
292 | } | |
293 | ||
294 | /* keep the mode and attribute bits */ | |
295 | val |= (ctrl & (TYPE2_U | TYPE2_S | TYPE2_M | | |
296 | TYPE2_LOAD | TYPE2_STORE | TYPE2_EXEC)); | |
297 | ||
298 | return val; | |
299 | } | |
300 | ||
301 | static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) | |
302 | { | |
9495c488 FC |
303 | target_ulong ctrl = env->tdata1[index]; |
304 | target_ulong addr = env->tdata2[index]; | |
95799e36 BM |
305 | bool enabled = type2_breakpoint_enabled(ctrl); |
306 | CPUState *cs = env_cpu(env); | |
307 | int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; | |
308 | uint32_t size; | |
309 | ||
310 | if (!enabled) { | |
311 | return; | |
312 | } | |
313 | ||
314 | if (ctrl & TYPE2_EXEC) { | |
9495c488 | 315 | cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); |
95799e36 BM |
316 | } |
317 | ||
318 | if (ctrl & TYPE2_LOAD) { | |
319 | flags |= BP_MEM_READ; | |
320 | } | |
321 | if (ctrl & TYPE2_STORE) { | |
322 | flags |= BP_MEM_WRITE; | |
323 | } | |
324 | ||
325 | if (flags & BP_MEM_ACCESS) { | |
326 | size = type2_breakpoint_size(env, ctrl); | |
327 | if (size != 0) { | |
328 | cpu_watchpoint_insert(cs, addr, size, flags, | |
9495c488 | 329 | &env->cpu_watchpoint[index]); |
95799e36 BM |
330 | } else { |
331 | cpu_watchpoint_insert(cs, addr, 8, flags, | |
9495c488 | 332 | &env->cpu_watchpoint[index]); |
95799e36 BM |
333 | } |
334 | } | |
335 | } | |
336 | ||
337 | static void type2_breakpoint_remove(CPURISCVState *env, target_ulong index) | |
338 | { | |
339 | CPUState *cs = env_cpu(env); | |
340 | ||
9495c488 FC |
341 | if (env->cpu_breakpoint[index]) { |
342 | cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); | |
343 | env->cpu_breakpoint[index] = NULL; | |
95799e36 BM |
344 | } |
345 | ||
9495c488 FC |
346 | if (env->cpu_watchpoint[index]) { |
347 | cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); | |
348 | env->cpu_watchpoint[index] = NULL; | |
95799e36 BM |
349 | } |
350 | } | |
351 | ||
a42bd001 | 352 | static void type2_reg_write(CPURISCVState *env, target_ulong index, |
95799e36 BM |
353 | int tdata_index, target_ulong val) |
354 | { | |
95799e36 BM |
355 | target_ulong new_val; |
356 | ||
357 | switch (tdata_index) { | |
358 | case TDATA1: | |
359 | new_val = type2_mcontrol_validate(env, val); | |
9495c488 FC |
360 | if (new_val != env->tdata1[index]) { |
361 | env->tdata1[index] = new_val; | |
95799e36 BM |
362 | type2_breakpoint_remove(env, index); |
363 | type2_breakpoint_insert(env, index); | |
364 | } | |
365 | break; | |
366 | case TDATA2: | |
9495c488 FC |
367 | if (val != env->tdata2[index]) { |
368 | env->tdata2[index] = val; | |
95799e36 BM |
369 | type2_breakpoint_remove(env, index); |
370 | type2_breakpoint_insert(env, index); | |
371 | } | |
372 | break; | |
9495c488 FC |
373 | case TDATA3: |
374 | qemu_log_mask(LOG_UNIMP, | |
375 | "tdata3 is not supported for type 2 trigger\n"); | |
376 | break; | |
95799e36 BM |
377 | default: |
378 | g_assert_not_reached(); | |
379 | } | |
380 | ||
381 | return; | |
382 | } | |
383 | ||
c472c142 FC |
384 | /* type 6 trigger */ |
385 | ||
386 | static inline bool type6_breakpoint_enabled(target_ulong ctrl) | |
387 | { | |
388 | bool mode = !!(ctrl & (TYPE6_VU | TYPE6_VS | TYPE6_U | TYPE6_S | TYPE6_M)); | |
389 | bool rwx = !!(ctrl & (TYPE6_LOAD | TYPE6_STORE | TYPE6_EXEC)); | |
390 | ||
391 | return mode && rwx; | |
392 | } | |
393 | ||
394 | static target_ulong type6_mcontrol6_validate(CPURISCVState *env, | |
395 | target_ulong ctrl) | |
396 | { | |
397 | target_ulong val; | |
398 | uint32_t size; | |
399 | ||
400 | /* validate the generic part first */ | |
401 | val = tdata1_validate(env, ctrl, TRIGGER_TYPE_AD_MATCH6); | |
402 | ||
403 | /* validate unimplemented (always zero) bits */ | |
404 | warn_always_zero_bit(ctrl, TYPE6_MATCH, "match"); | |
405 | warn_always_zero_bit(ctrl, TYPE6_CHAIN, "chain"); | |
406 | warn_always_zero_bit(ctrl, TYPE6_ACTION, "action"); | |
407 | warn_always_zero_bit(ctrl, TYPE6_TIMING, "timing"); | |
408 | warn_always_zero_bit(ctrl, TYPE6_SELECT, "select"); | |
409 | warn_always_zero_bit(ctrl, TYPE6_HIT, "hit"); | |
410 | ||
411 | /* validate size encoding */ | |
412 | size = extract32(ctrl, 16, 4); | |
413 | if (access_size[size] == -1) { | |
414 | qemu_log_mask(LOG_UNIMP, "access size %d is not supported, using SIZE_ANY\n", | |
415 | size); | |
416 | } else { | |
417 | val |= (ctrl & TYPE6_SIZE); | |
418 | } | |
419 | ||
420 | /* keep the mode and attribute bits */ | |
421 | val |= (ctrl & (TYPE6_VU | TYPE6_VS | TYPE6_U | TYPE6_S | TYPE6_M | | |
422 | TYPE6_LOAD | TYPE6_STORE | TYPE6_EXEC)); | |
423 | ||
424 | return val; | |
425 | } | |
426 | ||
427 | static void type6_breakpoint_insert(CPURISCVState *env, target_ulong index) | |
428 | { | |
429 | target_ulong ctrl = env->tdata1[index]; | |
430 | target_ulong addr = env->tdata2[index]; | |
431 | bool enabled = type6_breakpoint_enabled(ctrl); | |
432 | CPUState *cs = env_cpu(env); | |
433 | int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; | |
434 | uint32_t size; | |
435 | ||
436 | if (!enabled) { | |
437 | return; | |
438 | } | |
439 | ||
440 | if (ctrl & TYPE6_EXEC) { | |
441 | cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); | |
442 | } | |
443 | ||
444 | if (ctrl & TYPE6_LOAD) { | |
445 | flags |= BP_MEM_READ; | |
446 | } | |
447 | ||
448 | if (ctrl & TYPE6_STORE) { | |
449 | flags |= BP_MEM_WRITE; | |
450 | } | |
451 | ||
452 | if (flags & BP_MEM_ACCESS) { | |
453 | size = extract32(ctrl, 16, 4); | |
454 | if (size != 0) { | |
455 | cpu_watchpoint_insert(cs, addr, size, flags, | |
456 | &env->cpu_watchpoint[index]); | |
457 | } else { | |
458 | cpu_watchpoint_insert(cs, addr, 8, flags, | |
459 | &env->cpu_watchpoint[index]); | |
460 | } | |
461 | } | |
462 | } | |
463 | ||
464 | static void type6_breakpoint_remove(CPURISCVState *env, target_ulong index) | |
465 | { | |
466 | type2_breakpoint_remove(env, index); | |
467 | } | |
468 | ||
469 | static void type6_reg_write(CPURISCVState *env, target_ulong index, | |
470 | int tdata_index, target_ulong val) | |
471 | { | |
472 | target_ulong new_val; | |
473 | ||
474 | switch (tdata_index) { | |
475 | case TDATA1: | |
476 | new_val = type6_mcontrol6_validate(env, val); | |
477 | if (new_val != env->tdata1[index]) { | |
478 | env->tdata1[index] = new_val; | |
479 | type6_breakpoint_remove(env, index); | |
480 | type6_breakpoint_insert(env, index); | |
481 | } | |
482 | break; | |
483 | case TDATA2: | |
484 | if (val != env->tdata2[index]) { | |
485 | env->tdata2[index] = val; | |
486 | type6_breakpoint_remove(env, index); | |
487 | type6_breakpoint_insert(env, index); | |
488 | } | |
489 | break; | |
490 | case TDATA3: | |
491 | qemu_log_mask(LOG_UNIMP, | |
492 | "tdata3 is not supported for type 6 trigger\n"); | |
493 | break; | |
494 | default: | |
495 | g_assert_not_reached(); | |
496 | } | |
497 | ||
498 | return; | |
499 | } | |
500 | ||
2c9d7471 LZ |
501 | /* icount trigger type */ |
502 | static inline int | |
503 | itrigger_get_count(CPURISCVState *env, int index) | |
504 | { | |
505 | return get_field(env->tdata1[index], ITRIGGER_COUNT); | |
506 | } | |
507 | ||
508 | static inline void | |
509 | itrigger_set_count(CPURISCVState *env, int index, int value) | |
510 | { | |
511 | env->tdata1[index] = set_field(env->tdata1[index], | |
512 | ITRIGGER_COUNT, value); | |
513 | } | |
514 | ||
515 | static bool check_itrigger_priv(CPURISCVState *env, int index) | |
516 | { | |
517 | target_ulong tdata1 = env->tdata1[index]; | |
518 | if (riscv_cpu_virt_enabled(env)) { | |
519 | /* check VU/VS bit against current privilege level */ | |
520 | return (get_field(tdata1, ITRIGGER_VS) == env->priv) || | |
521 | (get_field(tdata1, ITRIGGER_VU) == env->priv); | |
522 | } else { | |
523 | /* check U/S/M bit against current privilege level */ | |
524 | return (get_field(tdata1, ITRIGGER_M) == env->priv) || | |
525 | (get_field(tdata1, ITRIGGER_S) == env->priv) || | |
526 | (get_field(tdata1, ITRIGGER_U) == env->priv); | |
527 | } | |
528 | } | |
529 | ||
530 | bool riscv_itrigger_enabled(CPURISCVState *env) | |
531 | { | |
532 | int count; | |
533 | for (int i = 0; i < RV_MAX_TRIGGERS; i++) { | |
534 | if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) { | |
535 | continue; | |
536 | } | |
537 | if (check_itrigger_priv(env, i)) { | |
538 | continue; | |
539 | } | |
540 | count = itrigger_get_count(env, i); | |
541 | if (!count) { | |
542 | continue; | |
543 | } | |
544 | return true; | |
545 | } | |
546 | ||
547 | return false; | |
548 | } | |
549 | ||
550 | void helper_itrigger_match(CPURISCVState *env) | |
551 | { | |
552 | int count; | |
553 | for (int i = 0; i < RV_MAX_TRIGGERS; i++) { | |
554 | if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) { | |
555 | continue; | |
556 | } | |
557 | if (check_itrigger_priv(env, i)) { | |
558 | continue; | |
559 | } | |
560 | count = itrigger_get_count(env, i); | |
561 | if (!count) { | |
562 | continue; | |
563 | } | |
564 | itrigger_set_count(env, i, count--); | |
565 | if (!count) { | |
577f0286 | 566 | env->itrigger_enabled = riscv_itrigger_enabled(env); |
2c9d7471 LZ |
567 | do_trigger_action(env, i); |
568 | } | |
569 | } | |
570 | } | |
571 | ||
5a4ae64c LZ |
572 | static void riscv_itrigger_update_count(CPURISCVState *env) |
573 | { | |
574 | int count, executed; | |
575 | /* | |
576 | * Record last icount, so that we can evaluate the executed instructions | |
577 | * since last priviledge mode change or timer expire. | |
578 | */ | |
579 | int64_t last_icount = env->last_icount, current_icount; | |
580 | current_icount = env->last_icount = icount_get_raw(); | |
581 | ||
582 | for (int i = 0; i < RV_MAX_TRIGGERS; i++) { | |
583 | if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) { | |
584 | continue; | |
585 | } | |
586 | count = itrigger_get_count(env, i); | |
587 | if (!count) { | |
588 | continue; | |
589 | } | |
590 | /* | |
591 | * Only when priviledge is changed or itrigger timer expires, | |
592 | * the count field in itrigger tdata1 register is updated. | |
593 | * And the count field in itrigger only contains remaining value. | |
594 | */ | |
595 | if (check_itrigger_priv(env, i)) { | |
596 | /* | |
597 | * If itrigger enabled in this priviledge mode, the number of | |
598 | * executed instructions since last priviledge change | |
599 | * should be reduced from current itrigger count. | |
600 | */ | |
601 | executed = current_icount - last_icount; | |
602 | itrigger_set_count(env, i, count - executed); | |
603 | if (count == executed) { | |
604 | do_trigger_action(env, i); | |
605 | } | |
606 | } else { | |
607 | /* | |
608 | * If itrigger is not enabled in this priviledge mode, | |
609 | * the number of executed instructions will be discard and | |
610 | * the count field in itrigger will not change. | |
611 | */ | |
612 | timer_mod(env->itrigger_timer[i], | |
613 | current_icount + count); | |
614 | } | |
615 | } | |
616 | } | |
617 | ||
618 | static void riscv_itrigger_timer_cb(void *opaque) | |
619 | { | |
620 | riscv_itrigger_update_count((CPURISCVState *)opaque); | |
621 | } | |
622 | ||
623 | void riscv_itrigger_update_priv(CPURISCVState *env) | |
624 | { | |
625 | riscv_itrigger_update_count(env); | |
626 | } | |
627 | ||
91809598 LZ |
628 | static target_ulong itrigger_validate(CPURISCVState *env, |
629 | target_ulong ctrl) | |
630 | { | |
631 | target_ulong val; | |
632 | ||
633 | /* validate the generic part first */ | |
634 | val = tdata1_validate(env, ctrl, TRIGGER_TYPE_INST_CNT); | |
635 | ||
636 | /* validate unimplemented (always zero) bits */ | |
637 | warn_always_zero_bit(ctrl, ITRIGGER_ACTION, "action"); | |
638 | warn_always_zero_bit(ctrl, ITRIGGER_HIT, "hit"); | |
639 | warn_always_zero_bit(ctrl, ITRIGGER_PENDING, "pending"); | |
640 | ||
641 | /* keep the mode and attribute bits */ | |
642 | val |= ctrl & (ITRIGGER_VU | ITRIGGER_VS | ITRIGGER_U | ITRIGGER_S | | |
643 | ITRIGGER_M | ITRIGGER_COUNT); | |
644 | ||
645 | return val; | |
646 | } | |
647 | ||
648 | static void itrigger_reg_write(CPURISCVState *env, target_ulong index, | |
649 | int tdata_index, target_ulong val) | |
650 | { | |
651 | target_ulong new_val; | |
652 | ||
653 | switch (tdata_index) { | |
654 | case TDATA1: | |
655 | /* set timer for icount */ | |
656 | new_val = itrigger_validate(env, val); | |
657 | if (new_val != env->tdata1[index]) { | |
658 | env->tdata1[index] = new_val; | |
659 | if (icount_enabled()) { | |
660 | env->last_icount = icount_get_raw(); | |
661 | /* set the count to timer */ | |
662 | timer_mod(env->itrigger_timer[index], | |
663 | env->last_icount + itrigger_get_count(env, index)); | |
577f0286 LZ |
664 | } else { |
665 | env->itrigger_enabled = riscv_itrigger_enabled(env); | |
91809598 LZ |
666 | } |
667 | } | |
668 | break; | |
669 | case TDATA2: | |
670 | qemu_log_mask(LOG_UNIMP, | |
671 | "tdata2 is not supported for icount trigger\n"); | |
672 | break; | |
673 | case TDATA3: | |
674 | qemu_log_mask(LOG_UNIMP, | |
675 | "tdata3 is not supported for icount trigger\n"); | |
676 | break; | |
677 | default: | |
678 | g_assert_not_reached(); | |
679 | } | |
680 | ||
681 | return; | |
682 | } | |
683 | ||
684 | static int itrigger_get_adjust_count(CPURISCVState *env) | |
685 | { | |
686 | int count = itrigger_get_count(env, env->trigger_cur), executed; | |
687 | if ((count != 0) && check_itrigger_priv(env, env->trigger_cur)) { | |
688 | executed = icount_get_raw() - env->last_icount; | |
689 | count += executed; | |
690 | } | |
691 | return count; | |
692 | } | |
693 | ||
95799e36 BM |
694 | target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index) |
695 | { | |
91809598 | 696 | int trigger_type; |
9495c488 FC |
697 | switch (tdata_index) { |
698 | case TDATA1: | |
91809598 LZ |
699 | trigger_type = extract_trigger_type(env, env->tdata1[env->trigger_cur]); |
700 | if ((trigger_type == TRIGGER_TYPE_INST_CNT) && icount_enabled()) { | |
701 | return deposit64(env->tdata1[env->trigger_cur], 10, 14, | |
702 | itrigger_get_adjust_count(env)); | |
703 | } | |
9495c488 FC |
704 | return env->tdata1[env->trigger_cur]; |
705 | case TDATA2: | |
706 | return env->tdata2[env->trigger_cur]; | |
707 | case TDATA3: | |
708 | return env->tdata3[env->trigger_cur]; | |
a42bd001 FC |
709 | default: |
710 | g_assert_not_reached(); | |
711 | } | |
95799e36 BM |
712 | } |
713 | ||
714 | void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val) | |
715 | { | |
a42bd001 | 716 | int trigger_type; |
95799e36 | 717 | |
a42bd001 FC |
718 | if (tdata_index == TDATA1) { |
719 | trigger_type = extract_trigger_type(env, val); | |
720 | } else { | |
721 | trigger_type = get_trigger_type(env, env->trigger_cur); | |
722 | } | |
723 | ||
724 | switch (trigger_type) { | |
725 | case TRIGGER_TYPE_AD_MATCH: | |
726 | type2_reg_write(env, env->trigger_cur, tdata_index, val); | |
727 | break; | |
c472c142 FC |
728 | case TRIGGER_TYPE_AD_MATCH6: |
729 | type6_reg_write(env, env->trigger_cur, tdata_index, val); | |
730 | break; | |
a42bd001 | 731 | case TRIGGER_TYPE_INST_CNT: |
91809598 LZ |
732 | itrigger_reg_write(env, env->trigger_cur, tdata_index, val); |
733 | break; | |
a42bd001 FC |
734 | case TRIGGER_TYPE_INT: |
735 | case TRIGGER_TYPE_EXCP: | |
a42bd001 FC |
736 | case TRIGGER_TYPE_EXT_SRC: |
737 | qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", | |
738 | trigger_type); | |
739 | break; | |
740 | case TRIGGER_TYPE_NO_EXIST: | |
741 | case TRIGGER_TYPE_UNAVAIL: | |
742 | qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", | |
743 | trigger_type); | |
744 | break; | |
745 | default: | |
746 | g_assert_not_reached(); | |
747 | } | |
95799e36 | 748 | } |
b5f6379d | 749 | |
31b9798d FC |
750 | target_ulong tinfo_csr_read(CPURISCVState *env) |
751 | { | |
752 | /* assume all triggers support the same types of triggers */ | |
c472c142 FC |
753 | return BIT(TRIGGER_TYPE_AD_MATCH) | |
754 | BIT(TRIGGER_TYPE_AD_MATCH6); | |
31b9798d FC |
755 | } |
756 | ||
b5f6379d BM |
757 | void riscv_cpu_debug_excp_handler(CPUState *cs) |
758 | { | |
759 | RISCVCPU *cpu = RISCV_CPU(cs); | |
760 | CPURISCVState *env = &cpu->env; | |
761 | ||
762 | if (cs->watchpoint_hit) { | |
763 | if (cs->watchpoint_hit->flags & BP_CPU) { | |
d1c11141 | 764 | do_trigger_action(env, DBG_ACTION_BP); |
b5f6379d BM |
765 | } |
766 | } else { | |
767 | if (cpu_breakpoint_test(cs, env->pc, BP_CPU)) { | |
d1c11141 | 768 | do_trigger_action(env, DBG_ACTION_BP); |
b5f6379d BM |
769 | } |
770 | } | |
771 | } | |
772 | ||
773 | bool riscv_cpu_debug_check_breakpoint(CPUState *cs) | |
774 | { | |
775 | RISCVCPU *cpu = RISCV_CPU(cs); | |
776 | CPURISCVState *env = &cpu->env; | |
777 | CPUBreakpoint *bp; | |
778 | target_ulong ctrl; | |
779 | target_ulong pc; | |
a42bd001 | 780 | int trigger_type; |
b5f6379d BM |
781 | int i; |
782 | ||
783 | QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { | |
a42bd001 FC |
784 | for (i = 0; i < RV_MAX_TRIGGERS; i++) { |
785 | trigger_type = get_trigger_type(env, i); | |
786 | ||
787 | switch (trigger_type) { | |
788 | case TRIGGER_TYPE_AD_MATCH: | |
c32461d8 FC |
789 | /* type 2 trigger cannot be fired in VU/VS mode */ |
790 | if (riscv_cpu_virt_enabled(env)) { | |
791 | return false; | |
792 | } | |
793 | ||
9495c488 FC |
794 | ctrl = env->tdata1[i]; |
795 | pc = env->tdata2[i]; | |
a42bd001 FC |
796 | |
797 | if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) { | |
798 | /* check U/S/M bit against current privilege level */ | |
799 | if ((ctrl >> 3) & BIT(env->priv)) { | |
800 | return true; | |
801 | } | |
b5f6379d | 802 | } |
a42bd001 | 803 | break; |
c472c142 FC |
804 | case TRIGGER_TYPE_AD_MATCH6: |
805 | ctrl = env->tdata1[i]; | |
806 | pc = env->tdata2[i]; | |
807 | ||
808 | if ((ctrl & TYPE6_EXEC) && (bp->pc == pc)) { | |
809 | if (riscv_cpu_virt_enabled(env)) { | |
810 | /* check VU/VS bit against current privilege level */ | |
811 | if ((ctrl >> 23) & BIT(env->priv)) { | |
812 | return true; | |
813 | } | |
814 | } else { | |
815 | /* check U/S/M bit against current privilege level */ | |
816 | if ((ctrl >> 3) & BIT(env->priv)) { | |
817 | return true; | |
818 | } | |
819 | } | |
820 | } | |
821 | break; | |
a42bd001 FC |
822 | default: |
823 | /* other trigger types are not supported or irrelevant */ | |
824 | break; | |
b5f6379d BM |
825 | } |
826 | } | |
827 | } | |
828 | ||
829 | return false; | |
830 | } | |
831 | ||
832 | bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) | |
833 | { | |
834 | RISCVCPU *cpu = RISCV_CPU(cs); | |
835 | CPURISCVState *env = &cpu->env; | |
836 | target_ulong ctrl; | |
837 | target_ulong addr; | |
a42bd001 | 838 | int trigger_type; |
b5f6379d BM |
839 | int flags; |
840 | int i; | |
841 | ||
a42bd001 FC |
842 | for (i = 0; i < RV_MAX_TRIGGERS; i++) { |
843 | trigger_type = get_trigger_type(env, i); | |
b5f6379d | 844 | |
a42bd001 FC |
845 | switch (trigger_type) { |
846 | case TRIGGER_TYPE_AD_MATCH: | |
c32461d8 FC |
847 | /* type 2 trigger cannot be fired in VU/VS mode */ |
848 | if (riscv_cpu_virt_enabled(env)) { | |
849 | return false; | |
850 | } | |
851 | ||
9495c488 FC |
852 | ctrl = env->tdata1[i]; |
853 | addr = env->tdata2[i]; | |
a42bd001 | 854 | flags = 0; |
b5f6379d | 855 | |
a42bd001 FC |
856 | if (ctrl & TYPE2_LOAD) { |
857 | flags |= BP_MEM_READ; | |
858 | } | |
859 | if (ctrl & TYPE2_STORE) { | |
860 | flags |= BP_MEM_WRITE; | |
861 | } | |
862 | ||
863 | if ((wp->flags & flags) && (wp->vaddr == addr)) { | |
864 | /* check U/S/M bit against current privilege level */ | |
865 | if ((ctrl >> 3) & BIT(env->priv)) { | |
866 | return true; | |
867 | } | |
b5f6379d | 868 | } |
a42bd001 | 869 | break; |
c472c142 FC |
870 | case TRIGGER_TYPE_AD_MATCH6: |
871 | ctrl = env->tdata1[i]; | |
872 | addr = env->tdata2[i]; | |
873 | flags = 0; | |
874 | ||
875 | if (ctrl & TYPE6_LOAD) { | |
876 | flags |= BP_MEM_READ; | |
877 | } | |
878 | if (ctrl & TYPE6_STORE) { | |
879 | flags |= BP_MEM_WRITE; | |
880 | } | |
881 | ||
882 | if ((wp->flags & flags) && (wp->vaddr == addr)) { | |
883 | if (riscv_cpu_virt_enabled(env)) { | |
884 | /* check VU/VS bit against current privilege level */ | |
885 | if ((ctrl >> 23) & BIT(env->priv)) { | |
886 | return true; | |
887 | } | |
888 | } else { | |
889 | /* check U/S/M bit against current privilege level */ | |
890 | if ((ctrl >> 3) & BIT(env->priv)) { | |
891 | return true; | |
892 | } | |
893 | } | |
894 | } | |
895 | break; | |
a42bd001 FC |
896 | default: |
897 | /* other trigger types are not supported */ | |
898 | break; | |
b5f6379d BM |
899 | } |
900 | } | |
901 | ||
902 | return false; | |
903 | } | |
b6092544 BM |
904 | |
905 | void riscv_trigger_init(CPURISCVState *env) | |
906 | { | |
9d5a84db | 907 | target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0); |
b6092544 BM |
908 | int i; |
909 | ||
a42bd001 FC |
910 | /* init to type 2 triggers */ |
911 | for (i = 0; i < RV_MAX_TRIGGERS; i++) { | |
b6092544 BM |
912 | /* |
913 | * type = TRIGGER_TYPE_AD_MATCH | |
914 | * dmode = 0 (both debug and M-mode can write tdata) | |
915 | * maskmax = 0 (unimplemented, always 0) | |
916 | * sizehi = 0 (match against any size, RV64 only) | |
917 | * hit = 0 (unimplemented, always 0) | |
918 | * select = 0 (always 0, perform match on address) | |
919 | * timing = 0 (always 0, trigger before instruction) | |
920 | * sizelo = 0 (match against any size) | |
921 | * action = 0 (always 0, raise a breakpoint exception) | |
922 | * chain = 0 (unimplemented, always 0) | |
923 | * match = 0 (always 0, when any compare value equals tdata2) | |
924 | */ | |
9495c488 FC |
925 | env->tdata1[i] = tdata1; |
926 | env->tdata2[i] = 0; | |
927 | env->tdata3[i] = 0; | |
928 | env->cpu_breakpoint[i] = NULL; | |
929 | env->cpu_watchpoint[i] = NULL; | |
5a4ae64c LZ |
930 | env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL, |
931 | riscv_itrigger_timer_cb, env); | |
b6092544 BM |
932 | } |
933 | } |