Second RISC-V PR for 8.2

* Add support for the max CPU
  * Detect user choice in TCG
  * Clear CSR values at reset and sync MPSTATE with host
  * Fix the typo of inverted order of pmpaddr13 and pmpaddr14
  * Split TCG/KVM accelerators from cpu.c
  * Add extension properties for all cpus
  * Replace GDB exit calls with proper shutdown
  * Support KVM_GET_REG_LIST
  * Remove RVG warning
  * Use env_archcpu for better performance
  * Deprecate capital 'Z' CPU properties
  * Fix vfwmaccbf16.vf
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmUncYAACgkQr3yVEwxT
 gBPQ3g/9Fi4uYRK7dymHHAQbOO9NPlmVPPSxmQ8fNUhoZUkbHfm56JEl42Xr02rA
 Lg2ORRQxJhAinANV8CotnbyLRHNCAvouCMCQEjHo1YEHzdXc0tQzp+rIOHT7v9rH
 6OQpI6RuCjO+0LQPMgzJx8yokMw/9b0uma3+RkNKod1XsSySo6JvDkMZGGZZWuVX
 Que3TMHzc4513PWEwRS9NaAHqRdy/ax0aPu9khswTYBxeJ/mBTLvGj4wBq5wnS7+
 JPvq0M5ScUMl4K5o884wsAzOdxRk8QZOMx3duMCbqXw0xFmYZj/EzcIeHdnXwuDB
 lcANd6LcESMNUb8iDBaFRjLnZ/gNiu20/P/LPWyTirfoZXzZ+h6WPnSeli36xtzO
 KKWtvS1YggCjsDvh9/PLYAvUGBcS/kUhIynN10YKnoKB+wSDxxyvBS1GU6c8czgc
 WDf3V4P3Z8oPKDA/24Qd9Uiho1Gq9FED4eBQPb9PuvkfboKE/g7lUp708XXDFVld
 hkJMsYROSRvk54RHITrD9Z+XFQ2TfC8wHLH0IwlyynQnc1sKvXaR6U1hZTAVtE4f
 yley/xCQ7OUV+hrx1sQLURcN6A+SPummOY5jdHiD29QcJnOZnkSy5j2KOlnHSa5i
 6v/6EFCgxwr69N6Q6X34VDv6+DZqLO2dNncQCInYFfupRhQ7t1E=
 =SUon
 -----END PGP SIGNATURE-----

Merge tag 'pull-riscv-to-apply-20231012-1' of https://github.com/alistair23/qemu into staging

Second RISC-V PR for 8.2

 * Add support for the max CPU
 * Detect user choice in TCG
 * Clear CSR values at reset and sync MPSTATE with host
 * Fix the typo of inverted order of pmpaddr13 and pmpaddr14
 * Split TCG/KVM accelerators from cpu.c
 * Add extension properties for all cpus
 * Replace GDB exit calls with proper shutdown
 * Support KVM_GET_REG_LIST
 * Remove RVG warning
 * Use env_archcpu for better performance
 * Deprecate capital 'Z' CPU properties
 * Fix vfwmaccbf16.vf

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmUncYAACgkQr3yVEwxT
# gBPQ3g/9Fi4uYRK7dymHHAQbOO9NPlmVPPSxmQ8fNUhoZUkbHfm56JEl42Xr02rA
# Lg2ORRQxJhAinANV8CotnbyLRHNCAvouCMCQEjHo1YEHzdXc0tQzp+rIOHT7v9rH
# 6OQpI6RuCjO+0LQPMgzJx8yokMw/9b0uma3+RkNKod1XsSySo6JvDkMZGGZZWuVX
# Que3TMHzc4513PWEwRS9NaAHqRdy/ax0aPu9khswTYBxeJ/mBTLvGj4wBq5wnS7+
# JPvq0M5ScUMl4K5o884wsAzOdxRk8QZOMx3duMCbqXw0xFmYZj/EzcIeHdnXwuDB
# lcANd6LcESMNUb8iDBaFRjLnZ/gNiu20/P/LPWyTirfoZXzZ+h6WPnSeli36xtzO
# KKWtvS1YggCjsDvh9/PLYAvUGBcS/kUhIynN10YKnoKB+wSDxxyvBS1GU6c8czgc
# WDf3V4P3Z8oPKDA/24Qd9Uiho1Gq9FED4eBQPb9PuvkfboKE/g7lUp708XXDFVld
# hkJMsYROSRvk54RHITrD9Z+XFQ2TfC8wHLH0IwlyynQnc1sKvXaR6U1hZTAVtE4f
# yley/xCQ7OUV+hrx1sQLURcN6A+SPummOY5jdHiD29QcJnOZnkSy5j2KOlnHSa5i
# 6v/6EFCgxwr69N6Q6X34VDv6+DZqLO2dNncQCInYFfupRhQ7t1E=
# =SUon
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 12 Oct 2023 00:09:36 EDT
# gpg:                using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6AE9 02B6 A7CA 877D 6D65  9296 AF7C 9513 0C53 8013

* tag 'pull-riscv-to-apply-20231012-1' of https://github.com/alistair23/qemu: (54 commits)
  target/riscv: Fix vfwmaccbf16.vf
  target/riscv: deprecate capital 'Z' CPU properties
  target/riscv: Use env_archcpu for better performance
  target/riscv/tcg: remove RVG warning
  target/riscv/kvm: support KVM_GET_REG_LIST
  target/riscv/kvm: improve 'init_multiext_cfg' error msg
  gdbstub: replace exit calls with proper shutdown for softmmu
  hw/char: riscv_htif: replace exit calls with proper shutdown
  hw/misc/sifive_test.c: replace exit calls with proper shutdown
  softmmu: pass the main loop status to gdb "Wxx" packet
  softmmu: add means to pass an exit code when requesting a shutdown
  target/riscv/tcg-cpu.c: add extension properties for all cpus
  target/riscv: add riscv_cpu_get_name()
  target/riscv/cpu: move priv spec functions to tcg-cpu.c
  target/riscv/cpu.c: export isa_edata_arr[]
  target/riscv/tcg: move riscv_cpu_add_misa_properties() to tcg-cpu.c
  target/riscv/cpu.c: make misa_ext_cfgs[] 'const'
  target/riscv/tcg: introduce tcg_cpu_instance_init()
  target/riscv/cpu.c: export set_misa()
  target/riscv/kvm: do not use riscv_cpu_add_misa_properties()
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2023-10-12 10:24:44 -04:00
commit 63011373ad
29 changed files with 1606 additions and 893 deletions

View file

