162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2019 Western Digital Corporation or its affiliates.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors:
662306a36Sopenharmony_ci *     Anup Patel <anup.patel@wdc.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/entry-kvm.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/kdebug.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/percpu.h>
1662306a36Sopenharmony_ci#include <linux/vmalloc.h>
1762306a36Sopenharmony_ci#include <linux/sched/signal.h>
1862306a36Sopenharmony_ci#include <linux/fs.h>
1962306a36Sopenharmony_ci#include <linux/kvm_host.h>
2062306a36Sopenharmony_ci#include <asm/csr.h>
2162306a36Sopenharmony_ci#include <asm/cacheflush.h>
2262306a36Sopenharmony_ci#include <asm/kvm_vcpu_vector.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciconst struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
2562306a36Sopenharmony_ci	KVM_GENERIC_VCPU_STATS(),
2662306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
2762306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
2862306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, mmio_exit_user),
2962306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, mmio_exit_kernel),
3062306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, csr_exit_user),
3162306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, csr_exit_kernel),
3262306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, signal_exits),
3362306a36Sopenharmony_ci	STATS_DESC_COUNTER(VCPU, exits)
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciconst struct kvm_stats_header kvm_vcpu_stats_header = {
3762306a36Sopenharmony_ci	.name_size = KVM_STATS_NAME_SIZE,
3862306a36Sopenharmony_ci	.num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
3962306a36Sopenharmony_ci	.id_offset = sizeof(struct kvm_stats_header),
4062306a36Sopenharmony_ci	.desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
4162306a36Sopenharmony_ci	.data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
4262306a36Sopenharmony_ci		       sizeof(kvm_vcpu_stats_desc),
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
4862306a36Sopenharmony_ci	struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
4962306a36Sopenharmony_ci	struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
5062306a36Sopenharmony_ci	struct kvm_cpu_context *reset_cntx = &vcpu->arch.guest_reset_context;
5162306a36Sopenharmony_ci	bool loaded;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	/**
5462306a36Sopenharmony_ci	 * The preemption should be disabled here because it races with
5562306a36Sopenharmony_ci	 * kvm_sched_out/kvm_sched_in(called from preempt notifiers) which
5662306a36Sopenharmony_ci	 * also calls vcpu_load/put.
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci	get_cpu();
5962306a36Sopenharmony_ci	loaded = (vcpu->cpu != -1);
6062306a36Sopenharmony_ci	if (loaded)
6162306a36Sopenharmony_ci		kvm_arch_vcpu_put(vcpu);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	vcpu->arch.last_exit_cpu = -1;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	memcpy(csr, reset_csr, sizeof(*csr));
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	memcpy(cntx, reset_cntx, sizeof(*cntx));
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	kvm_riscv_vcpu_fp_reset(vcpu);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	kvm_riscv_vcpu_vector_reset(vcpu);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	kvm_riscv_vcpu_timer_reset(vcpu);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_reset(vcpu);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
7862306a36Sopenharmony_ci	bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	kvm_riscv_vcpu_pmu_reset(vcpu);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	vcpu->arch.hfence_head = 0;
8362306a36Sopenharmony_ci	vcpu->arch.hfence_tail = 0;
8462306a36Sopenharmony_ci	memset(vcpu->arch.hfence_queue, 0, sizeof(vcpu->arch.hfence_queue));
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Reset the guest CSRs for hotplug usecase */
8762306a36Sopenharmony_ci	if (loaded)
8862306a36Sopenharmony_ci		kvm_arch_vcpu_load(vcpu, smp_processor_id());
8962306a36Sopenharmony_ci	put_cpu();
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciint kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciint kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int rc;
10062306a36Sopenharmony_ci	struct kvm_cpu_context *cntx;
10162306a36Sopenharmony_ci	struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Mark this VCPU never ran */
10462306a36Sopenharmony_ci	vcpu->arch.ran_atleast_once = false;
10562306a36Sopenharmony_ci	vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;
10662306a36Sopenharmony_ci	bitmap_zero(vcpu->arch.isa, RISCV_ISA_EXT_MAX);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Setup ISA features available to VCPU */
10962306a36Sopenharmony_ci	kvm_riscv_vcpu_setup_isa(vcpu);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* Setup vendor, arch, and implementation details */
11262306a36Sopenharmony_ci	vcpu->arch.mvendorid = sbi_get_mvendorid();
11362306a36Sopenharmony_ci	vcpu->arch.marchid = sbi_get_marchid();
11462306a36Sopenharmony_ci	vcpu->arch.mimpid = sbi_get_mimpid();
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Setup VCPU hfence queue */
11762306a36Sopenharmony_ci	spin_lock_init(&vcpu->arch.hfence_lock);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* Setup reset state of shadow SSTATUS and HSTATUS CSRs */
12062306a36Sopenharmony_ci	cntx = &vcpu->arch.guest_reset_context;
12162306a36Sopenharmony_ci	cntx->sstatus = SR_SPP | SR_SPIE;
12262306a36Sopenharmony_ci	cntx->hstatus = 0;
12362306a36Sopenharmony_ci	cntx->hstatus |= HSTATUS_VTW;
12462306a36Sopenharmony_ci	cntx->hstatus |= HSTATUS_SPVP;
12562306a36Sopenharmony_ci	cntx->hstatus |= HSTATUS_SPV;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (kvm_riscv_vcpu_alloc_vector_context(vcpu, cntx))
12862306a36Sopenharmony_ci		return -ENOMEM;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* By default, make CY, TM, and IR counters accessible in VU mode */
13162306a36Sopenharmony_ci	reset_csr->scounteren = 0x7;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Setup VCPU timer */
13462306a36Sopenharmony_ci	kvm_riscv_vcpu_timer_init(vcpu);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* setup performance monitoring */
13762306a36Sopenharmony_ci	kvm_riscv_vcpu_pmu_init(vcpu);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Setup VCPU AIA */
14062306a36Sopenharmony_ci	rc = kvm_riscv_vcpu_aia_init(vcpu);
14162306a36Sopenharmony_ci	if (rc)
14262306a36Sopenharmony_ci		return rc;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* Reset VCPU */
14562306a36Sopenharmony_ci	kvm_riscv_reset_vcpu(vcpu);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_civoid kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	/**
15362306a36Sopenharmony_ci	 * vcpu with id 0 is the designated boot cpu.
15462306a36Sopenharmony_ci	 * Keep all vcpus with non-zero id in power-off state so that
15562306a36Sopenharmony_ci	 * they can be brought up using SBI HSM extension.
15662306a36Sopenharmony_ci	 */
15762306a36Sopenharmony_ci	if (vcpu->vcpu_idx != 0)
15862306a36Sopenharmony_ci		kvm_riscv_vcpu_power_off(vcpu);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_civoid kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	/* Cleanup VCPU AIA context */
16462306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_deinit(vcpu);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Cleanup VCPU timer */
16762306a36Sopenharmony_ci	kvm_riscv_vcpu_timer_deinit(vcpu);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	kvm_riscv_vcpu_pmu_deinit(vcpu);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Free unused pages pre-allocated for G-stage page table mappings */
17262306a36Sopenharmony_ci	kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* Free vector context space for host and guest kernel */
17562306a36Sopenharmony_ci	kvm_riscv_vcpu_free_vector_context(vcpu);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciint kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	return kvm_riscv_vcpu_timer_pending(vcpu);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_civoid kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	kvm_riscv_aia_wakeon_hgei(vcpu, true);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	kvm_riscv_aia_wakeon_hgei(vcpu, false);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ciint kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	return (kvm_riscv_vcpu_has_interrupts(vcpu, -1UL) &&
19662306a36Sopenharmony_ci		!vcpu->arch.power_off && !vcpu->arch.pause);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciint kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cibool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	return (vcpu->arch.guest_context.sstatus & SR_SPP) ? true : false;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_civm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	return VM_FAULT_SIGBUS;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cilong kvm_arch_vcpu_async_ioctl(struct file *filp,
21562306a36Sopenharmony_ci			       unsigned int ioctl, unsigned long arg)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = filp->private_data;
21862306a36Sopenharmony_ci	void __user *argp = (void __user *)arg;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (ioctl == KVM_INTERRUPT) {
22162306a36Sopenharmony_ci		struct kvm_interrupt irq;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		if (copy_from_user(&irq, argp, sizeof(irq)))
22462306a36Sopenharmony_ci			return -EFAULT;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		if (irq.irq == KVM_INTERRUPT_SET)
22762306a36Sopenharmony_ci			return kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT);
22862306a36Sopenharmony_ci		else
22962306a36Sopenharmony_ci			return kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return -ENOIOCTLCMD;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cilong kvm_arch_vcpu_ioctl(struct file *filp,
23662306a36Sopenharmony_ci			 unsigned int ioctl, unsigned long arg)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = filp->private_data;
23962306a36Sopenharmony_ci	void __user *argp = (void __user *)arg;
24062306a36Sopenharmony_ci	long r = -EINVAL;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	switch (ioctl) {
24362306a36Sopenharmony_ci	case KVM_SET_ONE_REG:
24462306a36Sopenharmony_ci	case KVM_GET_ONE_REG: {
24562306a36Sopenharmony_ci		struct kvm_one_reg reg;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		r = -EFAULT;
24862306a36Sopenharmony_ci		if (copy_from_user(&reg, argp, sizeof(reg)))
24962306a36Sopenharmony_ci			break;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		if (ioctl == KVM_SET_ONE_REG)
25262306a36Sopenharmony_ci			r = kvm_riscv_vcpu_set_reg(vcpu, &reg);
25362306a36Sopenharmony_ci		else
25462306a36Sopenharmony_ci			r = kvm_riscv_vcpu_get_reg(vcpu, &reg);
25562306a36Sopenharmony_ci		break;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	case KVM_GET_REG_LIST: {
25862306a36Sopenharmony_ci		struct kvm_reg_list __user *user_list = argp;
25962306a36Sopenharmony_ci		struct kvm_reg_list reg_list;
26062306a36Sopenharmony_ci		unsigned int n;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		r = -EFAULT;
26362306a36Sopenharmony_ci		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
26462306a36Sopenharmony_ci			break;
26562306a36Sopenharmony_ci		n = reg_list.n;
26662306a36Sopenharmony_ci		reg_list.n = kvm_riscv_vcpu_num_regs(vcpu);
26762306a36Sopenharmony_ci		if (copy_to_user(user_list, &reg_list, sizeof(reg_list)))
26862306a36Sopenharmony_ci			break;
26962306a36Sopenharmony_ci		r = -E2BIG;
27062306a36Sopenharmony_ci		if (n < reg_list.n)
27162306a36Sopenharmony_ci			break;
27262306a36Sopenharmony_ci		r = kvm_riscv_vcpu_copy_reg_indices(vcpu, user_list->reg);
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci	default:
27662306a36Sopenharmony_ci		break;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return r;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
28362306a36Sopenharmony_ci				  struct kvm_sregs *sregs)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	return -EINVAL;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
28962306a36Sopenharmony_ci				  struct kvm_sregs *sregs)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	return -EINVAL;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	return -EINVAL;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	return -EINVAL;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
30562306a36Sopenharmony_ci				  struct kvm_translation *tr)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	return -EINVAL;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	return -EINVAL;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	return -EINVAL;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_civoid kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
32362306a36Sopenharmony_ci	unsigned long mask, val;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
32662306a36Sopenharmony_ci		mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
32762306a36Sopenharmony_ci		val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		csr->hvip &= ~mask;
33062306a36Sopenharmony_ci		csr->hvip |= val;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Flush AIA high interrupts */
33462306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_civoid kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	unsigned long hvip;
34062306a36Sopenharmony_ci	struct kvm_vcpu_arch *v = &vcpu->arch;
34162306a36Sopenharmony_ci	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* Read current HVIP and VSIE CSRs */
34462306a36Sopenharmony_ci	csr->vsie = csr_read(CSR_VSIE);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* Sync-up HVIP.VSSIP bit changes does by Guest */
34762306a36Sopenharmony_ci	hvip = csr_read(CSR_HVIP);
34862306a36Sopenharmony_ci	if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
34962306a36Sopenharmony_ci		if (hvip & (1UL << IRQ_VS_SOFT)) {
35062306a36Sopenharmony_ci			if (!test_and_set_bit(IRQ_VS_SOFT,
35162306a36Sopenharmony_ci					      v->irqs_pending_mask))
35262306a36Sopenharmony_ci				set_bit(IRQ_VS_SOFT, v->irqs_pending);
35362306a36Sopenharmony_ci		} else {
35462306a36Sopenharmony_ci			if (!test_and_set_bit(IRQ_VS_SOFT,
35562306a36Sopenharmony_ci					      v->irqs_pending_mask))
35662306a36Sopenharmony_ci				clear_bit(IRQ_VS_SOFT, v->irqs_pending);
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* Sync-up AIA high interrupts */
36162306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Sync-up timer CSRs */
36462306a36Sopenharmony_ci	kvm_riscv_vcpu_timer_sync(vcpu);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ciint kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	/*
37062306a36Sopenharmony_ci	 * We only allow VS-mode software, timer, and external
37162306a36Sopenharmony_ci	 * interrupts when irq is one of the local interrupts
37262306a36Sopenharmony_ci	 * defined by RISC-V privilege specification.
37362306a36Sopenharmony_ci	 */
37462306a36Sopenharmony_ci	if (irq < IRQ_LOCAL_MAX &&
37562306a36Sopenharmony_ci	    irq != IRQ_VS_SOFT &&
37662306a36Sopenharmony_ci	    irq != IRQ_VS_TIMER &&
37762306a36Sopenharmony_ci	    irq != IRQ_VS_EXT)
37862306a36Sopenharmony_ci		return -EINVAL;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	set_bit(irq, vcpu->arch.irqs_pending);
38162306a36Sopenharmony_ci	smp_mb__before_atomic();
38262306a36Sopenharmony_ci	set_bit(irq, vcpu->arch.irqs_pending_mask);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	kvm_vcpu_kick(vcpu);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciint kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * We only allow VS-mode software, timer, and external
39362306a36Sopenharmony_ci	 * interrupts when irq is one of the local interrupts
39462306a36Sopenharmony_ci	 * defined by RISC-V privilege specification.
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	if (irq < IRQ_LOCAL_MAX &&
39762306a36Sopenharmony_ci	    irq != IRQ_VS_SOFT &&
39862306a36Sopenharmony_ci	    irq != IRQ_VS_TIMER &&
39962306a36Sopenharmony_ci	    irq != IRQ_VS_EXT)
40062306a36Sopenharmony_ci		return -EINVAL;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	clear_bit(irq, vcpu->arch.irqs_pending);
40362306a36Sopenharmony_ci	smp_mb__before_atomic();
40462306a36Sopenharmony_ci	set_bit(irq, vcpu->arch.irqs_pending_mask);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cibool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	unsigned long ie;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
41462306a36Sopenharmony_ci		<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
41562306a36Sopenharmony_ci	ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
41662306a36Sopenharmony_ci		(unsigned long)mask;
41762306a36Sopenharmony_ci	if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie)
41862306a36Sopenharmony_ci		return true;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Check AIA high interrupts */
42162306a36Sopenharmony_ci	return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_civoid kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	vcpu->arch.power_off = true;
42762306a36Sopenharmony_ci	kvm_make_request(KVM_REQ_SLEEP, vcpu);
42862306a36Sopenharmony_ci	kvm_vcpu_kick(vcpu);
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_civoid kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	vcpu->arch.power_off = false;
43462306a36Sopenharmony_ci	kvm_vcpu_wake_up(vcpu);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
43862306a36Sopenharmony_ci				    struct kvm_mp_state *mp_state)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	if (vcpu->arch.power_off)
44162306a36Sopenharmony_ci		mp_state->mp_state = KVM_MP_STATE_STOPPED;
44262306a36Sopenharmony_ci	else
44362306a36Sopenharmony_ci		mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
44962306a36Sopenharmony_ci				    struct kvm_mp_state *mp_state)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	int ret = 0;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	switch (mp_state->mp_state) {
45462306a36Sopenharmony_ci	case KVM_MP_STATE_RUNNABLE:
45562306a36Sopenharmony_ci		vcpu->arch.power_off = false;
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci	case KVM_MP_STATE_STOPPED:
45862306a36Sopenharmony_ci		kvm_riscv_vcpu_power_off(vcpu);
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	default:
46162306a36Sopenharmony_ci		ret = -EINVAL;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return ret;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
46862306a36Sopenharmony_ci					struct kvm_guest_debug *dbg)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	/* TODO; To be implemented later. */
47162306a36Sopenharmony_ci	return -EINVAL;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void kvm_riscv_vcpu_update_config(const unsigned long *isa)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	u64 henvcfg = 0;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (riscv_isa_extension_available(isa, SVPBMT))
47962306a36Sopenharmony_ci		henvcfg |= ENVCFG_PBMTE;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (riscv_isa_extension_available(isa, SSTC))
48262306a36Sopenharmony_ci		henvcfg |= ENVCFG_STCE;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (riscv_isa_extension_available(isa, ZICBOM))
48562306a36Sopenharmony_ci		henvcfg |= (ENVCFG_CBIE | ENVCFG_CBCFE);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (riscv_isa_extension_available(isa, ZICBOZ))
48862306a36Sopenharmony_ci		henvcfg |= ENVCFG_CBZE;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	csr_write(CSR_HENVCFG, henvcfg);
49162306a36Sopenharmony_ci#ifdef CONFIG_32BIT
49262306a36Sopenharmony_ci	csr_write(CSR_HENVCFGH, henvcfg >> 32);
49362306a36Sopenharmony_ci#endif
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_civoid kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	csr_write(CSR_VSSTATUS, csr->vsstatus);
50162306a36Sopenharmony_ci	csr_write(CSR_VSIE, csr->vsie);
50262306a36Sopenharmony_ci	csr_write(CSR_VSTVEC, csr->vstvec);
50362306a36Sopenharmony_ci	csr_write(CSR_VSSCRATCH, csr->vsscratch);
50462306a36Sopenharmony_ci	csr_write(CSR_VSEPC, csr->vsepc);
50562306a36Sopenharmony_ci	csr_write(CSR_VSCAUSE, csr->vscause);
50662306a36Sopenharmony_ci	csr_write(CSR_VSTVAL, csr->vstval);
50762306a36Sopenharmony_ci	csr_write(CSR_HVIP, csr->hvip);
50862306a36Sopenharmony_ci	csr_write(CSR_VSATP, csr->vsatp);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	kvm_riscv_vcpu_update_config(vcpu->arch.isa);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	kvm_riscv_gstage_update_hgatp(vcpu);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	kvm_riscv_vcpu_timer_restore(vcpu);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
51762306a36Sopenharmony_ci	kvm_riscv_vcpu_guest_fp_restore(&vcpu->arch.guest_context,
51862306a36Sopenharmony_ci					vcpu->arch.isa);
51962306a36Sopenharmony_ci	kvm_riscv_vcpu_host_vector_save(&vcpu->arch.host_context);
52062306a36Sopenharmony_ci	kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
52162306a36Sopenharmony_ci					    vcpu->arch.isa);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_load(vcpu, cpu);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	vcpu->cpu = cpu;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_civoid kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	vcpu->cpu = -1;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_put(vcpu);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	kvm_riscv_vcpu_guest_fp_save(&vcpu->arch.guest_context,
53762306a36Sopenharmony_ci				     vcpu->arch.isa);
53862306a36Sopenharmony_ci	kvm_riscv_vcpu_host_fp_restore(&vcpu->arch.host_context);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	kvm_riscv_vcpu_timer_save(vcpu);
54162306a36Sopenharmony_ci	kvm_riscv_vcpu_guest_vector_save(&vcpu->arch.guest_context,
54262306a36Sopenharmony_ci					 vcpu->arch.isa);
54362306a36Sopenharmony_ci	kvm_riscv_vcpu_host_vector_restore(&vcpu->arch.host_context);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	csr->vsstatus = csr_read(CSR_VSSTATUS);
54662306a36Sopenharmony_ci	csr->vsie = csr_read(CSR_VSIE);
54762306a36Sopenharmony_ci	csr->vstvec = csr_read(CSR_VSTVEC);
54862306a36Sopenharmony_ci	csr->vsscratch = csr_read(CSR_VSSCRATCH);
54962306a36Sopenharmony_ci	csr->vsepc = csr_read(CSR_VSEPC);
55062306a36Sopenharmony_ci	csr->vscause = csr_read(CSR_VSCAUSE);
55162306a36Sopenharmony_ci	csr->vstval = csr_read(CSR_VSTVAL);
55262306a36Sopenharmony_ci	csr->hvip = csr_read(CSR_HVIP);
55362306a36Sopenharmony_ci	csr->vsatp = csr_read(CSR_VSATP);
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	struct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (kvm_request_pending(vcpu)) {
56162306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) {
56262306a36Sopenharmony_ci			kvm_vcpu_srcu_read_unlock(vcpu);
56362306a36Sopenharmony_ci			rcuwait_wait_event(wait,
56462306a36Sopenharmony_ci				(!vcpu->arch.power_off) && (!vcpu->arch.pause),
56562306a36Sopenharmony_ci				TASK_INTERRUPTIBLE);
56662306a36Sopenharmony_ci			kvm_vcpu_srcu_read_lock(vcpu);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci			if (vcpu->arch.power_off || vcpu->arch.pause) {
56962306a36Sopenharmony_ci				/*
57062306a36Sopenharmony_ci				 * Awaken to handle a signal, request to
57162306a36Sopenharmony_ci				 * sleep again later.
57262306a36Sopenharmony_ci				 */
57362306a36Sopenharmony_ci				kvm_make_request(KVM_REQ_SLEEP, vcpu);
57462306a36Sopenharmony_ci			}
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu))
57862306a36Sopenharmony_ci			kvm_riscv_reset_vcpu(vcpu);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_UPDATE_HGATP, vcpu))
58162306a36Sopenharmony_ci			kvm_riscv_gstage_update_hgatp(vcpu);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_FENCE_I, vcpu))
58462306a36Sopenharmony_ci			kvm_riscv_fence_i_process(vcpu);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci		/*
58762306a36Sopenharmony_ci		 * The generic KVM_REQ_TLB_FLUSH is same as
58862306a36Sopenharmony_ci		 * KVM_REQ_HFENCE_GVMA_VMID_ALL
58962306a36Sopenharmony_ci		 */
59062306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_HFENCE_GVMA_VMID_ALL, vcpu))
59162306a36Sopenharmony_ci			kvm_riscv_hfence_gvma_vmid_all_process(vcpu);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_HFENCE_VVMA_ALL, vcpu))
59462306a36Sopenharmony_ci			kvm_riscv_hfence_vvma_all_process(vcpu);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (kvm_check_request(KVM_REQ_HFENCE, vcpu))
59762306a36Sopenharmony_ci			kvm_riscv_hfence_process(vcpu);
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	csr_write(CSR_HVIP, csr->hvip);
60662306a36Sopenharmony_ci	kvm_riscv_vcpu_aia_update_hvip(vcpu);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/*
61062306a36Sopenharmony_ci * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
61162306a36Sopenharmony_ci * the vCPU is running.
61262306a36Sopenharmony_ci *
61362306a36Sopenharmony_ci * This must be noinstr as instrumentation may make use of RCU, and this is not
61462306a36Sopenharmony_ci * safe during the EQS.
61562306a36Sopenharmony_ci */
61662306a36Sopenharmony_cistatic void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	guest_state_enter_irqoff();
61962306a36Sopenharmony_ci	__kvm_riscv_switch_to(&vcpu->arch);
62062306a36Sopenharmony_ci	vcpu->arch.last_exit_cpu = vcpu->cpu;
62162306a36Sopenharmony_ci	guest_state_exit_irqoff();
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	int ret;
62762306a36Sopenharmony_ci	struct kvm_cpu_trap trap;
62862306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* Mark this VCPU ran at least once */
63162306a36Sopenharmony_ci	vcpu->arch.ran_atleast_once = true;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	kvm_vcpu_srcu_read_lock(vcpu);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	switch (run->exit_reason) {
63662306a36Sopenharmony_ci	case KVM_EXIT_MMIO:
63762306a36Sopenharmony_ci		/* Process MMIO value returned from user-space */
63862306a36Sopenharmony_ci		ret = kvm_riscv_vcpu_mmio_return(vcpu, vcpu->run);
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	case KVM_EXIT_RISCV_SBI:
64162306a36Sopenharmony_ci		/* Process SBI value returned from user-space */
64262306a36Sopenharmony_ci		ret = kvm_riscv_vcpu_sbi_return(vcpu, vcpu->run);
64362306a36Sopenharmony_ci		break;
64462306a36Sopenharmony_ci	case KVM_EXIT_RISCV_CSR:
64562306a36Sopenharmony_ci		/* Process CSR value returned from user-space */
64662306a36Sopenharmony_ci		ret = kvm_riscv_vcpu_csr_return(vcpu, vcpu->run);
64762306a36Sopenharmony_ci		break;
64862306a36Sopenharmony_ci	default:
64962306a36Sopenharmony_ci		ret = 0;
65062306a36Sopenharmony_ci		break;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	if (ret) {
65362306a36Sopenharmony_ci		kvm_vcpu_srcu_read_unlock(vcpu);
65462306a36Sopenharmony_ci		return ret;
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (run->immediate_exit) {
65862306a36Sopenharmony_ci		kvm_vcpu_srcu_read_unlock(vcpu);
65962306a36Sopenharmony_ci		return -EINTR;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	vcpu_load(vcpu);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	kvm_sigset_activate(vcpu);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	ret = 1;
66762306a36Sopenharmony_ci	run->exit_reason = KVM_EXIT_UNKNOWN;
66862306a36Sopenharmony_ci	while (ret > 0) {
66962306a36Sopenharmony_ci		/* Check conditions before entering the guest */
67062306a36Sopenharmony_ci		ret = xfer_to_guest_mode_handle_work(vcpu);
67162306a36Sopenharmony_ci		if (ret)
67262306a36Sopenharmony_ci			continue;
67362306a36Sopenharmony_ci		ret = 1;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		kvm_riscv_gstage_vmid_update(vcpu);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci		kvm_riscv_check_vcpu_requests(vcpu);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		preempt_disable();
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci		/* Update AIA HW state before entering guest */
68262306a36Sopenharmony_ci		ret = kvm_riscv_vcpu_aia_update(vcpu);
68362306a36Sopenharmony_ci		if (ret <= 0) {
68462306a36Sopenharmony_ci			preempt_enable();
68562306a36Sopenharmony_ci			continue;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		local_irq_disable();
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		/*
69162306a36Sopenharmony_ci		 * Ensure we set mode to IN_GUEST_MODE after we disable
69262306a36Sopenharmony_ci		 * interrupts and before the final VCPU requests check.
69362306a36Sopenharmony_ci		 * See the comment in kvm_vcpu_exiting_guest_mode() and
69462306a36Sopenharmony_ci		 * Documentation/virt/kvm/vcpu-requests.rst
69562306a36Sopenharmony_ci		 */
69662306a36Sopenharmony_ci		vcpu->mode = IN_GUEST_MODE;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		kvm_vcpu_srcu_read_unlock(vcpu);
69962306a36Sopenharmony_ci		smp_mb__after_srcu_read_unlock();
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		/*
70262306a36Sopenharmony_ci		 * We might have got VCPU interrupts updated asynchronously
70362306a36Sopenharmony_ci		 * so update it in HW.
70462306a36Sopenharmony_ci		 */
70562306a36Sopenharmony_ci		kvm_riscv_vcpu_flush_interrupts(vcpu);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		/* Update HVIP CSR for current CPU */
70862306a36Sopenharmony_ci		kvm_riscv_update_hvip(vcpu);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		if (ret <= 0 ||
71162306a36Sopenharmony_ci		    kvm_riscv_gstage_vmid_ver_changed(&vcpu->kvm->arch.vmid) ||
71262306a36Sopenharmony_ci		    kvm_request_pending(vcpu) ||
71362306a36Sopenharmony_ci		    xfer_to_guest_mode_work_pending()) {
71462306a36Sopenharmony_ci			vcpu->mode = OUTSIDE_GUEST_MODE;
71562306a36Sopenharmony_ci			local_irq_enable();
71662306a36Sopenharmony_ci			preempt_enable();
71762306a36Sopenharmony_ci			kvm_vcpu_srcu_read_lock(vcpu);
71862306a36Sopenharmony_ci			continue;
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		/*
72262306a36Sopenharmony_ci		 * Cleanup stale TLB enteries
72362306a36Sopenharmony_ci		 *
72462306a36Sopenharmony_ci		 * Note: This should be done after G-stage VMID has been
72562306a36Sopenharmony_ci		 * updated using kvm_riscv_gstage_vmid_ver_changed()
72662306a36Sopenharmony_ci		 */
72762306a36Sopenharmony_ci		kvm_riscv_local_tlb_sanitize(vcpu);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		guest_timing_enter_irqoff();
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		kvm_riscv_vcpu_enter_exit(vcpu);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		vcpu->mode = OUTSIDE_GUEST_MODE;
73462306a36Sopenharmony_ci		vcpu->stat.exits++;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		/*
73762306a36Sopenharmony_ci		 * Save SCAUSE, STVAL, HTVAL, and HTINST because we might
73862306a36Sopenharmony_ci		 * get an interrupt between __kvm_riscv_switch_to() and
73962306a36Sopenharmony_ci		 * local_irq_enable() which can potentially change CSRs.
74062306a36Sopenharmony_ci		 */
74162306a36Sopenharmony_ci		trap.sepc = vcpu->arch.guest_context.sepc;
74262306a36Sopenharmony_ci		trap.scause = csr_read(CSR_SCAUSE);
74362306a36Sopenharmony_ci		trap.stval = csr_read(CSR_STVAL);
74462306a36Sopenharmony_ci		trap.htval = csr_read(CSR_HTVAL);
74562306a36Sopenharmony_ci		trap.htinst = csr_read(CSR_HTINST);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		/* Syncup interrupts state with HW */
74862306a36Sopenharmony_ci		kvm_riscv_vcpu_sync_interrupts(vcpu);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		/*
75162306a36Sopenharmony_ci		 * We must ensure that any pending interrupts are taken before
75262306a36Sopenharmony_ci		 * we exit guest timing so that timer ticks are accounted as
75362306a36Sopenharmony_ci		 * guest time. Transiently unmask interrupts so that any
75462306a36Sopenharmony_ci		 * pending interrupts are taken.
75562306a36Sopenharmony_ci		 *
75662306a36Sopenharmony_ci		 * There's no barrier which ensures that pending interrupts are
75762306a36Sopenharmony_ci		 * recognised, so we just hope that the CPU takes any pending
75862306a36Sopenharmony_ci		 * interrupts between the enable and disable.
75962306a36Sopenharmony_ci		 */
76062306a36Sopenharmony_ci		local_irq_enable();
76162306a36Sopenharmony_ci		local_irq_disable();
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		guest_timing_exit_irqoff();
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		local_irq_enable();
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		preempt_enable();
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		kvm_vcpu_srcu_read_lock(vcpu);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci		ret = kvm_riscv_vcpu_exit(vcpu, run, &trap);
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	kvm_sigset_deactivate(vcpu);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	vcpu_put(vcpu);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	kvm_vcpu_srcu_read_unlock(vcpu);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return ret;
78162306a36Sopenharmony_ci}
782