master
c 386 lines 10.5 KB
Raw
1 /*
2 * QEMU monitor for RISC-V
3 *
4 * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
5 *
6 * RISC-V specific monitor commands implementation
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2 or later, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "qemu/osdep.h"
22 #include "qemu/ctype.h"
23 #include "qemu/qemu-print.h"
24 #include "cpu.h"
25 #include "target/riscv/tcg/csr.h"
26 #include "cpu_bits.h"
27 #include "monitor/monitor.h"
28 #include "monitor/hmp.h"
29 #include "system/memory.h"
30 #include "internals.h"
31
32 #ifdef TARGET_RISCV64
33 #define PTE_HEADER_FIELDS "vaddr paddr "\
34 "size attr\n"
35 #define PTE_HEADER_DELIMITER "---------------- ---------------- "\
36 "---------------- -------\n"
37 #else
38 #define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
39 #define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
40 #endif
41
42 #ifdef CONFIG_HMP
43
44 /* Perform linear address sign extension */
45 static target_ulong addr_canonical(int va_bits, target_ulong addr)
46 {
47 #ifdef TARGET_RISCV64
48 if (addr & (1UL << (va_bits - 1))) {
49 addr |= (hwaddr)-(1L << va_bits);
50 }
51 #endif
52
53 return addr;
54 }
55
56 static void print_pte_header(MonitorHMP *hmp)
57 {
58 monitor_hmp_printf(hmp, PTE_HEADER_FIELDS);
59 monitor_hmp_printf(hmp, PTE_HEADER_DELIMITER);
60 }
61
62 static void print_pte(MonitorHMP *hmp, int va_bits, target_ulong vaddr,
63 hwaddr paddr, target_ulong size, int attr)
64 {
65 /* sanity check on vaddr */
66 if (vaddr >= (1UL << va_bits)) {
67 return;
68 }
69
70 if (!size) {
71 return;
72 }
73
74 monitor_hmp_printf(hmp, TARGET_FMT_lx " " HWADDR_FMT_plx " " TARGET_FMT_lx
75 " %c%c%c%c%c%c%c\n",
76 addr_canonical(va_bits, vaddr),
77 paddr, size,
78 attr & PTE_R ? 'r' : '-',
79 attr & PTE_W ? 'w' : '-',
80 attr & PTE_X ? 'x' : '-',
81 attr & PTE_U ? 'u' : '-',
82 attr & PTE_G ? 'g' : '-',
83 attr & PTE_A ? 'a' : '-',
84 attr & PTE_D ? 'd' : '-');
85 }
86
87 static void walk_pte(MonitorHMP *hmp, AddressSpace *as,
88 hwaddr base, target_ulong start,
89 int level, int ptidxbits, int ptesize, int va_bits,
90 target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr,
91 target_ulong *last_size, int *last_attr)
92 {
93 const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
94 hwaddr pte_addr;
95 hwaddr paddr;
96 target_ulong last_start = -1;
97 target_ulong pgsize;
98 target_ulong pte;
99 int ptshift;
100 int attr;
101 int idx;
102
103 if (level < 0) {
104 return;
105 }
106
107 ptshift = level * ptidxbits;
108 pgsize = 1UL << (PGSHIFT + ptshift);
109
110 for (idx = 0; idx < (1UL << ptidxbits); idx++) {
111 pte_addr = base + idx * ptesize;
112 address_space_read(as, pte_addr, attrs, &pte, ptesize);
113
114 paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT;
115 attr = pte & 0xff;
116
117 /* PTE has to be valid */
118 if (attr & PTE_V) {
119 if (attr & (PTE_R | PTE_W | PTE_X)) {
120 /*
121 * A leaf PTE has been found
122 *
123 * If current PTE's permission bits differ from the last one,
124 * or the current PTE breaks up a contiguous virtual or
125 * physical mapping, address block together with the last one,
126 * print out the last contiguous mapped block details.
127 */
128 if ((*last_attr != attr) ||
129 (*last_paddr + *last_size != paddr) ||
130 (last_start + *last_size != start)) {
131 print_pte(hmp, va_bits, *vbase, *pbase,
132 *last_paddr + *last_size - *pbase, *last_attr);
133
134 *vbase = start;
135 *pbase = paddr;
136 *last_attr = attr;
137 }
138
139 last_start = start;
140 *last_paddr = paddr;
141 *last_size = pgsize;
142 } else {
143 /* pointer to the next level of the page table */
144 walk_pte(hmp, as, paddr, start, level - 1, ptidxbits, ptesize,
145 va_bits, vbase, pbase, last_paddr,
146 last_size, last_attr);
147 }
148 }
149
150 start += pgsize;
151 }
152
153 }
154
155 static void mem_info_svxx(MonitorHMP *hmp, CPUArchState *env)
156 {
157 AddressSpace *as = env_cpu(env)->as;
158 int levels, ptidxbits, ptesize, vm, va_bits;
159 hwaddr base;
160 target_ulong vbase;
161 hwaddr pbase;
162 hwaddr last_paddr;
163 target_ulong last_size;
164 int last_attr;
165
166 if (riscv_cpu_mxl(env) == MXL_RV32) {
167 base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
168 vm = get_field(env->satp, SATP32_MODE);
169 } else {
170 base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
171 vm = get_field(env->satp, SATP64_MODE);
172 }
173
174 switch (vm) {
175 case VM_1_10_SV32:
176 levels = 2;
177 ptidxbits = 10;
178 ptesize = 4;
179 break;
180 case VM_1_10_SV39:
181 levels = 3;
182 ptidxbits = 9;
183 ptesize = 8;
184 break;
185 case VM_1_10_SV48:
186 levels = 4;
187 ptidxbits = 9;
188 ptesize = 8;
189 break;
190 case VM_1_10_SV57:
191 levels = 5;
192 ptidxbits = 9;
193 ptesize = 8;
194 break;
195 default:
196 g_assert_not_reached();
197 }
198
199 /* calculate virtual address bits */
200 va_bits = PGSHIFT + levels * ptidxbits;
201
202 /* print header */
203 print_pte_header(hmp);
204
205 vbase = -1;
206 pbase = -1;
207 last_paddr = -1;
208 last_size = 0;
209 last_attr = 0;
210
211 /* walk page tables, starting from address 0 */
212 walk_pte(hmp, as, base, 0, levels - 1, ptidxbits, ptesize, va_bits,
213 &vbase, &pbase, &last_paddr, &last_size, &last_attr);
214
215 /* don't forget the last one */
216 print_pte(hmp, va_bits, vbase, pbase,
217 last_paddr + last_size - pbase, last_attr);
218 }
219
220 void hmp_info_mem(MonitorHMP *hmp, const QDict *qdict)
221 {
222 CPUArchState *env;
223
224 env = monitor_hmp_get_cpu_env(hmp);
225 if (!env) {
226 monitor_hmp_printf(hmp, "No CPU available\n");
227 return;
228 }
229
230 if (!riscv_cpu_cfg(env)->mmu) {
231 monitor_hmp_printf(hmp, "S-mode MMU unavailable\n");
232 return;
233 }
234
235 if (riscv_cpu_mxl(env) == MXL_RV32) {
236 if (!(env->satp & SATP32_MODE)) {
237 monitor_hmp_printf(hmp, "No translation or protection\n");
238 return;
239 }
240 } else {
241 if (!(env->satp & SATP64_MODE)) {
242 monitor_hmp_printf(hmp, "No translation or protection\n");
243 return;
244 }
245 }
246
247 mem_info_svxx(hmp, env);
248 }
249 #endif /* CONFIG_HMP */
250
251 #ifdef CONFIG_TCG
252 static bool reg_is_ulong_integer(CPURISCVState *env, const char *name,
253 target_ulong *val, bool is_gprh)
254 {
255 const char * const *reg_names;
256 uint64_t *vals;
257
258 if (is_gprh) {
259 reg_names = riscv_int_regnamesh;
260 vals = env->gprh;
261 } else {
262 reg_names = riscv_int_regnames;
263 vals = env->gpr;
264 }
265
266 for (int i = 0; i < 32; i++) {
267 g_auto(GStrv) reg_name = g_strsplit(reg_names[i], "/", 2);
268
269 g_assert(reg_name[0]);
270 g_assert(reg_name[1]);
271
272 if (g_ascii_strcasecmp(reg_name[0], name) == 0 ||
273 g_ascii_strcasecmp(reg_name[1], name) == 0) {
274 *val = vals[i];
275 return true;
276 }
277 }
278
279 return false;
280 }
281
282 static bool reg_is_u64_fpu(CPURISCVState *env, const char *name, uint64_t *val)
283 {
284 if (qemu_tolower(name[0]) != 'f') {
285 return false;
286 }
287
288 for (int i = 0; i < 32; i++) {
289 g_auto(GStrv) reg_name = g_strsplit(riscv_fpr_regnames[i], "/", 2);
290
291 g_assert(reg_name[0]);
292 g_assert(reg_name[1]);
293
294 if (g_ascii_strcasecmp(reg_name[0], name) == 0 ||
295 g_ascii_strcasecmp(reg_name[1], name) == 0) {
296 *val = env->fpr[i];
297 return true;
298 }
299 }
300
301 return false;
302 }
303
304 static bool reg_is_vreg(const char *name)
305 {
306 if (qemu_tolower(name[0]) != 'v' || strlen(name) > 3) {
307 return false;
308 }
309
310 for (int i = 0; i < 32; i++) {
311 if (g_ascii_strcasecmp(name, riscv_rvv_regnames[i]) == 0) {
312 return true;
313 }
314 }
315
316 return false;
317 }
318
319 int riscv_monitor_get_register_legacy(CPUState *cs, const char *name,
320 int64_t *pval)
321 {
322 RISCVCPU *hart = RISCV_CPU(cs);
323 CPURISCVState *env = cpu_env(cs);
324 target_ulong val = 0;
325 uint64_t val64 = 0;
326 int i;
327
328 if (reg_is_ulong_integer(env, name, &val, false) ||
329 reg_is_ulong_integer(env, name, &val, true)) {
330 *pval = riscv_cpu_is_32bit(hart) ? (int32_t)val : val;
331 return 0;
332 }
333
334 if (reg_is_u64_fpu(env, name, &val64)) {
335 *pval = val64;
336 return 0;
337 }
338
339 if (reg_is_vreg(name)) {
340 if (!riscv_cpu_cfg(env)->ext_zve32x) {
341 return -EINVAL;
342 }
343
344 qemu_printf("Unable to print the value of vector "
345 "vreg '%s' from this API\n", name);
346
347 /*
348 * We're returning 0 because returning -EINVAL triggers
349 * an 'unknown register' message in exp_unary() later,
350 * which feels ankward after our own error message.
351 */
352 *pval = 0;
353 return 0;
354 }
355
356 for (i = 0; i < ARRAY_SIZE(csr_ops); i++) {
357 RISCVException res;
358 int csrno = i;
359
360 /*
361 * Early skip when possible since we're going
362 * through a lot of NULL entries.
363 */
364 if (csr_ops[csrno].predicate == NULL) {
365 continue;
366 }
367
368 if (g_ascii_strcasecmp(csr_ops[csrno].name, name) != 0) {
369 continue;
370 }
371
372 res = riscv_csrrw_debug(env, csrno, &val, 0, 0);
373
374 /*
375 * Rely on the smode, hmode, etc, predicates within csr.c
376 * to do the filtering of the registers that are present.
377 */
378 if (res == RISCV_EXCP_NONE) {
379 *pval = riscv_cpu_is_32bit(hart) ? (int32_t)val : val;
380 return 0;
381 }
382 }
383
384 return -EINVAL;
385 }
386 #endif