2 * QEMU monitor for RISC-V
4 * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
6 * RISC-V specific monitor commands implementation
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.
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
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/>.
21 #include "qemu/osdep.h"
24 #include "monitor/monitor.h"
25 #include "monitor/hmp-target.h"
28 #define PTE_HEADER_FIELDS "vaddr paddr "\
30 #define PTE_HEADER_DELIMITER "---------------- ---------------- "\
31 "---------------- -------\n"
33 #define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
34 #define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
37 /* Perform linear address sign extension */
38 static target_ulong
addr_canonical(int va_bits
, target_ulong addr
)
41 if (addr
& (1UL << (va_bits
- 1))) {
42 addr
|= (hwaddr
)-(1L << va_bits
);
49 static void print_pte_header(Monitor
*mon
)
51 monitor_printf(mon
, PTE_HEADER_FIELDS
);
52 monitor_printf(mon
, PTE_HEADER_DELIMITER
);
55 static void print_pte(Monitor
*mon
, int va_bits
, target_ulong vaddr
,
56 hwaddr paddr
, target_ulong size
, int attr
)
58 /* santity check on vaddr */
59 if (vaddr
>= (1UL << va_bits
)) {
67 monitor_printf(mon
, TARGET_FMT_lx
" " HWADDR_FMT_plx
" " TARGET_FMT_lx
69 addr_canonical(va_bits
, vaddr
),
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' : '-');
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
)
87 target_ulong last_start
= -1;
98 ptshift
= level
* ptidxbits
;
99 pgsize
= 1UL << (PGSHIFT
+ ptshift
);
101 for (idx
= 0; idx
< (1UL << ptidxbits
); idx
++) {
102 pte_addr
= base
+ idx
* ptesize
;
103 cpu_physical_memory_read(pte_addr
, &pte
, ptesize
);
105 paddr
= (hwaddr
)(pte
>> PTE_PPN_SHIFT
) << PGSHIFT
;
108 /* PTE has to be valid */
110 if (attr
& (PTE_R
| PTE_W
| PTE_X
)) {
112 * A leaf PTE has been found
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.
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
);
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
);
146 static void mem_info_svxx(Monitor
*mon
, CPUArchState
*env
)
148 int levels
, ptidxbits
, ptesize
, vm
, va_bits
;
153 target_ulong last_size
;
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
);
160 base
= (hwaddr
)get_field(env
->satp
, SATP64_PPN
) << PGSHIFT
;
161 vm
= get_field(env
->satp
, SATP64_MODE
);
186 g_assert_not_reached();
190 /* calculate virtual address bits */
191 va_bits
= PGSHIFT
+ levels
* ptidxbits
;
194 print_pte_header(mon
);
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
);
206 /* don't forget the last one */
207 print_pte(mon
, va_bits
, vbase
, pbase
,
208 last_paddr
+ last_size
- pbase
, last_attr
);
211 void hmp_info_mem(Monitor
*mon
, const QDict
*qdict
)
215 env
= mon_get_cpu_env(mon
);
217 monitor_printf(mon
, "No CPU available\n");
221 if (!riscv_feature(env
, RISCV_FEATURE_MMU
)) {
222 monitor_printf(mon
, "S-mode MMU unavailable\n");
226 if (riscv_cpu_mxl(env
) == MXL_RV32
) {
227 if (!(env
->satp
& SATP32_MODE
)) {
228 monitor_printf(mon
, "No translation or protection\n");
232 if (!(env
->satp
& SATP64_MODE
)) {
233 monitor_printf(mon
, "No translation or protection\n");
238 mem_info_svxx(mon
, env
);