@@ -1205,10 +1205,19 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str)
{
char *old = *isa_str;
char *new = *isa_str;
- int i;
+ int i, offset;
for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
if (isa_ext_is_enabled(cpu, &isa_edata_arr[i])) {
+ offset = isa_edata_arr[i].ext_enable_offset;
+ if (kvm_enabled() && !kvm_riscv_ext_supported(offset)) {
+#ifndef CONFIG_USER_ONLY
+ info_report("disabling %s extension for hart %d as kvm does "
+ "not support it", isa_edata_arr[i].name,
+ (int)cpu->env.mhartid);
+#endif
+ continue;
+ }
if (isa_edata_arr[i].multi_letter) {
if (cpu->cfg.short_isa_string) {
continue;
@@ -42,6 +42,29 @@
#include "migration/migration.h"
#include "sysemu/runstate.h"
+struct isa_ext_info {
+ const char *name;
+ target_ulong misa_bit;
+ int ext_enable_offset;
+};
+
+#define ISA_EXT_DATA_ENTRY(_name, _bit, _prop) \
+ {#_name, _bit, offsetof(struct RISCVCPUConfig, _prop)}
+
+static const struct isa_ext_info isa_info_arr[] = {
+ ISA_EXT_DATA_ENTRY(a, RVA, ext_a),
+ ISA_EXT_DATA_ENTRY(c, RVC, ext_c),
+ ISA_EXT_DATA_ENTRY(d, RVD, ext_d),
+ ISA_EXT_DATA_ENTRY(f, RVF, ext_f),
+ ISA_EXT_DATA_ENTRY(h, RVH, ext_h),
+ ISA_EXT_DATA_ENTRY(i, RVI, ext_i),
+ ISA_EXT_DATA_ENTRY(m, RVM, ext_m),
+ ISA_EXT_DATA_ENTRY(svpbmt, 0, ext_svpbmt),
+ ISA_EXT_DATA_ENTRY(sstc, 0, ext_sstc),
+ ISA_EXT_DATA_ENTRY(svinval, 0, ext_svinval),
+ ISA_EXT_DATA_ENTRY(zihintpause, 0, ext_zihintpause),
+};
+
static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
uint64_t idx)
{
@@ -394,25 +417,66 @@ void kvm_arch_init_irq_routing(KVMState *s)
{
}
+bool kvm_riscv_ext_supported(int offset)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(isa_info_arr); ++i) {
+ if (isa_info_arr[i].ext_enable_offset == offset) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void kvm_riscv_set_isa_ext(CPUState *cs, CPURISCVState *env)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ unsigned long isa_ext_out;
+ bool *ext_state;
+ uint64_t id;
+ int i, ret;
+
+ env->misa_ext = 0;
+ for (i = 0; i < ARRAY_SIZE(isa_info_arr); i++) {
+ ext_state = (void *)&cpu->cfg + isa_info_arr[i].ext_enable_offset;
+ id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT, i);
+ ret = kvm_get_one_reg(cs, id, &isa_ext_out);
+ if (ret) {
+ warn_report("Disabling ext %s due to failure %d",
+ isa_info_arr[i].name, ret);
+ *ext_state = false;
+ continue;
+ }
+ if (isa_ext_out != (*ext_state)) {
+ isa_ext_out = *ext_state;
+ ret = kvm_set_one_reg(cs, id, &isa_ext_out);
+ if (ret) {
+ warn_report("Could not %s ext %s due to failure %d",
+ (isa_ext_out ? "enable" : "disable"),
+ isa_info_arr[i].name, ret);
+ *ext_state = !isa_ext_out;
+ }
+ }
+ /*
+ * If the single letter extension is supported by KVM then set
+ * the corresponding misa bit for the guest vcpu.
+ */
+ if (isa_info_arr[i].misa_bit && (*ext_state)) {
+ env->misa_ext |= isa_info_arr[i].misa_bit;
+ }
+ }
+}
+
int kvm_arch_init_vcpu(CPUState *cs)
{
- int ret = 0;
- target_ulong isa;
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
- uint64_t id;
qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs);
- id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
- KVM_REG_RISCV_CONFIG_REG(isa));
- ret = kvm_get_one_reg(cs, id, &isa);
- if (ret) {
- return ret;
- }
- env->misa_ext = isa;
-
- return ret;
+ kvm_riscv_set_isa_ext(cs, env);
+ return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
@@ -21,5 +21,5 @@
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
-
+bool kvm_riscv_ext_supported(int offset);
#endif