@ -2116,8 +2116,8 @@ static const char *csr_name(int csrno)
case 0x03ba: return "pmpaddr10";
case 0x03bb: return "pmpaddr11";
case 0x03bc: return "pmpaddr12";
case 0x03bd: return "pmpaddr14";
case 0x03be: return "pmpaddr13";
case 0x03bd: return "pmpaddr13";
case 0x03be: return "pmpaddr14";
case 0x03bf: return "pmpaddr15";
case 0x0780: return "mtohost";
case 0x0781: return "mfromhost";

View file

@ -327,6 +327,41 @@ QEMU's ``vhost`` feature, which would eliminate the high latency costs under
which the 9p ``proxy`` backend currently suffers. However as of to date nobody
has indicated plans for such kind of reimplementation unfortunately.
RISC-V 'any' CPU type ``-cpu any`` (since 8.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The 'any' CPU type was introduced back in 2018 and has been around since the
initial RISC-V QEMU port. Its usage has always been unclear: users don't know
what to expect from a CPU called 'any', and in fact the CPU does not do anything
special that isn't already done by the default CPUs rv32/rv64.
After the introduction of the 'max' CPU type, RISC-V now has a good coverage
of generic CPUs: rv32 and rv64 as default CPUs and 'max' as a feature complete
CPU for both 32 and 64 bit builds. Users are then discouraged to use the 'any'
CPU type starting in 8.2.
RISC-V CPU properties which start with capital 'Z' (since 8.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All RISC-V CPU properties which start with capital 'Z' are being deprecated
starting in 8.2. The reason is that they were wrongly added with capital 'Z'
in the past. CPU properties were later added with lower-case names, which
is the format we want to use from now on.
Users which try to use these deprecated properties will receive a warning
recommending to switch to their stable counterparts:
- "Zifencei" should be replaced with "zifencei"
- "Zicsr" should be replaced with "zicsr"
- "Zihintntl" should be replaced with "zihintntl"
- "Zihintpause" should be replaced with "zihintpause"
- "Zawrs" should be replaced with "zawrs"
- "Zfa" should be replaced with "zfa"
- "Zfh" should be replaced with "zfh"
- "Zfhmin" should be replaced with "zfhmin"
- "Zve32f" should be replaced with "zve32f"
- "Zve64f" should be replaced with "zve64f"
- "Zve64d" should be replaced with "zve64d"
Block device options
''''''''''''''''''''

View file

@ -1324,7 +1324,7 @@ static void handle_v_kill(GArray *params, void *user_ctx)
gdb_put_packet("OK");
error_report("QEMU: Terminated via GDBstub");
gdb_exit(0);
exit(0);
gdb_qemu_exit(0);
}
static const GdbCmdParseEntry gdb_v_commands_table[] = {
@ -1843,7 +1843,8 @@ static int gdb_handle_packet(const char *line_buf)
/* Kill the target */
error_report("QEMU: Terminated via GDBstub");
gdb_exit(0);
exit(0);
gdb_qemu_exit(0);
break;
case 'D':
{
static const GdbCmdParseEntry detach_cmd_desc = {

View file

@ -435,6 +435,12 @@ void gdb_exit(int code)
qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
}
void gdb_qemu_exit(int code)
{
qemu_system_shutdown_request_with_code(SHUTDOWN_CAUSE_GUEST_SHUTDOWN,
code);
}
/*
* Memory access
*/

View file

@ -113,6 +113,12 @@ void gdb_exit(int code)
gdb_put_packet(buf);
gdbserver_state.allow_stop_reply = false;
}
}
void gdb_qemu_exit(int code)
{
exit(code);
}
int gdb_handlesig(CPUState *cpu, int sig)

View file

@ -32,6 +32,7 @@
#include "exec/address-spaces.h"
#include "exec/tswap.h"
#include "sysemu/dma.h"
#include "sysemu/runstate.h"
#define RISCV_DEBUG_HTIF 0
#define HTIF_DEBUG(fmt, ...) \
@ -206,7 +207,9 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
g_free(sig_data);
}
exit(exit_code);
qemu_system_shutdown_request_with_code(
SHUTDOWN_CAUSE_GUEST_SHUTDOWN, exit_code);
return;
} else {
uint64_t syscall[8];
cpu_physical_memory_read(payload, syscall, sizeof(syscall));

View file

@ -32,7 +32,7 @@
#include "target/riscv/cpu.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "kvm_riscv.h"
#include "kvm/kvm_riscv.h"
#include "migration/vmstate.h"
#define APLIC_MAX_IDC (1UL << 14)

View file

@ -25,6 +25,7 @@
#include "qemu/module.h"
#include "sysemu/runstate.h"
#include "hw/misc/sifive_test.h"
#include "sysemu/sysemu.h"
static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size)
{
@ -39,9 +40,13 @@ static void sifive_test_write(void *opaque, hwaddr addr,
int code = (val64 >> 16) & 0xffff;
switch (status) {
case FINISHER_FAIL:
exit(code);
qemu_system_shutdown_request_with_code(
SHUTDOWN_CAUSE_GUEST_PANIC, code);
return;
case FINISHER_PASS:
exit(0);
qemu_system_shutdown_request_with_code(
SHUTDOWN_CAUSE_GUEST_SHUTDOWN, code);
return;
case FINISHER_RESET:
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
return;

View file

@ -35,7 +35,7 @@
#include "hw/riscv/virt.h"
#include "hw/riscv/boot.h"
#include "hw/riscv/numa.h"
#include "kvm_riscv.h"
#include "kvm/kvm_riscv.h"
#include "hw/intc/riscv_aclint.h"
#include "hw/intc/riscv_aplic.h"
#include "hw/intc/riscv_imsic.h"

View file

@ -110,4 +110,13 @@ int use_gdb_syscalls(void);
*/
void gdb_exit(int code);
/**
* gdb_qemu_exit: ask qemu to exit
* @code: exit code reported
*
* This requests qemu to exit. This function is allowed to return as
* the exit request might be processed asynchronously by qemu backend.
*/
void gdb_qemu_exit(int code);
#endif /* _SYSCALLS_H_ */

View file

@ -68,6 +68,8 @@ void qemu_system_wakeup_request(WakeupReason reason, Error **errp);
void qemu_system_wakeup_enable(WakeupReason reason, bool enabled);
void qemu_register_wakeup_notifier(Notifier *notifier);
void qemu_register_wakeup_support(void);
void qemu_system_shutdown_request_with_code(ShutdownCause reason,
int exit_code);
void qemu_system_shutdown_request(ShutdownCause reason);
void qemu_system_powerdown_request(void);
void qemu_register_powerdown_notifier(Notifier *notifier);

View file

@ -101,7 +101,7 @@ bool defaults_enabled(void);
void qemu_init(int argc, char **argv);
int qemu_main_loop(void);
void qemu_cleanup(void);
void qemu_cleanup(int);
extern QemuOptsList qemu_legacy_drive_opts;
extern QemuOptsList qemu_common_drive_opts;

View file

@ -35,7 +35,7 @@ int qemu_default_main(void)
int status;
status = qemu_main_loop();
qemu_cleanup();
qemu_cleanup(status);
return status;
}

View file

@ -385,6 +385,7 @@ void vm_state_notify(bool running, RunState state)
static ShutdownCause reset_requested;
static ShutdownCause shutdown_requested;
static int shutdown_exit_code = EXIT_SUCCESS;
static int shutdown_signal;
static pid_t shutdown_pid;
static int powerdown_requested;
@ -664,6 +665,13 @@ void qemu_system_killed(int signal, pid_t pid)
qemu_notify_event();
}
void qemu_system_shutdown_request_with_code(ShutdownCause reason,
int exit_code)
{
shutdown_exit_code = exit_code;
qemu_system_shutdown_request(reason);
}
void qemu_system_shutdown_request(ShutdownCause reason)
{
trace_qemu_system_shutdown_request(reason);
@ -725,7 +733,9 @@ static bool main_loop_should_exit(int *status)
if (shutdown_action == SHUTDOWN_ACTION_PAUSE) {
vm_stop(RUN_STATE_SHUTDOWN);
} else {
if (request == SHUTDOWN_CAUSE_GUEST_PANIC &&
if (shutdown_exit_code != EXIT_SUCCESS) {
*status = shutdown_exit_code;
} else if (request == SHUTDOWN_CAUSE_GUEST_PANIC &&
panic_action == PANIC_ACTION_EXIT_FAILURE) {
*status = EXIT_FAILURE;
}
@ -824,9 +834,9 @@ void qemu_init_subsystems(void)
}
void qemu_cleanup(void)
void qemu_cleanup(int status)
{
gdb_exit(0);
gdb_exit(status);
/*
* cleaning up the migration object cancels any existing migration

View file

@ -30,6 +30,7 @@
#define CPU_RESOLVING_TYPE TYPE_RISCV_CPU
#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
#define TYPE_RISCV_CPU_MAX RISCV_CPU_TYPE_NAME("max")
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
#define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128")

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,7 @@
#include "hw/core/cpu.h"
#include "hw/registerfields.h"
#include "hw/qdev-properties.h"
#include "exec/cpu-defs.h"
#include "qemu/cpu-float.h"
#include "qom/object.h"
@ -42,7 +43,7 @@
#define RV(x) ((target_ulong)1 << (x - 'A'))
/*
* Consider updating misa_ext_info_arr[] and misa_ext_cfgs[]
* Update misa_bits[], misa_ext_info_arr[] and misa_ext_cfgs[]
* when adding new MISA bits here.
*/
#define RVI RV('I')
@ -59,9 +60,12 @@
#define RVJ RV('J')
#define RVG RV('G')
extern const uint32_t misa_bits[];
const char *riscv_get_misa_ext_name(uint32_t bit);
const char *riscv_get_misa_ext_description(uint32_t bit);
#define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
/* Privileged specification version */
enum {
PRIV_VERSION_1_10_0 = 0,
@ -443,7 +447,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
bool probe, uintptr_t retaddr);
char *riscv_isa_string(RISCVCPU *cpu);
void riscv_cpu_list(void);
void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
#define cpu_list riscv_cpu_list
#define cpu_mmu_index riscv_cpu_mmu_index
@ -705,6 +708,33 @@ enum riscv_pmu_event_idx {
RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021,
};
/* used by tcg/tcg-cpu.c*/
void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en);
bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset);
void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext);
typedef struct RISCVCPUMultiExtConfig {
const char *name;
uint32_t offset;
bool enabled;
} RISCVCPUMultiExtConfig;
extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[];
extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[];
extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[];
extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[];
extern Property riscv_cpu_options[];
typedef struct isa_ext_data {
const char *name;
int min_version;
int ext_enable_offset;
} RISCVIsaExtData;
extern const RISCVIsaExtData isa_edata_arr[];
char *riscv_cpu_get_name(RISCVCPU *cpu);
void riscv_add_satp_mode_properties(Object *obj);
/* CSR function table */
extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];

