Skip to content

Commit

Permalink
target/riscv: Clear CSR values at reset and sync MPSTATE with host
Browse files Browse the repository at this point in the history
This patch fixes guest reboot errors when using KVM.

There are two issues when rebooting a guest using KVM
1. When the guest initiates a reboot the host is unable to stop the vcpu
2. When running a SMP guest the qemu monitor system_reset causes a vcpu crash

This can be fixed by clearing the CSR values at reset and syncing the
MPSTATE with the host.

Signed-off-by: liguang.zhang <liguang.zhang@hexintek.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20230913091332.17355-1-18622748025@163.com>
[ Changes by AF
 - Fixup commit message
 - Fixup patch style
]
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
  • Loading branch information
liguang-hxd authored and alistair23 committed Oct 12, 2023
1 parent 67f94b0 commit 8633951
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
44 changes: 44 additions & 0 deletions target/riscv/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,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)
{
Expand Down Expand Up @@ -795,6 +797,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;
Expand All @@ -814,6 +834,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;
}

Expand Down Expand Up @@ -926,6 +958,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;
}

Expand Down Expand Up @@ -1008,14 +1041,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)
Expand Down
1 change: 1 addition & 0 deletions target/riscv/kvm_riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,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

0 comments on commit 8633951

Please sign in to comment.