]> git.proxmox.com Git - mirror_qemu.git/blame - target/riscv/cpu.c
target/riscv: Create settable CPU properties
[mirror_qemu.git] / target / riscv / cpu.c
CommitLineData
dc5bd18f
MC
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"
0442428a 21#include "qemu/qemu-print.h"
dc5bd18f
MC
22#include "qemu/log.h"
23#include "cpu.h"
24#include "exec/exec-all.h"
25#include "qapi/error.h"
c4e95030 26#include "hw/qdev-properties.h"
dc5bd18f
MC
27#include "migration/vmstate.h"
28
29/* RISC-V CPU definitions */
30
79f86934 31static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
dc5bd18f
MC
32
33const char * const riscv_int_regnames[] = {
7f9188e2
RH
34 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
35 "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
36 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
37 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
dc5bd18f
MC
38};
39
40const char * const riscv_fpr_regnames[] = {
7f9188e2
RH
41 "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
42 "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
43 "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
44 "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
dc5bd18f
MC
45};
46
47const char * const riscv_excp_names[] = {
48 "misaligned_fetch",
49 "fault_fetch",
50 "illegal_instruction",
51 "breakpoint",
52 "misaligned_load",
53 "fault_load",
54 "misaligned_store",
55 "fault_store",
56 "user_ecall",
57 "supervisor_ecall",
58 "hypervisor_ecall",
59 "machine_ecall",
60 "exec_page_fault",
61 "load_page_fault",
62 "reserved",
63 "store_page_fault"
64};
65
66const char * const riscv_intr_names[] = {
67 "u_software",
68 "s_software",
69 "h_software",
70 "m_software",
71 "u_timer",
72 "s_timer",
73 "h_timer",
74 "m_timer",
75 "u_external",
76 "s_external",
77 "h_external",
78 "m_external",
426f0348
MC
79 "reserved",
80 "reserved",
81 "reserved",
82 "reserved"
dc5bd18f
MC
83};
84
dc5bd18f
MC
85static void set_misa(CPURISCVState *env, target_ulong misa)
86{
f18637cd 87 env->misa_mask = env->misa = misa;
dc5bd18f
MC
88}
89
90static void set_versions(CPURISCVState *env, int user_ver, int priv_ver)
91{
92 env->user_ver = user_ver;
93 env->priv_ver = priv_ver;
94}
95
96static void set_feature(CPURISCVState *env, int feature)
97{
98 env->features |= (1ULL << feature);
99}
100
101static void set_resetvec(CPURISCVState *env, int resetvec)
102{
103#ifndef CONFIG_USER_ONLY
104 env->resetvec = resetvec;
105#endif
106}
107
108static void riscv_any_cpu_init(Object *obj)
109{
110 CPURISCVState *env = &RISCV_CPU(obj)->env;
111 set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
112 set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
113 set_resetvec(env, DEFAULT_RSTVEC);
114}
115
eab15862
MC
116#if defined(TARGET_RISCV32)
117
dc5bd18f
MC
118static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
119{
120 CPURISCVState *env = &RISCV_CPU(obj)->env;
121 set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
122 set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
123 set_resetvec(env, DEFAULT_RSTVEC);
124 set_feature(env, RISCV_FEATURE_MMU);
a88365c1 125 set_feature(env, RISCV_FEATURE_PMP);
dc5bd18f
MC
126}
127
128static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
129{
130 CPURISCVState *env = &RISCV_CPU(obj)->env;
131 set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
132 set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
133 set_resetvec(env, DEFAULT_RSTVEC);
134 set_feature(env, RISCV_FEATURE_MMU);
a88365c1 135 set_feature(env, RISCV_FEATURE_PMP);
dc5bd18f
MC
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);
a88365c1 144 set_feature(env, RISCV_FEATURE_PMP);
dc5bd18f
MC
145}
146
eab15862
MC
147#elif defined(TARGET_RISCV64)
148
dc5bd18f
MC
149static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
150{
151 CPURISCVState *env = &RISCV_CPU(obj)->env;
152 set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
153 set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
154 set_resetvec(env, DEFAULT_RSTVEC);
155 set_feature(env, RISCV_FEATURE_MMU);
a88365c1 156 set_feature(env, RISCV_FEATURE_PMP);
dc5bd18f
MC
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);
a88365c1 166 set_feature(env, RISCV_FEATURE_PMP);
dc5bd18f
MC
167}
168
169static void rv64imacu_nommu_cpu_init(Object *obj)
170{
171 CPURISCVState *env = &RISCV_CPU(obj)->env;
172 set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
173 set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
174 set_resetvec(env, DEFAULT_RSTVEC);
a88365c1 175 set_feature(env, RISCV_FEATURE_PMP);
dc5bd18f
MC
176}
177
eab15862 178#endif
dc5bd18f
MC
179
180static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
181{
182 ObjectClass *oc;
183 char *typename;
184 char **cpuname;
185
186 cpuname = g_strsplit(cpu_model, ",", 1);
187 typename = g_strdup_printf(RISCV_CPU_TYPE_NAME("%s"), cpuname[0]);
188 oc = object_class_by_name(typename);
189 g_strfreev(cpuname);
190 g_free(typename);
191 if (!oc || !object_class_dynamic_cast(oc, TYPE_RISCV_CPU) ||
192 object_class_is_abstract(oc)) {
193 return NULL;
194 }
195 return oc;
196}
197
90c84c56 198static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
dc5bd18f
MC
199{
200 RISCVCPU *cpu = RISCV_CPU(cs);
201 CPURISCVState *env = &cpu->env;
202 int i;
203
90c84c56 204 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc);
dc5bd18f 205#ifndef CONFIG_USER_ONLY
90c84c56
MA
206 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
207 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
208 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ",
209 (target_ulong)atomic_read(&env->mip));
210 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie);
211 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
212 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
213 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec);
214 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc);
215 qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause);
dc5bd18f
MC
216#endif
217
218 for (i = 0; i < 32; i++) {
90c84c56
MA
219 qemu_fprintf(f, " %s " TARGET_FMT_lx,
220 riscv_int_regnames[i], env->gpr[i]);
dc5bd18f 221 if ((i & 3) == 3) {
90c84c56 222 qemu_fprintf(f, "\n");
dc5bd18f
MC
223 }
224 }
86ea1880
RH
225 if (flags & CPU_DUMP_FPU) {
226 for (i = 0; i < 32; i++) {
90c84c56
MA
227 qemu_fprintf(f, " %s %016" PRIx64,
228 riscv_fpr_regnames[i], env->fpr[i]);
86ea1880 229 if ((i & 3) == 3) {
90c84c56 230 qemu_fprintf(f, "\n");
86ea1880 231 }
dc5bd18f
MC
232 }
233 }
234}
235
236static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
237{
238 RISCVCPU *cpu = RISCV_CPU(cs);
239 CPURISCVState *env = &cpu->env;
240 env->pc = value;
241}
242
243static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
244{
245 RISCVCPU *cpu = RISCV_CPU(cs);
246 CPURISCVState *env = &cpu->env;
247 env->pc = tb->pc;
248}
249
250static bool riscv_cpu_has_work(CPUState *cs)
251{
252#ifndef CONFIG_USER_ONLY
253 RISCVCPU *cpu = RISCV_CPU(cs);
254 CPURISCVState *env = &cpu->env;
255 /*
256 * Definition of the WFI instruction requires it to ignore the privilege
257 * mode and delegation registers, but respect individual enables
258 */
259 return (atomic_read(&env->mip) & env->mie) != 0;
260#else
261 return true;
262#endif
263}
264
265void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
266 target_ulong *data)
267{
268 env->pc = data[0];
269}
270
271static void riscv_cpu_reset(CPUState *cs)
272{
273 RISCVCPU *cpu = RISCV_CPU(cs);
274 RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
275 CPURISCVState *env = &cpu->env;
276
277 mcc->parent_reset(cs);
278#ifndef CONFIG_USER_ONLY
279 env->priv = PRV_M;
280 env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
281 env->mcause = 0;
282 env->pc = env->resetvec;
283#endif
284 cs->exception_index = EXCP_NONE;
285 set_default_nan_mode(1, &env->fp_status);
286}
287
288static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
289{
290#if defined(TARGET_RISCV32)
291 info->print_insn = print_insn_riscv32;
292#elif defined(TARGET_RISCV64)
293 info->print_insn = print_insn_riscv64;
294#endif
295}
296
297static void riscv_cpu_realize(DeviceState *dev, Error **errp)
298{
299 CPUState *cs = CPU(dev);
c4e95030
AF
300 RISCVCPU *cpu = RISCV_CPU(dev);
301 CPURISCVState *env = &cpu->env;
dc5bd18f 302 RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
c4e95030
AF
303 int priv_version = PRIV_VERSION_1_10_0;
304 int user_version = USER_VERSION_2_02_0;
dc5bd18f
MC
305 Error *local_err = NULL;
306
307 cpu_exec_realizefn(cs, &local_err);
308 if (local_err != NULL) {
309 error_propagate(errp, local_err);
310 return;
311 }
312
c4e95030
AF
313 if (cpu->cfg.priv_spec) {
314 if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
315 priv_version = PRIV_VERSION_1_10_0;
316 } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) {
317 priv_version = PRIV_VERSION_1_09_1;
318 } else {
319 error_setg(errp,
320 "Unsupported privilege spec version '%s'",
321 cpu->cfg.priv_spec);
322 return;
323 }
324 }
325
326 if (cpu->cfg.user_spec) {
327 if (!g_strcmp0(cpu->cfg.user_spec, "v2.02.0")) {
328 user_version = USER_VERSION_2_02_0;
329 } else {
330 error_setg(errp,
331 "Unsupported user spec version '%s'",
332 cpu->cfg.user_spec);
333 return;
334 }
335 }
336
337 set_versions(env, user_version, priv_version);
338 set_resetvec(env, DEFAULT_RSTVEC);
339
340 if (cpu->cfg.mmu) {
341 set_feature(env, RISCV_FEATURE_MMU);
342 }
343
344 if (cpu->cfg.pmp) {
345 set_feature(env, RISCV_FEATURE_PMP);
346 }
347
5371f5cd
JW
348 riscv_cpu_register_gdb_regs_for_features(cs);
349
dc5bd18f
MC
350 qemu_init_vcpu(cs);
351 cpu_reset(cs);
352
353 mcc->parent_realize(dev, errp);
354}
355
356static void riscv_cpu_init(Object *obj)
357{
358 CPUState *cs = CPU(obj);
359 RISCVCPU *cpu = RISCV_CPU(obj);
360
361 cs->env_ptr = &cpu->env;
362}
363
364static const VMStateDescription vmstate_riscv_cpu = {
365 .name = "cpu",
366 .unmigratable = 1,
367};
368
c4e95030
AF
369static Property riscv_cpu_properties[] = {
370 DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
371 DEFINE_PROP_STRING("user_spec", RISCVCPU, cfg.user_spec),
372 DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
373 DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
374 DEFINE_PROP_END_OF_LIST(),
375};
376
dc5bd18f
MC
377static void riscv_cpu_class_init(ObjectClass *c, void *data)
378{
379 RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
380 CPUClass *cc = CPU_CLASS(c);
381 DeviceClass *dc = DEVICE_CLASS(c);
382
41fbbba7
MZ
383 device_class_set_parent_realize(dc, riscv_cpu_realize,
384 &mcc->parent_realize);
dc5bd18f
MC
385
386 mcc->parent_reset = cc->reset;
387 cc->reset = riscv_cpu_reset;
388
389 cc->class_by_name = riscv_cpu_class_by_name;
390 cc->has_work = riscv_cpu_has_work;
391 cc->do_interrupt = riscv_cpu_do_interrupt;
392 cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
393 cc->dump_state = riscv_cpu_dump_state;
394 cc->set_pc = riscv_cpu_set_pc;
395 cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
396 cc->gdb_read_register = riscv_cpu_gdb_read_register;
397 cc->gdb_write_register = riscv_cpu_gdb_write_register;
5371f5cd
JW
398 cc->gdb_num_core_regs = 33;
399#if defined(TARGET_RISCV32)
400 cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
401#elif defined(TARGET_RISCV64)
402 cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
403#endif
dc5bd18f
MC
404 cc->gdb_stop_before_watchpoint = true;
405 cc->disas_set_info = riscv_cpu_disas_set_info;
8a4ca3c1 406#ifndef CONFIG_USER_ONLY
dc5bd18f
MC
407 cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
408 cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
409#endif
410#ifdef CONFIG_TCG
411 cc->tcg_initialize = riscv_translate_init;
8a4ca3c1 412 cc->tlb_fill = riscv_cpu_tlb_fill;
dc5bd18f
MC
413#endif
414 /* For now, mark unmigratable: */
415 cc->vmsd = &vmstate_riscv_cpu;
c4e95030 416 dc->props = riscv_cpu_properties;
dc5bd18f
MC
417}
418
dc5bd18f
MC
419char *riscv_isa_string(RISCVCPU *cpu)
420{
421 int i;
d1fd31f8
MC
422 const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1;
423 char *isa_str = g_new(char, maxlen);
424 char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS);
dc5bd18f
MC
425 for (i = 0; i < sizeof(riscv_exts); i++) {
426 if (cpu->env.misa & RV(riscv_exts[i])) {
d1fd31f8 427 *p++ = qemu_tolower(riscv_exts[i]);
dc5bd18f
MC
428 }
429 }
d1fd31f8
MC
430 *p = '\0';
431 return isa_str;
dc5bd18f
MC
432}
433
eab15862 434static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b)
dc5bd18f 435{
eab15862
MC
436 ObjectClass *class_a = (ObjectClass *)a;
437 ObjectClass *class_b = (ObjectClass *)b;
438 const char *name_a, *name_b;
dc5bd18f 439
eab15862
MC
440 name_a = object_class_get_name(class_a);
441 name_b = object_class_get_name(class_b);
442 return strcmp(name_a, name_b);
dc5bd18f
MC
443}
444
eab15862 445static void riscv_cpu_list_entry(gpointer data, gpointer user_data)
dc5bd18f 446{
eab15862
MC
447 const char *typename = object_class_get_name(OBJECT_CLASS(data));
448 int len = strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX);
dc5bd18f 449
0442428a 450 qemu_printf("%.*s\n", len, typename);
eab15862 451}
dc5bd18f 452
0442428a 453void riscv_cpu_list(void)
eab15862 454{
eab15862
MC
455 GSList *list;
456
457 list = object_class_get_list(TYPE_RISCV_CPU, false);
458 list = g_slist_sort(list, riscv_cpu_list_compare);
0442428a 459 g_slist_foreach(list, riscv_cpu_list_entry, NULL);
eab15862 460 g_slist_free(list);
dc5bd18f
MC
461}
462
eab15862
MC
463#define DEFINE_CPU(type_name, initfn) \
464 { \
465 .name = type_name, \
466 .parent = TYPE_RISCV_CPU, \
467 .instance_init = initfn \
468 }
469
470static const TypeInfo riscv_cpu_type_infos[] = {
471 {
472 .name = TYPE_RISCV_CPU,
473 .parent = TYPE_CPU,
474 .instance_size = sizeof(RISCVCPU),
475 .instance_init = riscv_cpu_init,
476 .abstract = true,
477 .class_size = sizeof(RISCVCPUClass),
478 .class_init = riscv_cpu_class_init,
479 },
480 DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
481#if defined(TARGET_RISCV32)
482 DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
483 DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init),
484 DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init),
485 DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init),
486 DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init)
487#elif defined(TARGET_RISCV64)
488 DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
489 DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init),
490 DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init),
491 DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init),
492 DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init)
493#endif
494};
495
496DEFINE_TYPES(riscv_cpu_type_infos)