46808a4cb8
Everywhere we use kvm_for_each_vpcu(), we use an int as the vcpu index. Unfortunately, we're about to move rework the iterator, which requires this to be upgrade to an unsigned long. Let's bite the bullet and repaint all of it in one go. Signed-off-by: Marc Zyngier <maz@kernel.org> Message-Id: <20211116160403.4074052-7-maz@kernel.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
186 lines
4.6 KiB
C
186 lines
4.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
|
*
|
|
* Authors:
|
|
* Atish Patra <atish.patra@wdc.com>
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/err.h>
|
|
#include <linux/kvm_host.h>
|
|
#include <asm/csr.h>
|
|
#include <asm/sbi.h>
|
|
#include <asm/kvm_vcpu_timer.h>
|
|
|
|
#define SBI_VERSION_MAJOR 0
|
|
#define SBI_VERSION_MINOR 1
|
|
|
|
static void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu,
|
|
struct kvm_run *run)
|
|
{
|
|
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
|
|
|
|
vcpu->arch.sbi_context.return_handled = 0;
|
|
vcpu->stat.ecall_exit_stat++;
|
|
run->exit_reason = KVM_EXIT_RISCV_SBI;
|
|
run->riscv_sbi.extension_id = cp->a7;
|
|
run->riscv_sbi.function_id = cp->a6;
|
|
run->riscv_sbi.args[0] = cp->a0;
|
|
run->riscv_sbi.args[1] = cp->a1;
|
|
run->riscv_sbi.args[2] = cp->a2;
|
|
run->riscv_sbi.args[3] = cp->a3;
|
|
run->riscv_sbi.args[4] = cp->a4;
|
|
run->riscv_sbi.args[5] = cp->a5;
|
|
run->riscv_sbi.ret[0] = cp->a0;
|
|
run->riscv_sbi.ret[1] = cp->a1;
|
|
}
|
|
|
|
int kvm_riscv_vcpu_sbi_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|
{
|
|
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
|
|
|
|
/* Handle SBI return only once */
|
|
if (vcpu->arch.sbi_context.return_handled)
|
|
return 0;
|
|
vcpu->arch.sbi_context.return_handled = 1;
|
|
|
|
/* Update return values */
|
|
cp->a0 = run->riscv_sbi.ret[0];
|
|
cp->a1 = run->riscv_sbi.ret[1];
|
|
|
|
/* Move to next instruction */
|
|
vcpu->arch.guest_context.sepc += 4;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_RISCV_SBI_V01
|
|
|
|
static void kvm_sbi_system_shutdown(struct kvm_vcpu *vcpu,
|
|
struct kvm_run *run, u32 type)
|
|
{
|
|
unsigned long i;
|
|
struct kvm_vcpu *tmp;
|
|
|
|
kvm_for_each_vcpu(i, tmp, vcpu->kvm)
|
|
tmp->arch.power_off = true;
|
|
kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);
|
|
|
|
memset(&run->system_event, 0, sizeof(run->system_event));
|
|
run->system_event.type = type;
|
|
run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
|
}
|
|
|
|
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|
{
|
|
ulong hmask;
|
|
int i, ret = 1;
|
|
u64 next_cycle;
|
|
struct kvm_vcpu *rvcpu;
|
|
bool next_sepc = true;
|
|
struct cpumask cm, hm;
|
|
struct kvm *kvm = vcpu->kvm;
|
|
struct kvm_cpu_trap utrap = { 0 };
|
|
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
|
|
|
|
if (!cp)
|
|
return -EINVAL;
|
|
|
|
switch (cp->a7) {
|
|
case SBI_EXT_0_1_CONSOLE_GETCHAR:
|
|
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
|
|
/*
|
|
* The CONSOLE_GETCHAR/CONSOLE_PUTCHAR SBI calls cannot be
|
|
* handled in kernel so we forward these to user-space
|
|
*/
|
|
kvm_riscv_vcpu_sbi_forward(vcpu, run);
|
|
next_sepc = false;
|
|
ret = 0;
|
|
break;
|
|
case SBI_EXT_0_1_SET_TIMER:
|
|
#if __riscv_xlen == 32
|
|
next_cycle = ((u64)cp->a1 << 32) | (u64)cp->a0;
|
|
#else
|
|
next_cycle = (u64)cp->a0;
|
|
#endif
|
|
kvm_riscv_vcpu_timer_next_event(vcpu, next_cycle);
|
|
break;
|
|
case SBI_EXT_0_1_CLEAR_IPI:
|
|
kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_SOFT);
|
|
break;
|
|
case SBI_EXT_0_1_SEND_IPI:
|
|
if (cp->a0)
|
|
hmask = kvm_riscv_vcpu_unpriv_read(vcpu, false, cp->a0,
|
|
&utrap);
|
|
else
|
|
hmask = (1UL << atomic_read(&kvm->online_vcpus)) - 1;
|
|
if (utrap.scause) {
|
|
utrap.sepc = cp->sepc;
|
|
kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
|
|
next_sepc = false;
|
|
break;
|
|
}
|
|
for_each_set_bit(i, &hmask, BITS_PER_LONG) {
|
|
rvcpu = kvm_get_vcpu_by_id(vcpu->kvm, i);
|
|
kvm_riscv_vcpu_set_interrupt(rvcpu, IRQ_VS_SOFT);
|
|
}
|
|
break;
|
|
case SBI_EXT_0_1_SHUTDOWN:
|
|
kvm_sbi_system_shutdown(vcpu, run, KVM_SYSTEM_EVENT_SHUTDOWN);
|
|
next_sepc = false;
|
|
ret = 0;
|
|
break;
|
|
case SBI_EXT_0_1_REMOTE_FENCE_I:
|
|
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
|
|
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
|
|
if (cp->a0)
|
|
hmask = kvm_riscv_vcpu_unpriv_read(vcpu, false, cp->a0,
|
|
&utrap);
|
|
else
|
|
hmask = (1UL << atomic_read(&kvm->online_vcpus)) - 1;
|
|
if (utrap.scause) {
|
|
utrap.sepc = cp->sepc;
|
|
kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
|
|
next_sepc = false;
|
|
break;
|
|
}
|
|
cpumask_clear(&cm);
|
|
for_each_set_bit(i, &hmask, BITS_PER_LONG) {
|
|
rvcpu = kvm_get_vcpu_by_id(vcpu->kvm, i);
|
|
if (rvcpu->cpu < 0)
|
|
continue;
|
|
cpumask_set_cpu(rvcpu->cpu, &cm);
|
|
}
|
|
riscv_cpuid_to_hartid_mask(&cm, &hm);
|
|
if (cp->a7 == SBI_EXT_0_1_REMOTE_FENCE_I)
|
|
sbi_remote_fence_i(cpumask_bits(&hm));
|
|
else if (cp->a7 == SBI_EXT_0_1_REMOTE_SFENCE_VMA)
|
|
sbi_remote_hfence_vvma(cpumask_bits(&hm),
|
|
cp->a1, cp->a2);
|
|
else
|
|
sbi_remote_hfence_vvma_asid(cpumask_bits(&hm),
|
|
cp->a1, cp->a2, cp->a3);
|
|
break;
|
|
default:
|
|
/* Return error for unsupported SBI calls */
|
|
cp->a0 = SBI_ERR_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
if (next_sepc)
|
|
cp->sepc += 4;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#else
|
|
|
|
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|
{
|
|
kvm_riscv_vcpu_sbi_forward(vcpu, run);
|
|
return 0;
|
|
}
|
|
|
|
#endif
|