Merge tag 'pull-loongarch-20241016' of https://gitlab.com/gaosong/qemu into staging
[qemu/armbru.git] / target / arm / hyp_gdbstub.c
blob1e861263b3d9f067e1355a321d68d0d9ff600154
1 /*
2 * ARM implementation of KVM and HVF hooks, 64 bit specific code
4 * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
5 * Copyright Alex Bennée 2014, Linaro
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
12 #include "qemu/osdep.h"
13 #include "cpu.h"
14 #include "internals.h"
15 #include "gdbstub/enums.h"
17 /* Maximum and current break/watch point counts */
18 int max_hw_bps, max_hw_wps;
19 GArray *hw_breakpoints, *hw_watchpoints;
21 /**
22 * insert_hw_breakpoint()
23 * @addr: address of breakpoint
25 * See ARM ARM D2.9.1 for details but here we are only going to create
26 * simple un-linked breakpoints (i.e. we don't chain breakpoints
27 * together to match address and context or vmid). The hardware is
28 * capable of fancier matching but that will require exposing that
29 * fanciness to GDB's interface
31 * DBGBCR<n>_EL1, Debug Breakpoint Control Registers
33 * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0
34 * +------+------+-------+-----+----+------+-----+------+-----+---+
35 * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
36 * +------+------+-------+-----+----+------+-----+------+-----+---+
38 * BT: Breakpoint type (0 = unlinked address match)
39 * LBN: Linked BP number (0 = unused)
40 * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
41 * BAS: Byte Address Select (RES1 for AArch64)
42 * E: Enable bit
44 * DBGBVR<n>_EL1, Debug Breakpoint Value Registers
46 * 63 53 52 49 48 2 1 0
47 * +------+-----------+----------+-----+
48 * | RESS | VA[52:49] | VA[48:2] | 0 0 |
49 * +------+-----------+----------+-----+
51 * Depending on the addressing mode bits the top bits of the register
52 * are a sign extension of the highest applicable VA bit. Some
53 * versions of GDB don't do it correctly so we ensure they are correct
54 * here so future PC comparisons will work properly.
57 int insert_hw_breakpoint(target_ulong addr)
59 HWBreakpoint brk = {
60 .bcr = 0x1, /* BCR E=1, enable */
61 .bvr = sextract64(addr, 0, 53)
64 if (cur_hw_bps >= max_hw_bps) {
65 return -ENOBUFS;
68 brk.bcr = deposit32(brk.bcr, 1, 2, 0x3); /* PMC = 11 */
69 brk.bcr = deposit32(brk.bcr, 5, 4, 0xf); /* BAS = RES1 */
71 g_array_append_val(hw_breakpoints, brk);
73 return 0;
76 /**
77 * delete_hw_breakpoint()
78 * @pc: address of breakpoint
80 * Delete a breakpoint and shuffle any above down
83 int delete_hw_breakpoint(target_ulong pc)
85 int i;
86 for (i = 0; i < hw_breakpoints->len; i++) {
87 HWBreakpoint *brk = get_hw_bp(i);
88 if (brk->bvr == pc) {
89 g_array_remove_index(hw_breakpoints, i);
90 return 0;
93 return -ENOENT;
96 /**
97 * insert_hw_watchpoint()
98 * @addr: address of watch point
99 * @len: size of area
100 * @type: type of watch point
102 * See ARM ARM D2.10. As with the breakpoints we can do some advanced
103 * stuff if we want to. The watch points can be linked with the break
104 * points above to make them context aware. However for simplicity
105 * currently we only deal with simple read/write watch points.
107 * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
109 * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0
110 * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
111 * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
112 * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
114 * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
115 * WT: 0 - unlinked, 1 - linked (not currently used)
116 * LBN: Linked BP number (not currently used)
117 * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11)
118 * BAS: Byte Address Select
119 * LSC: Load/Store control (01: load, 10: store, 11: both)
120 * E: Enable
122 * The bottom 2 bits of the value register are masked. Therefore to
123 * break on any sizes smaller than an unaligned word you need to set
124 * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
125 * need to ensure you mask the address as required and set BAS=0xff
128 int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type)
130 HWWatchpoint wp = {
131 .wcr = R_DBGWCR_E_MASK, /* E=1, enable */
132 .wvr = addr & (~0x7ULL),
133 .details = { .vaddr = addr, .len = len }
136 if (cur_hw_wps >= max_hw_wps) {
137 return -ENOBUFS;
141 * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state,
142 * valid whether EL3 is implemented or not
144 wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3);
146 switch (type) {
147 case GDB_WATCHPOINT_READ:
148 wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1);
149 wp.details.flags = BP_MEM_READ;
150 break;
151 case GDB_WATCHPOINT_WRITE:
152 wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2);
153 wp.details.flags = BP_MEM_WRITE;
154 break;
155 case GDB_WATCHPOINT_ACCESS:
156 wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3);
157 wp.details.flags = BP_MEM_ACCESS;
158 break;
159 default:
160 g_assert_not_reached();
162 if (len <= 8) {
163 /* we align the address and set the bits in BAS */
164 int off = addr & 0x7;
165 int bas = (1 << len) - 1;
167 wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas);
168 } else {
169 /* For ranges above 8 bytes we need to be a power of 2 */
170 if (is_power_of_2(len)) {
171 int bits = ctz64(len);
173 wp.wvr &= ~((1 << bits) - 1);
174 wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits);
175 wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff);
176 } else {
177 return -ENOBUFS;
181 g_array_append_val(hw_watchpoints, wp);
182 return 0;
185 bool check_watchpoint_in_range(int i, target_ulong addr)
187 HWWatchpoint *wp = get_hw_wp(i);
188 uint64_t addr_top, addr_bottom = wp->wvr;
189 int bas = extract32(wp->wcr, 5, 8);
190 int mask = extract32(wp->wcr, 24, 4);
192 if (mask) {
193 addr_top = addr_bottom + (1 << mask);
194 } else {
196 * BAS must be contiguous but can offset against the base
197 * address in DBGWVR
199 addr_bottom = addr_bottom + ctz32(bas);
200 addr_top = addr_bottom + clo32(bas);
203 if (addr >= addr_bottom && addr <= addr_top) {
204 return true;
207 return false;
211 * delete_hw_watchpoint()
212 * @addr: address of breakpoint
214 * Delete a breakpoint and shuffle any above down
217 int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type)
219 int i;
220 for (i = 0; i < cur_hw_wps; i++) {
221 if (check_watchpoint_in_range(i, addr)) {
222 g_array_remove_index(hw_watchpoints, i);
223 return 0;
226 return -ENOENT;
229 bool find_hw_breakpoint(CPUState *cpu, target_ulong pc)
231 int i;
233 for (i = 0; i < cur_hw_bps; i++) {
234 HWBreakpoint *bp = get_hw_bp(i);
235 if (bp->bvr == pc) {
236 return true;
239 return false;
242 CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
244 int i;
246 for (i = 0; i < cur_hw_wps; i++) {
247 if (check_watchpoint_in_range(i, addr)) {
248 return &get_hw_wp(i)->details;
251 return NULL;