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 "cpu.h"
23 #include "cpu_bits.h"
24 #include "monitor/monitor.h"
25 #include "monitor/hmp-target.h"
26
27 #ifdef TARGET_RISCV64
28 #define PTE_HEADER_FIELDS "vaddr paddr "\
29 "size attr\n"
30 #define PTE_HEADER_DELIMITER "---------------- ---------------- "\
31 "---------------- -------\n"
32 #else
33 #define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
34 #define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
35 #endif
36
37 /* Perform linear address sign extension */
addr_canonical(int va_bits,target_ulong addr)38 static target_ulong addr_canonical(int va_bits, target_ulong addr)
39 {
40 #ifdef TARGET_RISCV64
41 if (addr & (1UL << (va_bits - 1))) {
42 addr |= (hwaddr)-(1L << va_bits);
43 }
44 #endif
45
46 return addr;
47 }
48
print_pte_header(Monitor * mon)49 static void print_pte_header(Monitor *mon)
50 {
51 monitor_printf(mon, PTE_HEADER_FIELDS);
52 monitor_printf(mon, PTE_HEADER_DELIMITER);
53 }
54
print_pte(Monitor * mon,int va_bits,target_ulong vaddr,hwaddr paddr,target_ulong size,int attr)55 static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr,
56 hwaddr paddr, target_ulong size, int attr)
57 {
58 /* sanity check on vaddr */
59 if (vaddr >= (1UL << va_bits)) {
60 return;
61 }
62
63 if (!size) {
64 return;
65 }
66
67 monitor_printf(mon, TARGET_FMT_lx " " HWADDR_FMT_plx " " TARGET_FMT_lx
68 " %c%c%c%c%c%c%c\n",
69 addr_canonical(va_bits, vaddr),
70 paddr, size,
71 attr & PTE_R ? 'r' : '-',
72 attr & PTE_W ? 'w' : '-',
73 attr & PTE_X ? 'x' : '-',
74 attr & PTE_U ? 'u' : '-',
75 attr & PTE_G ? 'g' : '-',
76 attr & PTE_A ? 'a' : '-',
77 attr & PTE_D ? 'd' : '-');
78 }
79
walk_pte(Monitor * mon,hwaddr base,target_ulong start,int level,int ptidxbits,int ptesize,int va_bits,target_ulong * vbase,hwaddr * pbase,hwaddr * last_paddr,target_ulong * last_size,int * last_attr)80 static void walk_pte(Monitor *mon, hwaddr base, target_ulong start,
81 int level, int ptidxbits, int ptesize, int va_bits,
82 target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr,
83 target_ulong *last_size, int *last_attr)
84 {
85 hwaddr pte_addr;
86 hwaddr paddr;
87 target_ulong last_start = -1;
88 target_ulong pgsize;
89 target_ulong pte;
90 int ptshift;
91 int attr;
92 int idx;
93
94 if (level < 0) {
95 return;
96 }
97
98 ptshift = level * ptidxbits;
99 pgsize = 1UL << (PGSHIFT + ptshift);
100
101 for (idx = 0; idx < (1UL << ptidxbits); idx++) {
102 pte_addr = base + idx * ptesize;
103 cpu_physical_memory_read(pte_addr, &pte, ptesize);
104
105 paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT;
106 attr = pte & 0xff;
107
108 /* PTE has to be valid */
109 if (attr & PTE_V) {
110 if (attr & (PTE_R | PTE_W | PTE_X)) {
111 /*
112 * A leaf PTE has been found
113 *
114 * If current PTE's permission bits differ from the last one,
115 * or the current PTE breaks up a contiguous virtual or
116 * physical mapping, address block together with the last one,
117 * print out the last contiguous mapped block details.
118 */
119 if ((*last_attr != attr) ||
120 (*last_paddr + *last_size != paddr) ||
121 (last_start + *last_size != start)) {
122 print_pte(mon, va_bits, *vbase, *pbase,
123 *last_paddr + *last_size - *pbase, *last_attr);
124
125 *vbase = start;
126 *pbase = paddr;
127 *last_attr = attr;
128 }
129
130 last_start = start;
131 *last_paddr = paddr;
132 *last_size = pgsize;
133 } else {
134 /* pointer to the next level of the page table */
135 walk_pte(mon, paddr, start, level - 1, ptidxbits, ptesize,
136 va_bits, vbase, pbase, last_paddr,
137 last_size, last_attr);
138 }
139 }
140
141 start += pgsize;
142 }
143
144 }
145
mem_info_svxx(Monitor * mon,CPUArchState * env)146 static void mem_info_svxx(Monitor *mon, CPUArchState *env)
147 {
148 int levels, ptidxbits, ptesize, vm, va_bits;
149 hwaddr base;
150 target_ulong vbase;
151 hwaddr pbase;
152 hwaddr last_paddr;
153 target_ulong last_size;
154 int last_attr;
155
156 if (riscv_cpu_mxl(env) == MXL_RV32) {
157 base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
158 vm = get_field(env->satp, SATP32_MODE);
159 } else {
160 base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
161 vm = get_field(env->satp, SATP64_MODE);
162 }
163
164 switch (vm) {
165 case VM_1_10_SV32:
166 levels = 2;
167 ptidxbits = 10;
168 ptesize = 4;
169 break;
170 case VM_1_10_SV39:
171 levels = 3;
172 ptidxbits = 9;
173 ptesize = 8;
174 break;
175 case VM_1_10_SV48:
176 levels = 4;
177 ptidxbits = 9;
178 ptesize = 8;
179 break;
180 case VM_1_10_SV57:
181 levels = 5;
182 ptidxbits = 9;
183 ptesize = 8;
184 break;
185 default:
186 g_assert_not_reached();
187 break;
188 }
189
190 /* calculate virtual address bits */
191 va_bits = PGSHIFT + levels * ptidxbits;
192
193 /* print header */
194 print_pte_header(mon);
195
196 vbase = -1;
197 pbase = -1;
198 last_paddr = -1;
199 last_size = 0;
200 last_attr = 0;
201
202 /* walk page tables, starting from address 0 */
203 walk_pte(mon, base, 0, levels - 1, ptidxbits, ptesize, va_bits,
204 &vbase, &pbase, &last_paddr, &last_size, &last_attr);
205
206 /* don't forget the last one */
207 print_pte(mon, va_bits, vbase, pbase,
208 last_paddr + last_size - pbase, last_attr);
209 }
210
hmp_info_mem(Monitor * mon,const QDict * qdict)211 void hmp_info_mem(Monitor *mon, const QDict *qdict)
212 {
213 CPUArchState *env;
214
215 env = mon_get_cpu_env(mon);
216 if (!env) {
217 monitor_printf(mon, "No CPU available\n");
218 return;
219 }
220
221 if (!riscv_cpu_cfg(env)->mmu) {
222 monitor_printf(mon, "S-mode MMU unavailable\n");
223 return;
224 }
225
226 if (riscv_cpu_mxl(env) == MXL_RV32) {
227 if (!(env->satp & SATP32_MODE)) {
228 monitor_printf(mon, "No translation or protection\n");
229 return;
230 }
231 } else {
232 if (!(env->satp & SATP64_MODE)) {
233 monitor_printf(mon, "No translation or protection\n");
234 return;
235 }
236 }
237
238 mem_info_svxx(mon, env);
239 }
240