View file

@ -65,8 +65,7 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
uint64_t *cs_base, uint32_t *pflags)
{
CPUState *cs = env_cpu(env);
RISCVCPU *cpu = RISCV_CPU(cs);
RISCVCPU *cpu = env_archcpu(env);
RISCVExtStatus fs, vs;
uint32_t flags = 0;

View file

@ -21,6 +21,7 @@
#include "qemu/log.h"
#include "qemu/timer.h"
#include "cpu.h"
#include "tcg/tcg-cpu.h"
#include "pmu.h"
#include "time_helper.h"
#include "exec/exec-all.h"

View file

@ -1,30 +0,0 @@
/*
* QEMU KVM RISC-V specific function stubs
*
* Copyright (c) 2020 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "kvm_riscv.h"
void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
{
abort();
}
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
{
abort();
}

View file

@ -31,6 +31,7 @@
#include "sysemu/kvm_int.h"
#include "cpu.h"
#include "trace.h"
#include "hw/core/accel-cpu.h"
#include "hw/pci/pci.h"
#include "exec/memattrs.h"
#include "exec/address-spaces.h"
@ -51,6 +52,8 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
kvm_set_irq(kvm_state, irq, !!level);
}
static bool cap_has_mp_state;
static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
uint64_t idx)
{
@ -205,10 +208,8 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs)
}
}
#define CPUCFG(_prop) offsetof(struct RISCVCPUConfig, _prop)
#define KVM_EXT_CFG(_name, _prop, _reg_id) \
{.name = _name, .offset = CPUCFG(_prop), \
{.name = _name, .offset = CPU_CFG_OFFSET(_prop), \
.kvm_reg_id = _reg_id}
static KVMCPUConfig kvm_multi_ext_cfgs[] = {
@ -285,13 +286,13 @@ static void kvm_cpu_set_multi_ext_cfg(Object *obj, Visitor *v,
static KVMCPUConfig kvm_cbom_blocksize = {
.name = "cbom_blocksize",
.offset = CPUCFG(cbom_blocksize),
.offset = CPU_CFG_OFFSET(cbom_blocksize),
.kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicbom_block_size)
};
static KVMCPUConfig kvm_cboz_blocksize = {
.name = "cboz_blocksize",
.offset = CPUCFG(cboz_blocksize),
.offset = CPU_CFG_OFFSET(cboz_blocksize),
.kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicboz_block_size)
};
@ -345,10 +346,58 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
}
}
static void cpu_set_cfg_unavailable(Object *obj, Visitor *v,
const char *name,
void *opaque, Error **errp)
{
const char *propname = opaque;
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
return;
}
if (value) {
error_setg(errp, "extension %s is not available with KVM",
propname);
}
}
static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name)
{
/* Check if KVM created the property already */
if (object_property_find(obj, prop_name)) {
return;
}
/*
* Set the default to disabled for every extension
* unknown to KVM and error out if the user attempts
* to enable any of them.
*/
object_property_add(obj, prop_name, "bool",
NULL, cpu_set_cfg_unavailable,
NULL, (void *)prop_name);
}
static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj,
const RISCVCPUMultiExtConfig *array)
{
const RISCVCPUMultiExtConfig *prop;
g_assert(array);
for (prop = array; prop && prop->name; prop++) {
riscv_cpu_add_kvm_unavail_prop(obj, prop->name);
}
}
static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj)
{
int i;
riscv_add_satp_mode_properties(cpu_obj);
for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) {
KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i];
int bit = misa_cfg->offset;
@ -364,6 +413,11 @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj)
misa_cfg->description);
}
for (i = 0; misa_bits[i] != 0; i++) {
const char *ext_name = riscv_get_misa_ext_name(misa_bits[i]);
riscv_cpu_add_kvm_unavail_prop(cpu_obj, ext_name);
}
for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
KVMCPUConfig *multi_cfg = &kvm_multi_ext_cfgs[i];
@ -380,6 +434,10 @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj)
object_property_add(cpu_obj, "cboz_blocksize", "uint16",
NULL, kvm_cpu_set_cbomz_blksize,
NULL, &kvm_cboz_blocksize);
riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_extensions);
riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_vendor_exts);
riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_experimental_exts);
}
static int kvm_riscv_get_regs_core(CPUState *cs)
@ -713,7 +771,8 @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
}
}
static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
KVMScratchCPU *kvmcpu)
{
CPURISCVState *env = &cpu->env;
uint64_t val;
@ -734,8 +793,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
val = false;
} else {
error_report("Unable to read ISA_EXT KVM register %s, "
"error %d", multi_ext_cfg->name, ret);
kvm_riscv_destroy_scratch_vcpu(kvmcpu);
"error code: %s", multi_ext_cfg->name,
strerrorname_np(errno));
exit(EXIT_FAILURE);
}
} else {
@ -754,7 +813,100 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
}
}
void kvm_riscv_init_user_properties(Object *cpu_obj)
static int uint64_cmp(const void *a, const void *b)
{
uint64_t val1 = *(const uint64_t *)a;
uint64_t val2 = *(const uint64_t *)b;
if (val1 < val2) {
return -1;
}
if (val1 > val2) {
return 1;
}
return 0;
}
static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
{
KVMCPUConfig *multi_ext_cfg;
struct kvm_one_reg reg;
struct kvm_reg_list rl_struct;
struct kvm_reg_list *reglist;
uint64_t val, reg_id, *reg_search;
int i, ret;
rl_struct.n = 0;
ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, &rl_struct);
/*
* If KVM_GET_REG_LIST isn't supported we'll get errno 22
* (EINVAL). Use read_legacy() in this case.
*/
if (errno == EINVAL) {
return kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
} else if (errno != E2BIG) {
/*
* E2BIG is an expected error message for the API since we
* don't know the number of registers. The right amount will
* be written in rl_struct.n.
*
* Error out if we get any other errno.
*/
error_report("Error when accessing get-reg-list, code: %s",
strerrorname_np(errno));
exit(EXIT_FAILURE);
}
reglist = g_malloc(sizeof(struct kvm_reg_list) +
rl_struct.n * sizeof(uint64_t));
reglist->n = rl_struct.n;
ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, reglist);
if (ret) {
error_report("Error when reading KVM_GET_REG_LIST, code %s ",
strerrorname_np(errno));
exit(EXIT_FAILURE);
}
/* sort reglist to use bsearch() */
qsort(&reglist->reg, reglist->n, sizeof(uint64_t), uint64_cmp);
for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
multi_ext_cfg = &kvm_multi_ext_cfgs[i];
reg_id = kvm_riscv_reg_id(&cpu->env, KVM_REG_RISCV_ISA_EXT,
multi_ext_cfg->kvm_reg_id);
reg_search = bsearch(&reg_id, reglist->reg, reglist->n,
sizeof(uint64_t), uint64_cmp);
if (!reg_search) {
continue;
}
reg.id = reg_id;
reg.addr = (uint64_t)&val;
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to read ISA_EXT KVM register %s, "
"error code: %s", multi_ext_cfg->name,
strerrorname_np(errno));
exit(EXIT_FAILURE);
}
multi_ext_cfg->supported = true;
kvm_cpu_cfg_set(cpu, multi_ext_cfg, val);
}
if (cpu->cfg.ext_icbom) {
kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cbom_blocksize);
}
if (cpu->cfg.ext_icboz) {
kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cboz_blocksize);
}
}
static void riscv_init_kvm_registers(Object *cpu_obj)
{
RISCVCPU *cpu = RISCV_CPU(cpu_obj);
KVMScratchCPU kvmcpu;
@ -763,7 +915,6 @@ void kvm_riscv_init_user_properties(Object *cpu_obj)
return;
}
kvm_riscv_add_cpu_user_properties(cpu_obj);
kvm_riscv_init_machine_ids(cpu, &kvmcpu);
kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
@ -797,6 +948,24 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state)
{
if (cap_has_mp_state) {
struct kvm_mp_state mp_state = {
.mp_state = state
};
int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
if (ret) {
fprintf(stderr, "%s: failed to sync MP_STATE %d/%s\n",
__func__, ret, strerror(-ret));
return -1;
}
}
return 0;
}
int kvm_arch_put_registers(CPUState *cs, int level)
{
int ret = 0;
@ -816,6 +985,18 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
if (KVM_PUT_RESET_STATE == level) {
RISCVCPU *cpu = RISCV_CPU(cs);
if (cs->cpu_index == 0) {
ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE);
} else {
ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED);
}
if (ret) {
return ret;
}
}
return ret;
}
@ -928,6 +1109,7 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
return 0;
}
@ -1010,14 +1192,25 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
{
CPURISCVState *env = &cpu->env;
int i;
if (!kvm_enabled()) {
return;
}
for (i = 0; i < 32; i++) {
env->gpr[i] = 0;
}
env->pc = cpu->env.kernel_addr;
env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
env->gpr[11] = cpu->env.fdt_addr; /* a1 */
env->satp = 0;
env->mie = 0;
env->stvec = 0;
env->sscratch = 0;
env->sepc = 0;
env->scause = 0;
env->stval = 0;
env->mip = 0;
}
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
@ -1229,3 +1422,62 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
}
static void kvm_cpu_instance_init(CPUState *cs)
{
Object *obj = OBJECT(RISCV_CPU(cs));
DeviceState *dev = DEVICE(obj);
riscv_init_kvm_registers(obj);
kvm_riscv_add_cpu_user_properties(obj);
for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) {
/* Check if we have a specific KVM handler for the option */
if (object_property_find(obj, prop->name)) {
continue;
}
qdev_property_add_static(dev, prop);
}
}
static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data)
{
AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
acc->cpu_instance_init = kvm_cpu_instance_init;
}
static const TypeInfo kvm_cpu_accel_type_info = {
.name = ACCEL_CPU_NAME("kvm"),
.parent = TYPE_ACCEL_CPU,
.class_init = kvm_cpu_accel_class_init,
.abstract = true,
};
static void kvm_cpu_accel_register_types(void)
{
type_register_static(&kvm_cpu_accel_type_info);
}
type_init(kvm_cpu_accel_register_types);
static void riscv_host_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
#if defined(TARGET_RISCV32)
env->misa_mxl_max = env->misa_mxl = MXL_RV32;
#elif defined(TARGET_RISCV64)
env->misa_mxl_max = env->misa_mxl = MXL_RV64;
#endif
}
static const TypeInfo riscv_kvm_cpu_type_infos[] = {
{
.name = TYPE_RISCV_CPU_HOST,
.parent = TYPE_RISCV_CPU,
.instance_init = riscv_host_cpu_init,
}
};
DEFINE_TYPES(riscv_kvm_cpu_type_infos)

