qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

monitor.c (6978B)


      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 " " TARGET_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_feature(env, RISCV_FEATURE_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 }