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(®, 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, ®); 25362306a36Sopenharmony_ci else 25462306a36Sopenharmony_ci r = kvm_riscv_vcpu_get_reg(vcpu, ®); 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(®_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, ®_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