View file

@ -19,7 +19,6 @@
#ifndef QEMU_KVM_RISCV_H
#define QEMU_KVM_RISCV_H
void kvm_riscv_init_user_properties(Object *cpu_obj);
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
@ -27,5 +26,6 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
uint64_t aplic_base, uint64_t imsic_base,
uint64_t guest_num);
void riscv_kvm_aplic_request(void *opaque, int irq, int level);
int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state);
#endif

View file

@ -0,0 +1 @@
riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm-cpu.c'))

View file

@ -24,7 +24,6 @@ riscv_ss.add(files(
'zce_helper.c',
'vcrypto_helper.c'
))
riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
riscv_system_ss = ss.source_set()
riscv_system_ss.add(files(
@ -38,5 +37,8 @@ riscv_system_ss.add(files(
'riscv-qmp-cmds.c',
))
subdir('tcg')
subdir('kvm')
target_arch += {'riscv': riscv_ss}
target_system_arch += {'riscv': riscv_system_ss}

View file

@ -0,0 +1,2 @@
riscv_ss.add(when: 'CONFIG_TCG', if_true: files(
'tcg-cpu.c'))

949
target/riscv/tcg/tcg-cpu.c Normal file
View file

@ -0,0 +1,949 @@
/*
* riscv TCG cpu class initialization
*
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
* Copyright (c) 2017-2018 SiFive, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "exec/exec-all.h"
#include "tcg-cpu.h"
#include "cpu.h"
#include "pmu.h"
#include "time_helper.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/accel.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "hw/core/accel-cpu.h"
#include "hw/core/tcg-cpu-ops.h"
#include "tcg/tcg.h"
/* Hash that stores user set extensions */
static GHashTable *multi_ext_user_opts;
static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
{
return g_hash_table_contains(multi_ext_user_opts,
GUINT_TO_POINTER(ext_offset));
}
static void riscv_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
if (!(tb_cflags(tb) & CF_PCREL)) {
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL);
tcg_debug_assert(!(cs->tcg_cflags & CF_PCREL));
if (xl == MXL_RV32) {
env->pc = (int32_t) tb->pc;
} else {
env->pc = tb->pc;
}
}
}
static void riscv_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
const uint64_t *data)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL);
target_ulong pc;
if (tb_cflags(tb) & CF_PCREL) {
pc = (env->pc & TARGET_PAGE_MASK) | data[0];
} else {
pc = data[0];
}
if (xl == MXL_RV32) {
env->pc = (int32_t)pc;
} else {
env->pc = pc;
}
env->bins = data[1];
}
static const struct TCGCPUOps riscv_tcg_ops = {
.initialize = riscv_translate_init,
.synchronize_from_tb = riscv_cpu_synchronize_from_tb,
.restore_state_to_opc = riscv_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
.tlb_fill = riscv_cpu_tlb_fill,
.cpu_exec_interrupt = riscv_cpu_exec_interrupt,
.do_interrupt = riscv_cpu_do_interrupt,
.do_transaction_failed = riscv_cpu_do_transaction_failed,
.do_unaligned_access = riscv_cpu_do_unaligned_access,
.debug_excp_handler = riscv_cpu_debug_excp_handler,
.debug_check_breakpoint = riscv_cpu_debug_check_breakpoint,
.debug_check_watchpoint = riscv_cpu_debug_check_watchpoint,
#endif /* !CONFIG_USER_ONLY */
};
static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
{
const RISCVIsaExtData *edata;
for (edata = isa_edata_arr; edata && edata->name; edata++) {
if (edata->ext_enable_offset != ext_offset) {
continue;
}
return edata->min_version;
}
g_assert_not_reached();
}
static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset,
bool value)
{
CPURISCVState *env = &cpu->env;
bool prev_val = isa_ext_is_enabled(cpu, ext_offset);
int min_version;
if (prev_val == value) {
return;
}
if (cpu_cfg_ext_is_user_set(ext_offset)) {
return;
}
if (value && env->priv_ver != PRIV_VERSION_LATEST) {
/* Do not enable it if priv_ver is older than min_version */
min_version = cpu_cfg_ext_get_min_version(ext_offset);
if (env->priv_ver < min_version) {
return;
}
}
isa_ext_update_enabled(cpu, ext_offset, value);
}
static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp)
{
if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) {
error_setg(errp, "H extension requires priv spec 1.12.0");
return;
}
}
static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp)
{
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
CPUClass *cc = CPU_CLASS(mcc);
CPURISCVState *env = &cpu->env;
/* Validate that MISA_MXL is set properly. */
switch (env->misa_mxl_max) {
#ifdef TARGET_RISCV64
case MXL_RV64:
case MXL_RV128:
cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
break;
#endif
case MXL_RV32:
cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
break;
default:
g_assert_not_reached();
}
if (env->misa_mxl_max != env->misa_mxl) {
error_setg(errp, "misa_mxl_max must be equal to misa_mxl");
return;
}
}
static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp)
{
CPURISCVState *env = &cpu->env;
int priv_version = -1;
if (cpu->cfg.priv_spec) {
if (!g_strcmp0(cpu->cfg.priv_spec, "v1.12.0")) {
priv_version = PRIV_VERSION_1_12_0;
} else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) {
priv_version = PRIV_VERSION_1_11_0;
} else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
priv_version = PRIV_VERSION_1_10_0;
} else {
error_setg(errp,
"Unsupported privilege spec version '%s'",
cpu->cfg.priv_spec);
return;
}
env->priv_ver = priv_version;
}
}
static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg,
Error **errp)
{
if (!is_power_of_2(cfg->vlen)) {
error_setg(errp, "Vector extension VLEN must be power of 2");
return;
}
if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) {
error_setg(errp,
"Vector extension implementation only supports VLEN "
"in the range [128, %d]", RV_VLEN_MAX);
return;
}
if (!is_power_of_2(cfg->elen)) {
error_setg(errp, "Vector extension ELEN must be power of 2");
return;
}
if (cfg->elen > 64 || cfg->elen < 8) {
error_setg(errp,
"Vector extension implementation only supports ELEN "
"in the range [8, 64]");
return;
}
if (cfg->vext_spec) {
if (!g_strcmp0(cfg->vext_spec, "v1.0")) {
env->vext_ver = VEXT_VERSION_1_00_0;
} else {
error_setg(errp, "Unsupported vector spec version '%s'",
cfg->vext_spec);
return;
}
} else if (env->vext_ver == 0) {
qemu_log("vector version is not specified, "
"use the default value v1.0\n");
env->vext_ver = VEXT_VERSION_1_00_0;
}
}
static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
{
CPURISCVState *env = &cpu->env;
const RISCVIsaExtData *edata;
/* Force disable extensions if priv spec version does not match */
for (edata = isa_edata_arr; edata && edata->name; edata++) {
if (isa_ext_is_enabled(cpu, edata->ext_enable_offset) &&
(env->priv_ver < edata->min_version)) {
isa_ext_update_enabled(cpu, edata->ext_enable_offset, false);
#ifndef CONFIG_USER_ONLY
warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx
" because privilege spec version does not match",
edata->name, env->mhartid);
#else
warn_report("disabling %s extension because "
"privilege spec version does not match",
edata->name);
#endif
}
}
}
/*
* Check consistency between chosen extensions while setting
* cpu->cfg accordingly.
*/
void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
{
CPURISCVState *env = &cpu->env;
Error *local_err = NULL;
/* Do some ISA extension error checking */
if (riscv_has_ext(env, RVG) &&
!(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) &&
riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) &&
riscv_has_ext(env, RVD) &&
cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) {
if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) &&
!cpu->cfg.ext_icsr) {
error_setg(errp, "RVG requires Zicsr but user set Zicsr to false");
return;
}
if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) &&
!cpu->cfg.ext_ifencei) {
error_setg(errp, "RVG requires Zifencei but user set "
"Zifencei to false");
return;
}
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true);
env->misa_ext |= RVI | RVM | RVA | RVF | RVD;
env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD;
}
if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) {
error_setg(errp,
"I and E extensions are incompatible");
return;
}
if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) {
error_setg(errp,
"Either I or E extension must be set");
return;
}
if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) {
error_setg(errp,
"Setting S extension without U extension is illegal");
return;
}
if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) {
error_setg(errp,
"H depends on an I base integer ISA with 32 x registers");
return;
}
if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) {
error_setg(errp, "H extension implicitly requires S-mode");
return;
}
if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) {
error_setg(errp, "F extension requires Zicsr");
return;
}
if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) {
error_setg(errp, "Zawrs extension requires A extension");
return;
}
if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) {
error_setg(errp, "Zfa extension requires F extension");
return;
}
if (cpu->cfg.ext_zfh) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true);
}
if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) {
error_setg(errp, "Zfh/Zfhmin extensions require F extension");
return;
}
if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) {
error_setg(errp, "Zfbfmin extension depends on F extension");
return;
}
if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) {
error_setg(errp, "D extension requires F extension");
return;
}
if (riscv_has_ext(env, RVV)) {
riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
/* The V vector extension depends on the Zve64d extension */
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true);
}
/* The Zve64d extension depends on the Zve64f extension */
if (cpu->cfg.ext_zve64d) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true);
}
/* The Zve64f extension depends on the Zve32f extension */
if (cpu->cfg.ext_zve64f) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true);
}
if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) {
error_setg(errp, "Zve64d/V extensions require D extension");
return;
}
if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) {
error_setg(errp, "Zve32f/Zve64f extensions require F extension");
return;
}
if (cpu->cfg.ext_zvfh) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true);
}
if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) {
error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension");
return;
}
if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) {
error_setg(errp, "Zvfh extensions requires Zfhmin extension");
return;
}
if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) {
error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension");
return;
}
if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) {
error_setg(errp, "Zvfbfmin extension depends on Zve32f extension");
return;
}
if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) {
error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension");
return;
}
/* Set the ISA extensions, checks should have happened above */
if (cpu->cfg.ext_zhinx) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
}
if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) && !cpu->cfg.ext_zfinx) {
error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx");
return;
}
if (cpu->cfg.ext_zfinx) {
if (!cpu->cfg.ext_icsr) {
error_setg(errp, "Zfinx extension requires Zicsr");
return;
}
if (riscv_has_ext(env, RVF)) {
error_setg(errp,
"Zfinx cannot be supported together with F extension");
return;
}
}
if (cpu->cfg.ext_zce) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true);
if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
}
}
/* zca, zcd and zcf has a PRIV 1.12.0 restriction */
if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
}
if (riscv_has_ext(env, RVD)) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true);
}
}
if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) {
error_setg(errp, "Zcf extension is only relevant to RV32");
return;
}
if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) {
error_setg(errp, "Zcf extension requires F extension");
return;
}
if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) {
error_setg(errp, "Zcd extension requires D extension");
return;
}
if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb ||
cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) {
error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca "
"extension");
return;
}
if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) {
error_setg(errp, "Zcmp/Zcmt extensions are incompatible with "
"Zcd extension");
return;
}
if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) {
error_setg(errp, "Zcmt extension requires Zicsr extension");
return;
}
/*
* In principle Zve*x would also suffice here, were they supported
* in qemu
*/
if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned ||
cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) &&
!cpu->cfg.ext_zve32f) {
error_setg(errp,
"Vector crypto extensions require V or Zve* extensions");
return;
}
if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) {
error_setg(
errp,
"Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions");
return;
}
if (cpu->cfg.ext_zk) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true);
}
if (cpu->cfg.ext_zkn) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true);
}
if (cpu->cfg.ext_zks) {
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true);
cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true);
}
/*
* Disable isa extensions based on priv spec after we
* validated and set everything we need.
*/
riscv_cpu_disable_priv_spec_isa_exts(cpu);
}
static bool riscv_cpu_is_generic(Object *cpu_obj)
{
return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL;
}
/*
* We'll get here via the following path:
*
* riscv_cpu_realize()
* -> cpu_exec_realizefn()
* -> tcg_cpu_realize() (via accel_cpu_common_realize())
*/
static bool tcg_cpu_realize(CPUState *cs, Error **errp)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
Error *local_err = NULL;
if (object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) {
g_autofree char *name = riscv_cpu_get_name(cpu);
error_setg(errp, "'%s' CPU is not compatible with TCG acceleration",
name);
return false;
}
riscv_cpu_validate_misa_mxl(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return false;
}
riscv_cpu_validate_priv_spec(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return false;
}
riscv_cpu_validate_misa_priv(env, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return false;
}
if (cpu->cfg.epmp && !cpu->cfg.pmp) {
/*
* Enhanced PMP should only be available
* on harts with PMP support
*/
error_setg(errp, "Invalid configuration: EPMP requires PMP support");
return false;
}
riscv_cpu_validate_set_extensions(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return false;
}
#ifndef CONFIG_USER_ONLY
CPU(cs)->tcg_cflags |= CF_PCREL;
if (cpu->cfg.ext_sstc) {
riscv_timer_init(cpu);
}
if (cpu->cfg.pmu_num) {
if (!riscv_pmu_init(cpu, cpu->cfg.pmu_num) && cpu->cfg.ext_sscofpmf) {
cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
riscv_pmu_timer_cb, cpu);
}
}
#endif
return true;
}
typedef struct RISCVCPUMisaExtConfig {
target_ulong misa_bit;
bool enabled;
} RISCVCPUMisaExtConfig;
static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
const RISCVCPUMisaExtConfig *misa_ext_cfg = opaque;
target_ulong misa_bit = misa_ext_cfg->misa_bit;
RISCVCPU *cpu = RISCV_CPU(obj);
CPURISCVState *env = &cpu->env;
bool generic_cpu = riscv_cpu_is_generic(obj);
bool prev_val, value;
if (!visit_type_bool(v, name, &value, errp)) {
return;
}
prev_val = env->misa_ext & misa_bit;
if (value == prev_val) {
return;
}
if (value) {
if (!generic_cpu) {
g_autofree char *cpuname = riscv_cpu_get_name(cpu);
error_setg(errp, "'%s' CPU does not allow enabling extensions",
cpuname);
return;
}
env->misa_ext |= misa_bit;
env->misa_ext_mask |= misa_bit;
} else {
env->misa_ext &= ~misa_bit;
env->misa_ext_mask &= ~misa_bit;
}
}
static void cpu_get_misa_ext_cfg(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
const RISCVCPUMisaExtConfig *misa_ext_cfg = opaque;
target_ulong misa_bit = misa_ext_cfg->misa_bit;
RISCVCPU *cpu = RISCV_CPU(obj);
CPURISCVState *env = &cpu->env;
bool value;
value = env->misa_ext & misa_bit;
visit_type_bool(v, name, &value, errp);
}
#define MISA_CFG(_bit, _enabled) \
{.misa_bit = _bit, .enabled = _enabled}
static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
MISA_CFG(RVA, true),
MISA_CFG(RVC, true),
MISA_CFG(RVD, true),
MISA_CFG(RVF, true),
MISA_CFG(RVI, true),
MISA_CFG(RVE, false),
MISA_CFG(RVM, true),
MISA_CFG(RVS, true),
MISA_CFG(RVU, true),
MISA_CFG(RVH, true),
MISA_CFG(RVJ, false),
MISA_CFG(RVV, false),
MISA_CFG(RVG, false),
};
/*
* We do not support user choice tracking for MISA
* extensions yet because, so far, we do not silently
* change MISA bits during realize() (RVG enables MISA
* bits but the user is warned about it).
*/
static void riscv_cpu_add_misa_properties(Object *cpu_obj)
{
bool use_def_vals = riscv_cpu_is_generic(cpu_obj);
int i;
for (i = 0; i < ARRAY_SIZE(misa_ext_cfgs); i++) {
const RISCVCPUMisaExtConfig *misa_cfg = &misa_ext_cfgs[i];
int bit = misa_cfg->misa_bit;
const char *name = riscv_get_misa_ext_name(bit);
const char *desc = riscv_get_misa_ext_description(bit);
/* Check if KVM already created the property */
if (object_property_find(cpu_obj, name)) {
continue;
}
object_property_add(cpu_obj, name, "bool",
cpu_get_misa_ext_cfg,
cpu_set_misa_ext_cfg,
NULL, (void *)misa_cfg);
object_property_set_description(cpu_obj, name, desc);
if (use_def_vals) {
object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL);
}
}
}
static bool cpu_ext_is_deprecated(const char *ext_name)
{
return isupper(ext_name[0]);
}
/*
* String will be allocated in the heap. Caller is responsible
* for freeing it.
*/
static char *cpu_ext_to_lower(const char *ext_name)
{
char *ret = g_malloc0(strlen(ext_name) + 1);
strcpy(ret, ext_name);
ret[0] = tolower(ret[0]);
return ret;
}
static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque;
RISCVCPU *cpu = RISCV_CPU(obj);
bool generic_cpu = riscv_cpu_is_generic(obj);
bool prev_val, value;
if (!visit_type_bool(v, name, &value, errp)) {
return;
}
if (cpu_ext_is_deprecated(multi_ext_cfg->name)) {
g_autofree char *lower = cpu_ext_to_lower(multi_ext_cfg->name);
warn_report("CPU property '%s' is deprecated. Please use '%s' instead",
multi_ext_cfg->name, lower);
}
g_hash_table_insert(multi_ext_user_opts,
GUINT_TO_POINTER(multi_ext_cfg->offset),
(gpointer)value);
prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset);
if (value == prev_val) {
return;
}
if (value && !generic_cpu) {
g_autofree char *cpuname = riscv_cpu_get_name(cpu);
error_setg(errp, "'%s' CPU does not allow enabling extensions",
cpuname);
return;
}
isa_ext_update_enabled(cpu, multi_ext_cfg->offset, value);
}
static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque;
bool value = isa_ext_is_enabled(RISCV_CPU(obj), multi_ext_cfg->offset);
visit_type_bool(v, name, &value, errp);
}
static void cpu_add_multi_ext_prop(Object *cpu_obj,
const RISCVCPUMultiExtConfig *multi_cfg)
{
bool generic_cpu = riscv_cpu_is_generic(cpu_obj);
bool deprecated_ext = cpu_ext_is_deprecated(multi_cfg->name);
object_property_add(cpu_obj, multi_cfg->name, "bool",
cpu_get_multi_ext_cfg,
cpu_set_multi_ext_cfg,
NULL, (void *)multi_cfg);
if (!generic_cpu || deprecated_ext) {
return;
}
/*
* Set def val directly instead of using
* object_property_set_bool() to save the set()
* callback hash for user inputs.
*/
isa_ext_update_enabled(RISCV_CPU(cpu_obj), multi_cfg->offset,
multi_cfg->enabled);
}
static void riscv_cpu_add_multiext_prop_array(Object *obj,
const RISCVCPUMultiExtConfig *array)
{
const RISCVCPUMultiExtConfig *prop;
g_assert(array);
for (prop = array; prop && prop->name; prop++) {
cpu_add_multi_ext_prop(obj, prop);
}
}
/*
* Add CPU properties with user-facing flags.
*
* This will overwrite existing env->misa_ext values with the
* defaults set via riscv_cpu_add_misa_properties().
*/
static void riscv_cpu_add_user_properties(Object *obj)
{
#ifndef CONFIG_USER_ONLY
riscv_add_satp_mode_properties(obj);
#endif
riscv_cpu_add_misa_properties(obj);
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_extensions);
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts);
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts);
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts);
for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) {
qdev_property_add_static(DEVICE(obj), prop);
}
}
/*
* The 'max' type CPU will have all possible ratified
* non-vendor extensions enabled.
*/
static void riscv_init_max_cpu_extensions(Object *obj)
{
RISCVCPU *cpu = RISCV_CPU(obj);
CPURISCVState *env = &cpu->env;
const RISCVCPUMultiExtConfig *prop;
/* Enable RVG, RVJ and RVV that are disabled by default */
riscv_cpu_set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV);
for (prop = riscv_cpu_extensions; prop && prop->name; prop++) {
isa_ext_update_enabled(cpu, prop->offset, true);
}
/* set vector version */
env->vext_ver = VEXT_VERSION_1_00_0;
/* Zfinx is not compatible with F. Disable it */
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zfinx), false);
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zdinx), false);
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinx), false);
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zhinxmin), false);
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zce), false);
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false);
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false);
if (env->misa_mxl != MXL_RV32) {
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false);
}
}
static bool riscv_cpu_has_max_extensions(Object *cpu_obj)
{
return object_dynamic_cast(cpu_obj, TYPE_RISCV_CPU_MAX) != NULL;
}
static void tcg_cpu_instance_init(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
Object *obj = OBJECT(cpu);
multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal);
riscv_cpu_add_user_properties(obj);
if (riscv_cpu_has_max_extensions(obj)) {
riscv_init_max_cpu_extensions(obj);
}
}
static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc)
{
/*
* All cpus use the same set of operations.
*/
cc->tcg_ops = &riscv_tcg_ops;
}
static void tcg_cpu_class_init(CPUClass *cc)
{
cc->init_accel_cpu = tcg_cpu_init_ops;
}
static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data)
{
AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
acc->cpu_class_init = tcg_cpu_class_init;
acc->cpu_instance_init = tcg_cpu_instance_init;
acc->cpu_target_realize = tcg_cpu_realize;
}
static const TypeInfo tcg_cpu_accel_type_info = {
.name = ACCEL_CPU_NAME("tcg"),
.parent = TYPE_ACCEL_CPU,
.class_init = tcg_cpu_accel_class_init,
.abstract = true,
};
static void tcg_cpu_accel_register_types(void)
{
type_register_static(&tcg_cpu_accel_type_info);
}
type_init(tcg_cpu_accel_register_types);

