qemu/target/riscv/monitor.c
<<
>>
Prefs
   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 */
  38static 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
  49static void print_pte_header(Monitor *mon)
  50{
  51    monitor_printf(mon, PTE_HEADER_FIELDS);
  52    monitor_printf(mon, PTE_HEADER_DELIMITER);
  53}
  54
  55static 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
  80static 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
 146static 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
 211void 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}
 240