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    "coprocessor",
  78    "host"
  79};
  80
  81typedef struct RISCVCPUInfo {
  82    const int bit_widths;
  83    const char *name;
  84    void (*initfn)(Object *obj);
  85} RISCVCPUInfo;
  86
  87static void set_misa(CPURISCVState *env, target_ulong misa)
  88{
  89    env->misa = misa;
  90}
  91
  92static void set_versions(CPURISCVState *env, int user_ver, int priv_ver)
  93{
  94    env->user_ver = user_ver;
  95    env->priv_ver = priv_ver;
  96}
  97
  98static void set_feature(CPURISCVState *env, int feature)
  99{
 100    env->features |= (1ULL << feature);
 101}
 102
 103static void set_resetvec(CPURISCVState *env, int resetvec)
 104{
 105#ifndef CONFIG_USER_ONLY
 106    env->resetvec = resetvec;
 107#endif
 108}
 109
 110static void riscv_any_cpu_init(Object *obj)
 111{
 112    CPURISCVState *env = &RISCV_CPU(obj)->env;
 113    set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
 114    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 115    set_resetvec(env, DEFAULT_RSTVEC);
 116}
 117
 118#if defined(TARGET_RISCV32)
 119
 120static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
 121{
 122    CPURISCVState *env = &RISCV_CPU(obj)->env;
 123    set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 124    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
 125    set_resetvec(env, DEFAULT_RSTVEC);
 126    set_feature(env, RISCV_FEATURE_MMU);
 127}
 128
 129static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
 130{
 131    CPURISCVState *env = &RISCV_CPU(obj)->env;
 132    set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 133    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 134    set_resetvec(env, DEFAULT_RSTVEC);
 135    set_feature(env, RISCV_FEATURE_MMU);
 136}
 137
 138static void rv32imacu_nommu_cpu_init(Object *obj)
 139{
 140    CPURISCVState *env = &RISCV_CPU(obj)->env;
 141    set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
 142    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 143    set_resetvec(env, DEFAULT_RSTVEC);
 144}
 145
 146#elif defined(TARGET_RISCV64)
 147
 148static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
 149{
 150    CPURISCVState *env = &RISCV_CPU(obj)->env;
 151    set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 152    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
 153    set_resetvec(env, DEFAULT_RSTVEC);
 154    set_feature(env, RISCV_FEATURE_MMU);
 155}
 156
 157static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
 158{
 159    CPURISCVState *env = &RISCV_CPU(obj)->env;
 160    set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
 161    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 162    set_resetvec(env, DEFAULT_RSTVEC);
 163    set_feature(env, RISCV_FEATURE_MMU);
 164}
 165
 166static void rv64imacu_nommu_cpu_init(Object *obj)
 167{
 168    CPURISCVState *env = &RISCV_CPU(obj)->env;
 169    set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
 170    set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
 171    set_resetvec(env, DEFAULT_RSTVEC);
 172}
 173
 174#endif
 175
 176static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
 177{
 178    ObjectClass *oc;
 179    char *typename;
 180    char **cpuname;
 181
 182    cpuname = g_strsplit(cpu_model, ",", 1);
 183    typename = g_strdup_printf(RISCV_CPU_TYPE_NAME("%s"), cpuname[0]);
 184    oc = object_class_by_name(typename);
 185    g_strfreev(cpuname);
 186    g_free(typename);
 187    if (!oc || !object_class_dynamic_cast(oc, TYPE_RISCV_CPU) ||
 188        object_class_is_abstract(oc)) {
 189        return NULL;
 190    }
 191    return oc;
 192}
 193
 194static void riscv_cpu_dump_state(CPUState *cs, FILE *f,
 195    fprintf_function cpu_fprintf, int flags)
 196{
 197    RISCVCPU *cpu = RISCV_CPU(cs);
 198    CPURISCVState *env = &cpu->env;
 199    int i;
 200
 201    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
 202#ifndef CONFIG_USER_ONLY
 203    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
 204    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
 205    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ",
 206        (target_ulong)atomic_read(&env->mip));
 207    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
 208    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
 209    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
 210    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec   ", env->mtvec);
 211    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc    ", env->mepc);
 212    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause  ", env->mcause);
 213#endif
 214
 215    for (i = 0; i < 32; i++) {
 216        cpu_fprintf(f, " %s " TARGET_FMT_lx,
 217            riscv_int_regnames[i], env->gpr[i]);
 218        if ((i & 3) == 3) {
 219            cpu_fprintf(f, "\n");
 220        }
 221    }
 222    if (flags & CPU_DUMP_FPU) {
 223        for (i = 0; i < 32; i++) {
 224            cpu_fprintf(f, " %s %016" PRIx64,
 225                riscv_fpr_regnames[i], env->fpr[i]);
 226            if ((i & 3) == 3) {
 227                cpu_fprintf(f, "\n");
 228            }
 229        }
 230    }
 231}
 232
 233static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
 234{
 235    RISCVCPU *cpu = RISCV_CPU(cs);
 236    CPURISCVState *env = &cpu->env;
 237    env->pc = value;
 238}
 239
 240static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
 241{
 242    RISCVCPU *cpu = RISCV_CPU(cs);
 243    CPURISCVState *env = &cpu->env;
 244    env->pc = tb->pc;
 245}
 246
 247static bool riscv_cpu_has_work(CPUState *cs)
 248{
 249#ifndef CONFIG_USER_ONLY
 250    RISCVCPU *cpu = RISCV_CPU(cs);
 251    CPURISCVState *env = &cpu->env;
 252    /*
 253     * Definition of the WFI instruction requires it to ignore the privilege
 254     * mode and delegation registers, but respect individual enables
 255     */
 256    return (atomic_read(&env->mip) & env->mie) != 0;
 257#else
 258    return true;
 259#endif
 260}
 261
 262void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
 263                          target_ulong *data)
 264{
 265    env->pc = data[0];
 266}
 267
 268static void riscv_cpu_reset(CPUState *cs)
 269{
 270    RISCVCPU *cpu = RISCV_CPU(cs);
 271    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
 272    CPURISCVState *env = &cpu->env;
 273
 274    mcc->parent_reset(cs);
 275#ifndef CONFIG_USER_ONLY
 276    env->priv = PRV_M;
 277    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
 278    env->mcause = 0;
 279    env->pc = env->resetvec;
 280#endif
 281    cs->exception_index = EXCP_NONE;
 282    set_default_nan_mode(1, &env->fp_status);
 283}
 284
 285static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
 286{
 287#if defined(TARGET_RISCV32)
 288    info->print_insn = print_insn_riscv32;
 289#elif defined(TARGET_RISCV64)
 290    info->print_insn = print_insn_riscv64;
 291#endif
 292}
 293
 294static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 295{
 296    CPUState *cs = CPU(dev);
 297    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
 298    Error *local_err = NULL;
 299
 300    cpu_exec_realizefn(cs, &local_err);
 301    if (local_err != NULL) {
 302        error_propagate(errp, local_err);
 303        return;
 304    }
 305
 306    qemu_init_vcpu(cs);
 307    cpu_reset(cs);
 308
 309    mcc->parent_realize(dev, errp);
 310}
 311
 312static void riscv_cpu_init(Object *obj)
 313{
 314    CPUState *cs = CPU(obj);
 315    RISCVCPU *cpu = RISCV_CPU(obj);
 316
 317    cs->env_ptr = &cpu->env;
 318}
 319
 320static const VMStateDescription vmstate_riscv_cpu = {
 321    .name = "cpu",
 322    .unmigratable = 1,
 323};
 324
 325static void riscv_cpu_class_init(ObjectClass *c, void *data)
 326{
 327    RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
 328    CPUClass *cc = CPU_CLASS(c);
 329    DeviceClass *dc = DEVICE_CLASS(c);
 330
 331    mcc->parent_realize = dc->realize;
 332    dc->realize = riscv_cpu_realize;
 333
 334    mcc->parent_reset = cc->reset;
 335    cc->reset = riscv_cpu_reset;
 336
 337    cc->class_by_name = riscv_cpu_class_by_name;
 338    cc->has_work = riscv_cpu_has_work;
 339    cc->do_interrupt = riscv_cpu_do_interrupt;
 340    cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
 341    cc->dump_state = riscv_cpu_dump_state;
 342    cc->set_pc = riscv_cpu_set_pc;
 343    cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
 344    cc->gdb_read_register = riscv_cpu_gdb_read_register;
 345    cc->gdb_write_register = riscv_cpu_gdb_write_register;
 346    cc->gdb_num_core_regs = 65;
 347    cc->gdb_stop_before_watchpoint = true;
 348    cc->disas_set_info = riscv_cpu_disas_set_info;
 349#ifdef CONFIG_USER_ONLY
 350    cc->handle_mmu_fault = riscv_cpu_handle_mmu_fault;
 351#else
 352    cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
 353    cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
 354#endif
 355#ifdef CONFIG_TCG
 356    cc->tcg_initialize = riscv_translate_init;
 357#endif
 358    /* For now, mark unmigratable: */
 359    cc->vmsd = &vmstate_riscv_cpu;
 360}
 361
 362char *riscv_isa_string(RISCVCPU *cpu)
 363{
 364    int i;
 365    const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1;
 366    char *isa_str = g_new(char, maxlen);
 367    char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS);
 368    for (i = 0; i < sizeof(riscv_exts); i++) {
 369        if (cpu->env.misa & RV(riscv_exts[i])) {
 370            *p++ = qemu_tolower(riscv_exts[i]);
 371        }
 372    }
 373    *p = '\0';
 374    return isa_str;
 375}
 376
 377typedef struct RISCVCPUListState {
 378    fprintf_function cpu_fprintf;
 379    FILE *file;
 380} RISCVCPUListState;
 381
 382static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b)
 383{
 384    ObjectClass *class_a = (ObjectClass *)a;
 385    ObjectClass *class_b = (ObjectClass *)b;
 386    const char *name_a, *name_b;
 387
 388    name_a = object_class_get_name(class_a);
 389    name_b = object_class_get_name(class_b);
 390    return strcmp(name_a, name_b);
 391}
 392
 393static void riscv_cpu_list_entry(gpointer data, gpointer user_data)
 394{
 395    RISCVCPUListState *s = user_data;
 396    const char *typename = object_class_get_name(OBJECT_CLASS(data));
 397    int len = strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX);
 398
 399    (*s->cpu_fprintf)(s->file, "%.*s\n", len, typename);
 400}
 401
 402void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 403{
 404    RISCVCPUListState s = {
 405        .cpu_fprintf = cpu_fprintf,
 406        .file = f,
 407    };
 408    GSList *list;
 409
 410    list = object_class_get_list(TYPE_RISCV_CPU, false);
 411    list = g_slist_sort(list, riscv_cpu_list_compare);
 412    g_slist_foreach(list, riscv_cpu_list_entry, &s);
 413    g_slist_free(list);
 414}
 415
 416#define DEFINE_CPU(type_name, initfn)      \
 417    {                                      \
 418        .name = type_name,                 \
 419        .parent = TYPE_RISCV_CPU,          \
 420        .instance_init = initfn            \
 421    }
 422
 423static const TypeInfo riscv_cpu_type_infos[] = {
 424    {
 425        .name = TYPE_RISCV_CPU,
 426        .parent = TYPE_CPU,
 427        .instance_size = sizeof(RISCVCPU),
 428        .instance_init = riscv_cpu_init,
 429        .abstract = true,
 430        .class_size = sizeof(RISCVCPUClass),
 431        .class_init = riscv_cpu_class_init,
 432    },
 433    DEFINE_CPU(TYPE_RISCV_CPU_ANY,              riscv_any_cpu_init),
 434#if defined(TARGET_RISCV32)
 435    DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
 436    DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init),
 437    DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU,  rv32imacu_nommu_cpu_init),
 438    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31,       rv32imacu_nommu_cpu_init),
 439    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34,       rv32gcsu_priv1_10_0_cpu_init)
 440#elif defined(TARGET_RISCV64)
 441    DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
 442    DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init),
 443    DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU,  rv64imacu_nommu_cpu_init),
 444    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51,       rv64imacu_nommu_cpu_init),
 445    DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54,       rv64gcsu_priv1_10_0_cpu_init)
 446#endif
 447};
 448
 449DEFINE_TYPES(riscv_cpu_type_infos)
 450