qemu/target/riscv/gdbstub.c
<<
>>
Prefs
   1/*
   2 * RISC-V GDB Server Stub
   3 *
   4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2 or later, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along with
  16 * this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include "qemu/osdep.h"
  20#include "exec/gdbstub.h"
  21#include "cpu.h"
  22
  23int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
  24{
  25    RISCVCPU *cpu = RISCV_CPU(cs);
  26    CPURISCVState *env = &cpu->env;
  27
  28    if (n < 32) {
  29        return gdb_get_regl(mem_buf, env->gpr[n]);
  30    } else if (n == 32) {
  31        return gdb_get_regl(mem_buf, env->pc);
  32    }
  33    return 0;
  34}
  35
  36int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
  37{
  38    RISCVCPU *cpu = RISCV_CPU(cs);
  39    CPURISCVState *env = &cpu->env;
  40
  41    if (n == 0) {
  42        /* discard writes to x0 */
  43        return sizeof(target_ulong);
  44    } else if (n < 32) {
  45        env->gpr[n] = ldtul_p(mem_buf);
  46        return sizeof(target_ulong);
  47    } else if (n == 32) {
  48        env->pc = ldtul_p(mem_buf);
  49        return sizeof(target_ulong);
  50    }
  51    return 0;
  52}
  53
  54static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
  55{
  56    if (n < 32) {
  57        if (env->misa_ext & RVD) {
  58            return gdb_get_reg64(buf, env->fpr[n]);
  59        }
  60        if (env->misa_ext & RVF) {
  61            return gdb_get_reg32(buf, env->fpr[n]);
  62        }
  63    /* there is hole between ft11 and fflags in fpu.xml */
  64    } else if (n < 36 && n > 32) {
  65        target_ulong val = 0;
  66        int result;
  67        /*
  68         * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP
  69         * register 33, so we recalculate the map index.
  70         * This also works for CSR_FRM and CSR_FCSR.
  71         */
  72        result = riscv_csrrw_debug(env, n - 32, &val,
  73                                   0, 0);
  74        if (result == RISCV_EXCP_NONE) {
  75            return gdb_get_regl(buf, val);
  76        }
  77    }
  78    return 0;
  79}
  80
  81static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
  82{
  83    if (n < 32) {
  84        env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
  85        return sizeof(uint64_t);
  86    /* there is hole between ft11 and fflags in fpu.xml */
  87    } else if (n < 36 && n > 32) {
  88        target_ulong val = ldtul_p(mem_buf);
  89        int result;
  90        /*
  91         * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP
  92         * register 33, so we recalculate the map index.
  93         * This also works for CSR_FRM and CSR_FCSR.
  94         */
  95        result = riscv_csrrw_debug(env, n - 32, NULL,
  96                                   val, -1);
  97        if (result == RISCV_EXCP_NONE) {
  98            return sizeof(target_ulong);
  99        }
 100    }
 101    return 0;
 102}
 103
 104static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
 105{
 106    if (n < CSR_TABLE_SIZE) {
 107        target_ulong val = 0;
 108        int result;
 109
 110        result = riscv_csrrw_debug(env, n, &val, 0, 0);
 111        if (result == RISCV_EXCP_NONE) {
 112            return gdb_get_regl(buf, val);
 113        }
 114    }
 115    return 0;
 116}
 117
 118static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
 119{
 120    if (n < CSR_TABLE_SIZE) {
 121        target_ulong val = ldtul_p(mem_buf);
 122        int result;
 123
 124        result = riscv_csrrw_debug(env, n, NULL, val, -1);
 125        if (result == RISCV_EXCP_NONE) {
 126            return sizeof(target_ulong);
 127        }
 128    }
 129    return 0;
 130}
 131
 132static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
 133{
 134    if (n == 0) {
 135#ifdef CONFIG_USER_ONLY
 136        return gdb_get_regl(buf, 0);
 137#else
 138        return gdb_get_regl(buf, cs->priv);
 139#endif
 140    }
 141    return 0;
 142}
 143
 144static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
 145{
 146    if (n == 0) {
 147#ifndef CONFIG_USER_ONLY
 148        cs->priv = ldtul_p(mem_buf) & 0x3;
 149        if (cs->priv == PRV_H) {
 150            cs->priv = PRV_S;
 151        }
 152#endif
 153        return sizeof(target_ulong);
 154    }
 155    return 0;
 156}
 157
 158static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
 159{
 160    RISCVCPU *cpu = RISCV_CPU(cs);
 161    CPURISCVState *env = &cpu->env;
 162    GString *s = g_string_new(NULL);
 163    riscv_csr_predicate_fn predicate;
 164    int bitsize = 16 << env->misa_mxl_max;
 165    int i;
 166
 167    g_string_printf(s, "<?xml version=\"1.0\"?>");
 168    g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">");
 169    g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">");
 170
 171    for (i = 0; i < CSR_TABLE_SIZE; i++) {
 172        predicate = csr_ops[i].predicate;
 173        if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) {
 174            if (csr_ops[i].name) {
 175                g_string_append_printf(s, "<reg name=\"%s\"", csr_ops[i].name);
 176            } else {
 177                g_string_append_printf(s, "<reg name=\"csr%03x\"", i);
 178            }
 179            g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
 180            g_string_append_printf(s, " regnum=\"%d\"/>", base_reg + i);
 181        }
 182    }
 183
 184    g_string_append_printf(s, "</feature>");
 185
 186    cpu->dyn_csr_xml = g_string_free(s, false);
 187    return CSR_TABLE_SIZE;
 188}
 189
 190void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
 191{
 192    RISCVCPU *cpu = RISCV_CPU(cs);
 193    CPURISCVState *env = &cpu->env;
 194    if (env->misa_ext & RVD) {
 195        gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
 196                                 36, "riscv-64bit-fpu.xml", 0);
 197    } else if (env->misa_ext & RVF) {
 198        gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
 199                                 36, "riscv-32bit-fpu.xml", 0);
 200    }
 201#if defined(TARGET_RISCV32)
 202    gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
 203                             1, "riscv-32bit-virtual.xml", 0);
 204#elif defined(TARGET_RISCV64)
 205    gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
 206                             1, "riscv-64bit-virtual.xml", 0);
 207#endif
 208
 209    gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
 210                             riscv_gen_dynamic_csr_xml(cs, cs->gdb_num_regs),
 211                             "riscv-csr.xml", 0);
 212}
 213