View file

@ -0,0 +1,27 @@
/*
* riscv TCG cpu class initialization
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RISCV_TCG_CPU_H
#define RISCV_TCG_CPU_H
#include "cpu.h"
void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
#endif

View file

@ -3361,7 +3361,7 @@ static uint32_t fwmaccbf16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
RVVCALL(OPFVV3, vfwmaccbf16_vv, WOP_UUU_H, H4, H2, H2, fwmaccbf16)
GEN_VEXT_VV_ENV(vfwmaccbf16_vv, 4)
RVVCALL(OPFVF3, vfwmaccbf16_vf, WOP_UUU_H, H4, H2, fwmacc16)
RVVCALL(OPFVF3, vfwmaccbf16_vf, WOP_UUU_H, H4, H2, fwmaccbf16)
GEN_VEXT_VF(vfwmaccbf16_vf, 4)
static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s)

View file

@ -501,6 +501,38 @@ def test_riscv64(self):
self.common_tuxrun(csums=sums)
def test_riscv32_maxcpu(self):
"""
:avocado: tags=arch:riscv32
:avocado: tags=machine:virt
:avocado: tags=cpu:max
:avocado: tags=tuxboot:riscv32
"""
sums = { "Image" :
"89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5",
"fw_jump.elf" :
"f2ef28a0b77826f79d085d3e4aa686f1159b315eff9099a37046b18936676985",
"rootfs.ext4.zst" :
"7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba" }
self.common_tuxrun(csums=sums)
def test_riscv64_maxcpu(self):
"""
:avocado: tags=arch:riscv64
:avocado: tags=machine:virt
:avocado: tags=cpu:max
:avocado: tags=tuxboot:riscv64
"""
sums = { "Image" :
"cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e",
"fw_jump.elf" :
"6e3373abcab4305fe151b564a4c71110d833c21f2c0a1753b7935459e36aedcf",
"rootfs.ext4.zst" :
"b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb" }
self.common_tuxrun(csums=sums)
def test_s390(self):
"""
:avocado: tags=arch:s390x