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 */ 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 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 55 static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr, 56 hwaddr paddr, target_ulong size, int attr) 57 { 58 /* santity 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 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 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 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