qemu/target/riscv/cpu.c
<<
>>
Prefs
   1/*
   2 * QEMU RISC-V CPU
   3 *
   4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
   5 * Copyright (c) 2017-2018 SiFive, Inc.
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms and conditions of the GNU General Public License,
   9 * version 2 or later, as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu/log.h"
  22#include "cpu.h"
  23#include "exec/exec-all.h"
  24#include "qapi/error.h"
  25#include "migration/vmstate.h"
  26
  27/* RISC-V CPU definitions */
  28
  29static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
  30
  31const char * const riscv_int_regnames[] = {
  32  "zero", "ra  ", "sp  ", "gp  ", "tp  ", "t0  ", "t1  ", "t2  ",
  33  "s0  ", "s1  ", "a0  ", "a1  ", "a2  ", "a3  ", "a4  ", "a5  ",
  34  "a6  ", "a7  ", "s2  ", "s3  ", "s4  ", "s5  ", "s6  ", "s7  ",
  35  "s8  ", "s9  ", "s10 ", "s11 ", "t3  ", "t4  ", "t5  ", "t6  "
  36};
  37
  38const char * const riscv_fpr_regnames[] = {
  39  "ft0 ", "ft1 ", "ft2 ", "ft3 ", "ft4 ", "ft5 ", "ft6 ",  "ft7 ",
  40  "fs0 ", "fs1 ", "fa0 ", "fa1 ", "fa2 ", "fa3 ", "fa4 ",  "fa5 ",
  41  "fa6 ", "fa7 ", "fs2 ", "fs3 ", "fs4 ", "fs5 ", "fs6 ",  "fs7 ",
  42  "fs8 ", "fs9 ", "fs10", "fs11", "ft8 ", "ft9 ", "ft10",  "ft11"
  43};
  44
  45const char * const riscv_excp_names[] = {
  46    "misaligned_fetch",
  47    "fault_fetch",
  48    "illegal_instruction",
  49    "breakpoint",
  50    "misaligned_load",
  51    "fault_load",
  52    "misaligned_store",
  53    "fault_store",
  54    "user_ecall",
  55    "supervisor_ecall",
  56    "hypervisor_ecall",
  57    "machine_ecall",
  58    "exec_page_fault",
  59    "load_page_fault",
  60    "reserved",
  61    "store_page_fault"
  62};
  63
  64const char * const riscv_intr_names[] = {
  65    "u_software",
  66    "s_software",
  67    "h_software",
  68    "m_software",
  69    "u_timer",
  70    "s_timer",
  71    "h_timer",
  72    "m_timer",
  73    "u_external",
  74    "s_external",
  75    "h_external",
  76    "m_external",
  77    "reserved",
  78    "reserved",
  79    "reserved",
  80    "reserved"
  81};
  82
  83typedef struct RISCVCPUInfo {
  84    const int bit_widths;
  85    const char *name;
  86    void (*initfn)(Object *obj);
  87} RISCVCPUInfo;
  88
  89static void set_misa(CPURISCVState *env, target_ulong misa)
  90{
  91    env->misa = misa;
  92}
  93
  94static void set_versions(CPURISCVState *env, int user_ver, int priv_ver)
  95{
  96    env->user_ver = user_ver;
  97    env->priv_ver = priv_ver;
  98}
  99
 100static void set_feature(CPURISCVState *env, int feature)
 101{
 102    env->features |= (1ULL << feature);
 103}
 104
 105static void set_resetvec(CPURISCVState *env, int resetvec)
 106{
 107#ifndef CONFIG_USER_ONLY
 108    env->resetvec = resetvec;
 109#endif
 110}
 111
 112static void riscv_any_cpu_init(Object *obj)
 113{
 114    CPURISCVState *env = &RISCV_CPU(obj)->env;
 115    set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
 116    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 117    set_resetvec(env, DEFAULT_RSTVEC);
 118}
 119
 120#if defined(TARGET_RISCV32)
 121
 122static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
 123{
 124    CPURISCVState *env = &RISCV_CPU(obj)->env;
 125    set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 126    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
 127    set_resetvec(env, DEFAULT_RSTVEC);
 128    set_feature(env, RISCV_FEATURE_MMU);
 129}
 130
 131static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
 132{
 133    CPURISCVState *env = &RISCV_CPU(obj)->env;
 134    set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 135    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 136    set_resetvec(env, DEFAULT_RSTVEC);
 137    set_feature(env, RISCV_FEATURE_MMU);
 138}
 139
 140static void rv32imacu_nommu_cpu_init(Object *obj)
 141{
 142    CPURISCVState *env = &RISCV_CPU(obj)->env;
 143    set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
 144    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 145    set_resetvec(env, DEFAULT_RSTVEC);
 146}
 147
 148#elif defined(TARGET_RISCV64)
 149
 150static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
 151{
 152    CPURISCVState *env = &RISCV_CPU(obj)->env;
 153    set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 154    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
 155    set_resetvec(env, DEFAULT_RSTVEC);
 156    set_feature(env, RISCV_FEATURE_MMU);
 157}
 158
 159static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
 160{
 161    CPURISCVState *env = &RISCV_CPU(obj)->env;
 162    set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 163    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 164    set_resetvec(env, DEFAULT_RSTVEC);
 165    set_feature(env, RISCV_FEATURE_MMU);
 166}
 167
 168static void rv64imacu_nommu_cpu_init(Object *obj)
 169{
 170    CPURISCVState *env = &RISCV_CPU(obj)->env;
 171    set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
 172    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 173    set_resetvec(env, DEFAULT_RSTVEC);
 174}
 175
 176#endif
 177
 178static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
 179{
 180    ObjectClass *oc;
 181    char *typename;
 182    char **cpuname;
 183
 184    cpuname = g_strsplit(cpu_model, ",", 1);
 185    typename = g_strdup_printf(RISCV_CPU_TYPE_NAME("%s"), cpuname[0]);
 186    oc = object_class_by_name(typename);
 187    g_strfreev(cpuname);
 188    g_free(typename);
 189    if (!oc || !object_class_dynamic_cast(oc, TYPE_RISCV_CPU) ||
 190        object_class_is_abstract(oc)) {
 191        return NULL;
 192    }
 193    return oc;
 194}
 195
 196static void riscv_cpu_dump_state(CPUState *cs, FILE *f,
 197    fprintf_function cpu_fprintf, int flags)
 198{
 199    RISCVCPU *cpu = RISCV_CPU(cs);
 200    CPURISCVState *env = &cpu->env;
 201    int i;
 202
 203    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
 204#ifndef CONFIG_USER_ONLY
 205    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
 206    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
 207    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ",
 208        (target_ulong)atomic_read(&env->mip));
 209    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
 210    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
 211    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
 212    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec   ", env->mtvec);
 213    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc    ", env->mepc);
 214    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause  ", env->mcause);
 215#endif
 216
 217    for (i = 0; i < 32; i++) {
 218        cpu_fprintf(f, " %s " TARGET_FMT_lx,
 219            riscv_int_regnames[i], env->gpr[i]);
 220        if ((i & 3) == 3) {
 221            cpu_fprintf(f, "\n");
 222        }
 223    }
 224    if (flags & CPU_DUMP_FPU) {
 225        for (i = 0; i < 32; i++) {
 226            cpu_fprintf(f, " %s %016" PRIx64,
 227                riscv_fpr_regnames[i], env->fpr[i]);
 228            if ((i & 3) == 3) {
 229                cpu_fprintf(f, "\n");
 230            }
 231        }
 232    }
 233}
 234
 235static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
 236{
 237    RISCVCPU *cpu = RISCV_CPU(cs);
 238    CPURISCVState *env = &cpu->env;
 239    env->pc = value;
 240}
 241
 242static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
 243{
 244    RISCVCPU *cpu = RISCV_CPU(cs);
 245    CPURISCVState *env = &cpu->env;
 246    env->pc = tb->pc;
 247}
 248
 249static bool riscv_cpu_has_work(CPUState *cs)
 250{
 251#ifndef CONFIG_USER_ONLY
 252    RISCVCPU *cpu = RISCV_CPU(cs);
 253    CPURISCVState *env = &cpu->env;
 254    /*
 255     * Definition of the WFI instruction requires it to ignore the privilege
 256     * mode and delegation registers, but respect individual enables
 257     */
 258    return (atomic_read(&env->mip) & env->mie) != 0;
 259#else
 260    return true;
 261#endif
 262}
 263
 264void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
 265                          target_ulong *data)
 266{
 267    env->pc = data[0];
 268}
 269
 270static void riscv_cpu_reset(CPUState *cs)
 271{
 272    RISCVCPU *cpu = RISCV_CPU(cs);
 273    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
 274    CPURISCVState *env = &cpu->env;
 275
 276    mcc->parent_reset(cs);
 277#ifndef CONFIG_USER_ONLY
 278    env->priv = PRV_M;
 279    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
 280    env->mcause = 0;
 281    env->pc = env->resetvec;
 282#endif
 283    cs->exception_index = EXCP_NONE;
 284    set_default_nan_mode(1, &env->fp_status);
 285}
 286
 287static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
 288{
 289#if defined(TARGET_RISCV32)
 290    info->print_insn = print_insn_riscv32;
 291#elif defined(TARGET_RISCV64)
 292    info->print_insn = print_insn_riscv64;
 293#endif
 294}
 295
 296static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 297{
 298    CPUState *cs = CPU(dev);
 299    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
 300    Error *local_err = NULL;
 301
 302    cpu_exec_realizefn(cs, &local_err);
 303    if (local_err != NULL) {
 304        error_propagate(errp, local_err);
 305        return;
 306    }
 307
 308    qemu_init_vcpu(cs);
 309    cpu_reset(cs);
 310
 311    mcc->parent_realize(dev, errp);
 312}
 313
 314static void riscv_cpu_init(Object *obj)
 315{
 316    CPUState *cs = CPU(obj);
 317    RISCVCPU *cpu = RISCV_CPU(obj);
 318
 319    cs->env_ptr = &cpu->env;
 320}
 321
 322static const VMStateDescription vmstate_riscv_cpu = {
 323    .name = "cpu",
 324    .unmigratable = 1,
 325};
 326
 327static void riscv_cpu_class_init(ObjectClass *c, void *data)
 328{
 329    RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
 330    CPUClass *cc = CPU_CLASS(c);
 331    DeviceClass *dc = DEVICE_CLASS(c);
 332
 333    mcc->parent_realize = dc->realize;
 334    dc->realize = riscv_cpu_realize;
 335
 336    mcc->parent_reset = cc->reset;
 337    cc->reset = riscv_cpu_reset;
 338
 339    cc->class_by_name = riscv_cpu_class_by_name;
 340    cc->has_work = riscv_cpu_has_work;
 341    cc->do_interrupt = riscv_cpu_do_interrupt;
 342    cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
 343    cc->dump_state = riscv_cpu_dump_state;
 344    cc->set_pc = riscv_cpu_set_pc;
 345    cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
 346    cc->gdb_read_register = riscv_cpu_gdb_read_register;
 347    cc->gdb_write_register = riscv_cpu_gdb_write_register;
 348    cc->gdb_num_core_regs = 65;
 349    cc->gdb_stop_before_watchpoint = true;
 350    cc->disas_set_info = riscv_cpu_disas_set_info;
 351#ifdef CONFIG_USER_ONLY
 352    cc->handle_mmu_fault = riscv_cpu_handle_mmu_fault;
 353#else
 354    cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
 355    cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
 356#endif
 357#ifdef CONFIG_TCG
 358    cc->tcg_initialize = riscv_translate_init;
 359#endif
 360    /* For now, mark unmigratable: */
 361    cc->vmsd = &vmstate_riscv_cpu;
 362}
 363
 364char *riscv_isa_string(RISCVCPU *cpu)
 365{
 366    int i;
 367    const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1;
 368    char *isa_str = g_new(char, maxlen);
 369    char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS);
 370    for (i = 0; i < sizeof(riscv_exts); i++) {
 371        if (cpu->env.misa & RV(riscv_exts[i])) {
 372            *p++ = qemu_tolower(riscv_exts[i]);
 373        }
 374    }
 375    *p = '\0';
 376    return isa_str;
 377}
 378
 379typedef struct RISCVCPUListState {
 380    fprintf_function cpu_fprintf;
 381    FILE *file;
 382} RISCVCPUListState;
 383
 384static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b)
 385{
 386    ObjectClass *class_a = (ObjectClass *)a;
 387    ObjectClass *class_b = (ObjectClass *)b;
 388    const char *name_a, *name_b;
 389
 390    name_a = object_class_get_name(class_a);
 391    name_b = object_class_get_name(class_b);
 392    return strcmp(name_a, name_b);
 393}
 394
 395static void riscv_cpu_list_entry(gpointer data, gpointer user_data)
 396{
 397    RISCVCPUListState *s = user_data;
 398    const char *typename = object_class_get_name(OBJECT_CLASS(data));
 399    int len = strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX);
 400
 401    (*s->cpu_fprintf)(s->file, "%.*s\n", len, typename);
 402}
 403
 404void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 405{
 406    RISCVCPUListState s = {
 407        .cpu_fprintf = cpu_fprintf,
 408        .file = f,
 409    };
 410    GSList *list;
 411
 412    list = object_class_get_list(TYPE_RISCV_CPU, false);
 413    list = g_slist_sort(list, riscv_cpu_list_compare);
 414    g_slist_foreach(list, riscv_cpu_list_entry, &s);
 415    g_slist_free(list);
 416}
 417
 418#define DEFINE_CPU(type_name, initfn)      \
 419    {                                      \
 420        .name = type_name,                 \
 421        .parent = TYPE_RISCV_CPU,          \
 422        .instance_init = initfn            \
 423    }
 424
 425static const TypeInfo riscv_cpu_type_infos[] = {
 426    {
 427        .name = TYPE_RISCV_CPU,
 428        .parent = TYPE_CPU,
 429        .instance_size = sizeof(RISCVCPU),
 430        .instance_init = riscv_cpu_init,
 431        .abstract = true,
 432        .class_size = sizeof(RISCVCPUClass),
 433        .class_init = riscv_cpu_class_init,
 434    },
 435    DEFINE_CPU(TYPE_RISCV_CPU_ANY,              riscv_any_cpu_init),
 436#if defined(TARGET_RISCV32)
 437    DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
 438    DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init),
 439    DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU,  rv32imacu_nommu_cpu_init),
 440    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31,       rv32imacu_nommu_cpu_init),
 441    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34,       rv32gcsu_priv1_10_0_cpu_init)
 442#elif defined(TARGET_RISCV64)
 443    DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
 444    DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init),
 445    DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU,  rv64imacu_nommu_cpu_init),
 446    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51,       rv64imacu_nommu_cpu_init),
 447    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54,       rv64gcsu_priv1_10_0_cpu_init)
 448#endif
 449};
 450
 451DEFINE_TYPES(riscv_cpu_type_infos)
 452