18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/bitops.h>
78c2ecf20Sopenharmony_ci#include <linux/errno.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/kdebug.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
128c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
148c2ecf20Sopenharmony_ci#include <linux/fs.h>
158c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
168c2ecf20Sopenharmony_ci#include <linux/kvm.h>
178c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
188c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
198c2ecf20Sopenharmony_ci#include <linux/sched/stat.h>
208c2ecf20Sopenharmony_ci#include <asm/fpu.h>
218c2ecf20Sopenharmony_ci#include <asm/lbt.h>
228c2ecf20Sopenharmony_ci#include <asm/watch.h>
238c2ecf20Sopenharmony_ci#include <asm/page.h>
248c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
258c2ecf20Sopenharmony_ci#include <asm/mmu_context.h>
268c2ecf20Sopenharmony_ci#include <asm/pgalloc.h>
278c2ecf20Sopenharmony_ci#include <asm/pgtable.h>
288c2ecf20Sopenharmony_ci#include <asm/cpufeature.h>
298c2ecf20Sopenharmony_ci#include "kvmcpu.h"
308c2ecf20Sopenharmony_ci#include <asm/setup.h>
318c2ecf20Sopenharmony_ci#include <asm/time.h>
328c2ecf20Sopenharmony_ci#include <asm/paravirt.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "intc/ls3a_ipi.h"
358c2ecf20Sopenharmony_ci#include "intc/ls7a_irq.h"
368c2ecf20Sopenharmony_ci#include "intc/ls3a_ext_irq.h"
378c2ecf20Sopenharmony_ci#include "kvm_compat.h"
388c2ecf20Sopenharmony_ci#include "kvmcsr.h"
398c2ecf20Sopenharmony_ci#include "ls_irq.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * Define loongarch kvm version.
438c2ecf20Sopenharmony_ci * Add version number when qemu/kvm interface changed
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ci#define KVM_LOONGARCH_VERSION 1
468c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS
478c2ecf20Sopenharmony_ci#include "trace.h"
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct kvm_stats_debugfs_item vcpu_debugfs_entries[] = {
508c2ecf20Sopenharmony_ci	VCPU_STAT("idle", idle_exits),
518c2ecf20Sopenharmony_ci	VCPU_STAT("signal", signal_exits),
528c2ecf20Sopenharmony_ci	VCPU_STAT("interrupt", int_exits),
538c2ecf20Sopenharmony_ci	VCPU_STAT("tlbmiss_ld", excep_exits[EXCCODE_TLBL]),
548c2ecf20Sopenharmony_ci	VCPU_STAT("tlbmiss_st", excep_exits[EXCCODE_TLBS]),
558c2ecf20Sopenharmony_ci	VCPU_STAT("tlb_ifetch", excep_exits[EXCCODE_TLBI]),
568c2ecf20Sopenharmony_ci	VCPU_STAT("tlbmod", excep_exits[EXCCODE_TLBM]),
578c2ecf20Sopenharmony_ci	VCPU_STAT("tlbri", excep_exits[EXCCODE_TLBNR]),
588c2ecf20Sopenharmony_ci	VCPU_STAT("tlbxi", excep_exits[EXCCODE_TLBNX]),
598c2ecf20Sopenharmony_ci	VCPU_STAT("fp_disabled", excep_exits[EXCCODE_FPDIS]),
608c2ecf20Sopenharmony_ci	VCPU_STAT("lsx_disabled", excep_exits[EXCCODE_LSXDIS]),
618c2ecf20Sopenharmony_ci	VCPU_STAT("lasx_disabled", excep_exits[EXCCODE_LASXDIS]),
628c2ecf20Sopenharmony_ci	VCPU_STAT("fpe", excep_exits[EXCCODE_FPE]),
638c2ecf20Sopenharmony_ci	VCPU_STAT("watch", excep_exits[EXCCODE_WATCH]),
648c2ecf20Sopenharmony_ci	VCPU_STAT("gspr", excep_exits[EXCCODE_GSPR]),
658c2ecf20Sopenharmony_ci	VCPU_STAT("vz_gsfc", excep_exits[EXCCODE_GCM]),
668c2ecf20Sopenharmony_ci	VCPU_STAT("vz_hc", excep_exits[EXCCODE_HVC]),
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	VCPU_STAT("rdcsr_cpu_feature", rdcsr_cpu_feature_exits),
698c2ecf20Sopenharmony_ci	VCPU_STAT("rdcsr_misc_func", rdcsr_misc_func_exits),
708c2ecf20Sopenharmony_ci	VCPU_STAT("rdcsr_ipi_access", rdcsr_ipi_access_exits),
718c2ecf20Sopenharmony_ci	VCPU_STAT("cpucfg", cpucfg_exits),
728c2ecf20Sopenharmony_ci	VCPU_STAT("huge_dec", huge_dec_exits),
738c2ecf20Sopenharmony_ci	VCPU_STAT("huge_thp", huge_thp_exits),
748c2ecf20Sopenharmony_ci	VCPU_STAT("huge_adj", huge_adjust_exits),
758c2ecf20Sopenharmony_ci	VCPU_STAT("huge_set", huge_set_exits),
768c2ecf20Sopenharmony_ci	VCPU_STAT("huge_merg", huge_merge_exits),
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	VCPU_STAT("halt_successful_poll", halt_successful_poll),
798c2ecf20Sopenharmony_ci	VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
808c2ecf20Sopenharmony_ci	VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
818c2ecf20Sopenharmony_ci	VCPU_STAT("halt_wakeup", halt_wakeup),
828c2ecf20Sopenharmony_ci	VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
838c2ecf20Sopenharmony_ci	VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
848c2ecf20Sopenharmony_ci	{NULL}
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct kvm_stats_debugfs_item debugfs_entries[] = {
888c2ecf20Sopenharmony_ci	VM_STAT("remote_tlb_flush", remote_tlb_flush),
898c2ecf20Sopenharmony_ci	VM_STAT("pip_read_exits", pip_read_exits),
908c2ecf20Sopenharmony_ci	VM_STAT("pip_write_exits", pip_write_exits),
918c2ecf20Sopenharmony_ci	VM_STAT("vm_ioctl_irq_line", vm_ioctl_irq_line),
928c2ecf20Sopenharmony_ci	VM_STAT("ls7a_ioapic_update", ls7a_ioapic_update),
938c2ecf20Sopenharmony_ci	VM_STAT("ls7a_ioapic_set_irq", ls7a_ioapic_set_irq),
948c2ecf20Sopenharmony_ci	VM_STAT("ls7a_msi_irq", ls7a_msi_irq),
958c2ecf20Sopenharmony_ci	VM_STAT("ioapic_reg_write", ioapic_reg_write),
968c2ecf20Sopenharmony_ci	VM_STAT("ioapic_reg_read", ioapic_reg_read),
978c2ecf20Sopenharmony_ci	VM_STAT("set_ls7a_ioapic", set_ls7a_ioapic),
988c2ecf20Sopenharmony_ci	VM_STAT("get_ls7a_ioapic", get_ls7a_ioapic),
998c2ecf20Sopenharmony_ci	VM_STAT("set_ls3a_ext_irq", set_ls3a_ext_irq),
1008c2ecf20Sopenharmony_ci	VM_STAT("get_ls3a_ext_irq", get_ls3a_ext_irq),
1018c2ecf20Sopenharmony_ci	VM_STAT("ls3a_ext_irq", trigger_ls3a_ext_irq),
1028c2ecf20Sopenharmony_ci	{NULL}
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic int lvcpu_stat_get(void *address, u64 *val)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	*val = *(u64 *)address;
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ciDEFINE_SIMPLE_ATTRIBUTE(lvcpu_stat_fops, lvcpu_stat_get, NULL, "%llu\n");
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int vcpu_pid_get(void *arg, u64 *val)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)arg;
1158c2ecf20Sopenharmony_ci	if (vcpu)
1168c2ecf20Sopenharmony_ci		*val = pid_vnr(vcpu->pid);
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ciDEFINE_SIMPLE_ATTRIBUTE(vcpu_pid_fops, vcpu_pid_get, NULL, "%llu\n");
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_civoid kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct kvm_stats_debugfs_item *p;
1248c2ecf20Sopenharmony_ci	debugfs_create_file("pid", 0444, debugfs_dentry, vcpu, &vcpu_pid_fops);
1258c2ecf20Sopenharmony_ci	for (p = vcpu_debugfs_entries; p->name && p->kind == KVM_STAT_VCPU; ++p) {
1268c2ecf20Sopenharmony_ci		debugfs_create_file(p->name, 0444, debugfs_dentry,
1278c2ecf20Sopenharmony_ci				(void *)vcpu + p->offset, &lvcpu_stat_fops);
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cibool kvm_trace_guest_mode_change;
1328c2ecf20Sopenharmony_cistatic struct kvm_context __percpu *vmcs;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciint kvm_guest_mode_change_trace_reg(void)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	kvm_trace_guest_mode_change = 1;
1378c2ecf20Sopenharmony_ci	return 0;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_civoid kvm_guest_mode_change_trace_unreg(void)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	kvm_trace_guest_mode_change = 0;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	if (vcpu->arch.pv.pv_unhalted)
1488c2ecf20Sopenharmony_ci		return true;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return false;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * XXXKYMA: We are simulatoring a processor that has the WII bit set in
1558c2ecf20Sopenharmony_ci * Config7, so we are "runnable" if interrupts are pending
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ciint kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	return !!(vcpu->arch.irq_pending) || kvm_vcpu_has_events(vcpu);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cibool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return false;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ciint kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
1738c2ecf20Sopenharmony_civoid kvm_update_stolen_time(struct kvm_vcpu *vcpu)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct kvm_host_map map;
1768c2ecf20Sopenharmony_ci	struct kvm_steal_time *st;
1778c2ecf20Sopenharmony_ci	int ret = 0;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (vcpu->arch.st.guest_addr == 0)
1808c2ecf20Sopenharmony_ci		return;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ret = kvm_map_gfn(vcpu, vcpu->arch.st.guest_addr >> PAGE_SHIFT,
1838c2ecf20Sopenharmony_ci				&map, &vcpu->arch.st.cache, false);
1848c2ecf20Sopenharmony_ci	if (ret) {
1858c2ecf20Sopenharmony_ci		kvm_info("%s ret:%d\n", __func__, ret);
1868c2ecf20Sopenharmony_ci		return;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	st = map.hva + offset_in_page(vcpu->arch.st.guest_addr);
1898c2ecf20Sopenharmony_ci	if (st->version & 1)
1908c2ecf20Sopenharmony_ci		st->version += 1; /* first time write, random junk */
1918c2ecf20Sopenharmony_ci	st->version += 1;
1928c2ecf20Sopenharmony_ci	smp_wmb();
1938c2ecf20Sopenharmony_ci	st->steal += current->sched_info.run_delay -
1948c2ecf20Sopenharmony_ci		vcpu->arch.st.last_steal;
1958c2ecf20Sopenharmony_ci	vcpu->arch.st.last_steal = current->sched_info.run_delay;
1968c2ecf20Sopenharmony_ci	smp_wmb();
1978c2ecf20Sopenharmony_ci	st->version += 1;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cibool _kvm_pvtime_supported(void)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	return !!sched_info_on();
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ciint _kvm_pvtime_set_attr(struct kvm_vcpu *vcpu,
2088c2ecf20Sopenharmony_ci				struct kvm_device_attr *attr)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	u64 __user *user = (u64 __user *)attr->addr;
2118c2ecf20Sopenharmony_ci	struct kvm *kvm = vcpu->kvm;
2128c2ecf20Sopenharmony_ci	u64 ipa;
2138c2ecf20Sopenharmony_ci	int ret = 0;
2148c2ecf20Sopenharmony_ci	int idx;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (!_kvm_pvtime_supported() ||
2178c2ecf20Sopenharmony_ci		attr->attr != KVM_LARCH_VCPU_PVTIME_IPA)
2188c2ecf20Sopenharmony_ci		return -ENXIO;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (get_user(ipa, user))
2218c2ecf20Sopenharmony_ci		return -EFAULT;
2228c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(ipa, 64))
2238c2ecf20Sopenharmony_ci		return -EINVAL;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/* Check the address is in a valid memslot */
2268c2ecf20Sopenharmony_ci	idx = srcu_read_lock(&kvm->srcu);
2278c2ecf20Sopenharmony_ci	if (kvm_is_error_hva(gfn_to_hva(kvm, ipa >> PAGE_SHIFT)))
2288c2ecf20Sopenharmony_ci		ret = -EINVAL;
2298c2ecf20Sopenharmony_ci	srcu_read_unlock(&kvm->srcu, idx);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (!ret)
2328c2ecf20Sopenharmony_ci		vcpu->arch.st.guest_addr = ipa;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return ret;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ciint _kvm_pvtime_get_attr(struct kvm_vcpu *vcpu,
2388c2ecf20Sopenharmony_ci				struct kvm_device_attr *attr)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	u64 __user *user = (u64 __user *)attr->addr;
2418c2ecf20Sopenharmony_ci	u64 ipa;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (!_kvm_pvtime_supported() ||
2448c2ecf20Sopenharmony_ci		attr->attr != KVM_LARCH_VCPU_PVTIME_IPA)
2458c2ecf20Sopenharmony_ci		return -ENXIO;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	ipa = vcpu->arch.st.guest_addr;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (put_user(ipa, user))
2508c2ecf20Sopenharmony_ci		return -EFAULT;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ciint _kvm_pvtime_has_attr(struct kvm_vcpu *vcpu,
2568c2ecf20Sopenharmony_ci				struct kvm_device_attr *attr)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	switch (attr->attr) {
2598c2ecf20Sopenharmony_ci	case KVM_LARCH_VCPU_PVTIME_IPA:
2608c2ecf20Sopenharmony_ci		if (_kvm_pvtime_supported())
2618c2ecf20Sopenharmony_ci			return 0;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return -ENXIO;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct kvm_host_map map;
2708c2ecf20Sopenharmony_ci	struct kvm_steal_time *st;
2718c2ecf20Sopenharmony_ci	int ret = 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (vcpu->arch.st.guest_addr == 0)
2748c2ecf20Sopenharmony_ci		return;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	ret = kvm_map_gfn(vcpu, vcpu->arch.st.guest_addr >> PAGE_SHIFT,
2778c2ecf20Sopenharmony_ci				&map, &vcpu->arch.st.cache, false);
2788c2ecf20Sopenharmony_ci	if (ret) {
2798c2ecf20Sopenharmony_ci		kvm_info("%s ret:%d\n", __func__, ret);
2808c2ecf20Sopenharmony_ci		return;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci	st = map.hva + offset_in_page(vcpu->arch.st.guest_addr);
2838c2ecf20Sopenharmony_ci	if (st->version & 1)
2848c2ecf20Sopenharmony_ci		st->version += 1; /* first time write, random junk */
2858c2ecf20Sopenharmony_ci	st->version += 1;
2868c2ecf20Sopenharmony_ci	smp_wmb();
2878c2ecf20Sopenharmony_ci	st->preempted = KVM_VCPU_PREEMPTED;
2888c2ecf20Sopenharmony_ci	smp_wmb();
2898c2ecf20Sopenharmony_ci	st->version += 1;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic void kvm_steal_time_clear_preempted(struct kvm_vcpu *vcpu)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct kvm_host_map map;
2978c2ecf20Sopenharmony_ci	struct kvm_steal_time *st;
2988c2ecf20Sopenharmony_ci	int ret = 0;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (vcpu->arch.st.guest_addr == 0)
3018c2ecf20Sopenharmony_ci		return;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	ret = kvm_map_gfn(vcpu, vcpu->arch.st.guest_addr >> PAGE_SHIFT,
3048c2ecf20Sopenharmony_ci				&map, &vcpu->arch.st.cache, false);
3058c2ecf20Sopenharmony_ci	if (ret) {
3068c2ecf20Sopenharmony_ci		kvm_info("%s ret:%d\n", __func__, ret);
3078c2ecf20Sopenharmony_ci		return;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci	st = map.hva + offset_in_page(vcpu->arch.st.guest_addr);
3108c2ecf20Sopenharmony_ci	if (st->version & 1)
3118c2ecf20Sopenharmony_ci		st->version += 1; /* first time write, random junk */
3128c2ecf20Sopenharmony_ci	st->version += 1;
3138c2ecf20Sopenharmony_ci	smp_wmb();
3148c2ecf20Sopenharmony_ci	st->preempted = 0;
3158c2ecf20Sopenharmony_ci	smp_wmb();
3168c2ecf20Sopenharmony_ci	st->version += 1;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci#endif
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ciint kvm_arch_hardware_enable(void)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	unsigned long gcfg = 0;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* First init gtlbc, gcfg, gstat, gintc. All guest use the same config */
3278c2ecf20Sopenharmony_ci	kvm_clear_csr_gtlbc(KVM_GTLBC_USETGID | KVM_GTLBC_TOTI);
3288c2ecf20Sopenharmony_ci	kvm_write_csr_gcfg(0);
3298c2ecf20Sopenharmony_ci	kvm_write_csr_gstat(0);
3308c2ecf20Sopenharmony_ci	kvm_write_csr_gintc(0);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/*
3338c2ecf20Sopenharmony_ci	 * Enable virtualization features granting guest direct control of
3348c2ecf20Sopenharmony_ci	 * certain features:
3358c2ecf20Sopenharmony_ci	 * GCI=2:       Trap on init or unimplement cache instruction.
3368c2ecf20Sopenharmony_ci	 * TORU=0:      Trap on Root Unimplement.
3378c2ecf20Sopenharmony_ci	 * CACTRL=1:    Root control cache.
3388c2ecf20Sopenharmony_ci	 * TOP=0:       Trap on Previlege.
3398c2ecf20Sopenharmony_ci	 * TOE=0:       Trap on Exception.
3408c2ecf20Sopenharmony_ci	 * TIT=0:       Trap on Timer.
3418c2ecf20Sopenharmony_ci	 */
3428c2ecf20Sopenharmony_ci	if (cpu_has_gcip_all)
3438c2ecf20Sopenharmony_ci		gcfg |= KVM_GCFG_GCI_SECURE;
3448c2ecf20Sopenharmony_ci	if (cpu_has_matc_root)
3458c2ecf20Sopenharmony_ci		gcfg |= KVM_GCFG_MATC_ROOT;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	gcfg |= KVM_GCFG_TIT;
3488c2ecf20Sopenharmony_ci	kvm_write_csr_gcfg(gcfg);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	kvm_flush_tlb_all();
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* Enable using TGID  */
3538c2ecf20Sopenharmony_ci	kvm_set_csr_gtlbc(KVM_GTLBC_USETGID);
3548c2ecf20Sopenharmony_ci	kvm_debug("gtlbc:%llx gintc:%llx gstat:%llx gcfg:%llx",
3558c2ecf20Sopenharmony_ci			kvm_read_csr_gtlbc(), kvm_read_csr_gintc(),
3568c2ecf20Sopenharmony_ci			kvm_read_csr_gstat(), kvm_read_csr_gcfg());
3578c2ecf20Sopenharmony_ci	return 0;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_civoid kvm_arch_hardware_disable(void)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	kvm_clear_csr_gtlbc(KVM_GTLBC_USETGID | KVM_GTLBC_TOTI);
3638c2ecf20Sopenharmony_ci	kvm_write_csr_gcfg(0);
3648c2ecf20Sopenharmony_ci	kvm_write_csr_gstat(0);
3658c2ecf20Sopenharmony_ci	kvm_write_csr_gintc(0);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* Flush any remaining guest TLB entries */
3688c2ecf20Sopenharmony_ci	kvm_flush_tlb_all();
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ciint kvm_arch_hardware_setup(void *opaque)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	return 0;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ciint kvm_arch_check_processor_compat(void *rtn)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	return 0;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ciint kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	/* Allocate page table to map GPA -> RPA */
3848c2ecf20Sopenharmony_ci	kvm->arch.gpa_mm.pgd = kvm_pgd_alloc();
3858c2ecf20Sopenharmony_ci	if (!kvm->arch.gpa_mm.pgd)
3868c2ecf20Sopenharmony_ci		return -ENOMEM;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	kvm->arch.cpucfg_lasx = (read_cpucfg(LOONGARCH_CPUCFG2) &
3898c2ecf20Sopenharmony_ci					  CPUCFG2_LASX);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	_kvm_init_iocsr(kvm);
3928c2ecf20Sopenharmony_ci	kvm->arch.vmcs = vmcs;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic void kvm_free_vcpus(struct kvm *kvm)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	unsigned int i;
4008c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm) {
4038c2ecf20Sopenharmony_ci		kvm_vcpu_destroy(vcpu);
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	mutex_lock(&kvm->lock);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	for (i = 0; i < atomic_read(&kvm->online_vcpus); i++)
4098c2ecf20Sopenharmony_ci		kvm->vcpus[i] = NULL;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	atomic_set(&kvm->online_vcpus, 0);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	mutex_unlock(&kvm->lock);
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_civoid kvm_arch_destroy_vm(struct kvm *kvm)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	kvm_destroy_ls3a_ipi(kvm);
4198c2ecf20Sopenharmony_ci	kvm_destroy_ls7a_ioapic(kvm);
4208c2ecf20Sopenharmony_ci	kvm_destroy_ls3a_ext_irq(kvm);
4218c2ecf20Sopenharmony_ci	kvm_free_vcpus(kvm);
4228c2ecf20Sopenharmony_ci	_kvm_destroy_mm(kvm);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cilong kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl,
4268c2ecf20Sopenharmony_ci			unsigned long arg)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciint kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
4328c2ecf20Sopenharmony_ci			    unsigned long npages)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciint kvm_arch_prepare_memory_region(struct kvm *kvm,
4388c2ecf20Sopenharmony_ci				   struct kvm_memory_slot *memslot,
4398c2ecf20Sopenharmony_ci				   const struct kvm_userspace_memory_region *mem,
4408c2ecf20Sopenharmony_ci				   enum kvm_mr_change change)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	return 0;
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic void _kvm_new_vpid(unsigned long cpu, struct kvm_vcpu *vcpu)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct kvm_context *context;
4488c2ecf20Sopenharmony_ci	unsigned long vpid;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
4518c2ecf20Sopenharmony_ci	vpid = context->vpid_cache;
4528c2ecf20Sopenharmony_ci	if (!(++vpid & context->gid_mask)) {
4538c2ecf20Sopenharmony_ci		if (!vpid)              /* fix version if needed */
4548c2ecf20Sopenharmony_ci			vpid = context->gid_fisrt_ver;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		++vpid;         /* vpid 0 reserved for root */
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		/* start new vpid cycle */
4598c2ecf20Sopenharmony_ci		kvm_flush_tlb_all();
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	context->vpid_cache = vpid;
4638c2ecf20Sopenharmony_ci	vcpu->arch.vpid[cpu] = vpid;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci/* Returns 1 if the guest TLB may be clobbered */
4678c2ecf20Sopenharmony_cistatic int _kvm_check_requests(struct kvm_vcpu *vcpu, int cpu)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	int ret = 0;
4708c2ecf20Sopenharmony_ci	int i;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (!kvm_request_pending(vcpu))
4738c2ecf20Sopenharmony_ci		return 0;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu)) {
4768c2ecf20Sopenharmony_ci		/* Drop all vpids for this VCPU */
4778c2ecf20Sopenharmony_ci		for_each_possible_cpu(i)
4788c2ecf20Sopenharmony_ci			vcpu->arch.vpid[i] = 0;
4798c2ecf20Sopenharmony_ci		/* This will clobber guest TLB contents too */
4808c2ecf20Sopenharmony_ci		ret = 1;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	return ret;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic void _kvm_update_vmid(struct kvm_vcpu *vcpu, int cpu)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct kvm_context *context;
4898c2ecf20Sopenharmony_ci	bool migrated;
4908c2ecf20Sopenharmony_ci	unsigned int gstinfo_gidmask, gstinfo_gid = 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/*
4938c2ecf20Sopenharmony_ci	 * Are we entering guest context on a different CPU to last time?
4948c2ecf20Sopenharmony_ci	 * If so, the VCPU's guest TLB state on this CPU may be stale.
4958c2ecf20Sopenharmony_ci	 */
4968c2ecf20Sopenharmony_ci	context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
4978c2ecf20Sopenharmony_ci	migrated = (vcpu->arch.last_exec_cpu != cpu);
4988c2ecf20Sopenharmony_ci	vcpu->arch.last_exec_cpu = cpu;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	/*
5018c2ecf20Sopenharmony_ci	 * Check if our vpid is of an older version and thus invalid.
5028c2ecf20Sopenharmony_ci	 *
5038c2ecf20Sopenharmony_ci	 * We also discard the stored vpid if we've executed on
5048c2ecf20Sopenharmony_ci	 * another CPU, as the guest mappings may have changed without
5058c2ecf20Sopenharmony_ci	 * hypervisor knowledge.
5068c2ecf20Sopenharmony_ci	 */
5078c2ecf20Sopenharmony_ci	gstinfo_gidmask = context->gid_mask << KVM_GSTAT_GID_SHIFT;
5088c2ecf20Sopenharmony_ci	if (migrated ||
5098c2ecf20Sopenharmony_ci			(vcpu->arch.vpid[cpu] ^ context->vpid_cache) &
5108c2ecf20Sopenharmony_ci			context->gid_ver_mask) {
5118c2ecf20Sopenharmony_ci		_kvm_new_vpid(cpu, vcpu);
5128c2ecf20Sopenharmony_ci		trace_kvm_vpid_change(vcpu, vcpu->arch.vpid[cpu]);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci	gstinfo_gid = (vcpu->arch.vpid[cpu] & context->gid_mask) <<
5158c2ecf20Sopenharmony_ci		KVM_GSTAT_GID_SHIFT;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* Restore GSTAT(0x50).vpid */
5188c2ecf20Sopenharmony_ci	kvm_change_csr_gstat(gstinfo_gidmask, gstinfo_gid);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci/*
5228c2ecf20Sopenharmony_ci * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
5238c2ecf20Sopenharmony_ci */
5248c2ecf20Sopenharmony_cistatic int _kvm_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	unsigned long exst = vcpu->arch.host_estat;
5278c2ecf20Sopenharmony_ci	u32 intr = exst & 0x1fff; /* ignore NMI */
5288c2ecf20Sopenharmony_ci	u32 exccode = (exst & KVM_ESTAT_EXC) >> KVM_ESTAT_EXC_SHIFT;
5298c2ecf20Sopenharmony_ci	u32 __user *opc = (u32 __user *) vcpu->arch.pc;
5308c2ecf20Sopenharmony_ci	int ret = RESUME_GUEST, cpu;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	vcpu->mode = OUTSIDE_GUEST_MODE;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* Set a default exit reason */
5358c2ecf20Sopenharmony_ci	run->exit_reason = KVM_EXIT_UNKNOWN;
5368c2ecf20Sopenharmony_ci	run->ready_for_interrupt_injection = 1;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/*
5398c2ecf20Sopenharmony_ci	 * Set the appropriate status bits based on host CPU features,
5408c2ecf20Sopenharmony_ci	 * before we hit the scheduler
5418c2ecf20Sopenharmony_ci	 */
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	local_irq_enable();
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	kvm_debug("%s: exst: %lx, PC: %p, kvm_run: %p, kvm_vcpu: %p\n",
5468c2ecf20Sopenharmony_ci			__func__, exst, opc, run, vcpu);
5478c2ecf20Sopenharmony_ci	trace_kvm_exit(vcpu, exccode);
5488c2ecf20Sopenharmony_ci	if (exccode) {
5498c2ecf20Sopenharmony_ci		vcpu->stat.excep_exits[exccode]++;
5508c2ecf20Sopenharmony_ci		ret = _kvm_handle_fault(vcpu, exccode);
5518c2ecf20Sopenharmony_ci	} else {
5528c2ecf20Sopenharmony_ci		WARN(!intr, "suspicious vm exiting");
5538c2ecf20Sopenharmony_ci		++vcpu->stat.int_exits;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		if (need_resched())
5568c2ecf20Sopenharmony_ci			cond_resched();
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		ret = RESUME_GUEST;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
5628c2ecf20Sopenharmony_ci	if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu))
5638c2ecf20Sopenharmony_ci		kvm_update_stolen_time(vcpu);
5648c2ecf20Sopenharmony_ci#endif
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	cond_resched();
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	local_irq_disable();
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (ret == RESUME_GUEST) {
5718c2ecf20Sopenharmony_ci		/* Only check for signals if not already exiting to userspace */
5728c2ecf20Sopenharmony_ci		if (signal_pending(current)) {
5738c2ecf20Sopenharmony_ci			run->exit_reason = KVM_EXIT_INTR;
5748c2ecf20Sopenharmony_ci			ret = (-EINTR << 2) | RESUME_HOST;
5758c2ecf20Sopenharmony_ci			++vcpu->stat.signal_exits;
5768c2ecf20Sopenharmony_ci			trace_kvm_exit(vcpu, KVM_TRACE_EXIT_SIGNAL);
5778c2ecf20Sopenharmony_ci			return ret;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		trace_kvm_reenter(vcpu);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		kvm_acquire_timer(vcpu);
5838c2ecf20Sopenharmony_ci		_kvm_deliver_intr(vcpu);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		/*
5868c2ecf20Sopenharmony_ci		 * Make sure the read of VCPU requests in vcpu_reenter()
5878c2ecf20Sopenharmony_ci		 * callback is not reordered ahead of the write to vcpu->mode,
5888c2ecf20Sopenharmony_ci		 * or we could miss a TLB flush request while the requester sees
5898c2ecf20Sopenharmony_ci		 * the VCPU as outside of guest mode and not needing an IPI.
5908c2ecf20Sopenharmony_ci		 */
5918c2ecf20Sopenharmony_ci		smp_store_mb(vcpu->mode, IN_GUEST_MODE);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		cpu = smp_processor_id();
5948c2ecf20Sopenharmony_ci		_kvm_check_requests(vcpu, cpu);
5958c2ecf20Sopenharmony_ci		_kvm_update_vmid(vcpu, cpu);
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return ret;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci/* low level hrtimer wake routine */
6028c2ecf20Sopenharmony_cistatic enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	vcpu = container_of(timer, struct kvm_vcpu, arch.swtimer);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	_kvm_queue_irq(vcpu, LARCH_INT_TIMER);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	rcuwait_wake_up(&vcpu->wait);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return kvm_count_timeout(vcpu);
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ciint kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	return 0;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ciint kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	int i;
6238c2ecf20Sopenharmony_ci	unsigned long timer_hz;
6248c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	for_each_possible_cpu(i)
6278c2ecf20Sopenharmony_ci		vcpu->arch.vpid[i] = 0;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	hrtimer_init(&vcpu->arch.swtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
6308c2ecf20Sopenharmony_ci	vcpu->arch.swtimer.function = kvm_swtimer_wakeup;
6318c2ecf20Sopenharmony_ci	vcpu->arch.fpu_enabled = true;
6328c2ecf20Sopenharmony_ci	vcpu->arch.lsx_enabled = true;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	vcpu->kvm->arch.online_vcpus = vcpu->vcpu_id + 1;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	vcpu->arch.host_eentry = kvm_csr_readq(KVM_CSR_EENTRY);
6378c2ecf20Sopenharmony_ci	vcpu->arch.guest_eentry = (unsigned long)kvm_exception_entry;
6388c2ecf20Sopenharmony_ci	vcpu->arch.vcpu_run = kvm_enter_guest;
6398c2ecf20Sopenharmony_ci	vcpu->arch.handle_exit = _kvm_handle_exit;
6408c2ecf20Sopenharmony_ci	vcpu->arch.csr = kzalloc(sizeof(struct loongarch_csrs), GFP_KERNEL);
6418c2ecf20Sopenharmony_ci	/*
6428c2ecf20Sopenharmony_ci	 * kvm all exceptions share one exception entry, and host <-> guest switch
6438c2ecf20Sopenharmony_ci	 * also switch excfg.VS field, keep host excfg.VS info here
6448c2ecf20Sopenharmony_ci	 */
6458c2ecf20Sopenharmony_ci	vcpu->arch.host_ecfg = (kvm_read_csr_ecfg() & KVM_ECFG_VS);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (!vcpu->arch.csr)
6488c2ecf20Sopenharmony_ci		return -ENOMEM;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	/* Init */
6518c2ecf20Sopenharmony_ci	vcpu->arch.last_sched_cpu = -1;
6528c2ecf20Sopenharmony_ci	vcpu->arch.last_exec_cpu = -1;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	/*
6558c2ecf20Sopenharmony_ci	 * Initialize guest register state to valid architectural reset state.
6568c2ecf20Sopenharmony_ci	 */
6578c2ecf20Sopenharmony_ci	timer_hz = calc_const_freq();
6588c2ecf20Sopenharmony_ci	kvm_init_timer(vcpu, timer_hz);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* Set Initialize mode for GUEST */
6618c2ecf20Sopenharmony_ci	kvm_write_sw_gcsr(csr, KVM_CSR_CRMD, KVM_CRMD_DA);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	/* Set cpuid */
6648c2ecf20Sopenharmony_ci	kvm_write_sw_gcsr(csr, KVM_CSR_TMID, vcpu->vcpu_id);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	/* start with no pending virtual guest interrupts */
6678c2ecf20Sopenharmony_ci	csr->csrs[KVM_CSR_GINTC] = 0;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return 0;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_civoid kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	int cpu;
6758c2ecf20Sopenharmony_ci	struct kvm_context *context;
6768c2ecf20Sopenharmony_ci	struct gfn_to_pfn_cache *cache = &vcpu->arch.st.cache;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	hrtimer_cancel(&vcpu->arch.swtimer);
6798c2ecf20Sopenharmony_ci	kvm_mmu_free_memory_caches(vcpu);
6808c2ecf20Sopenharmony_ci	if (vcpu->arch.st.guest_addr)
6818c2ecf20Sopenharmony_ci		kvm_release_pfn(cache->pfn, cache->dirty, cache);
6828c2ecf20Sopenharmony_ci	kfree(vcpu->arch.csr);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/*
6858c2ecf20Sopenharmony_ci	 * If the VCPU is freed and reused as another VCPU, we don't want the
6868c2ecf20Sopenharmony_ci	 * matching pointer wrongly hanging around in last_vcpu.
6878c2ecf20Sopenharmony_ci	 */
6888c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
6898c2ecf20Sopenharmony_ci		context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
6908c2ecf20Sopenharmony_ci		if (context->last_vcpu == vcpu)
6918c2ecf20Sopenharmony_ci			context->last_vcpu = NULL;
6928c2ecf20Sopenharmony_ci	}
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
6968c2ecf20Sopenharmony_ci		KVM_GUESTDBG_USE_SW_BP | KVM_GUESTDBG_SINGLESTEP)
6978c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
6988c2ecf20Sopenharmony_ci					struct kvm_guest_debug *dbg)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	int ret = 0;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) {
7038c2ecf20Sopenharmony_ci		ret = -EINVAL;
7048c2ecf20Sopenharmony_ci		goto out;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci	if (dbg->control & KVM_GUESTDBG_ENABLE) {
7078c2ecf20Sopenharmony_ci		vcpu->guest_debug = dbg->control;
7088c2ecf20Sopenharmony_ci		/* No hardware breakpoint */
7098c2ecf20Sopenharmony_ci	} else {
7108c2ecf20Sopenharmony_ci		vcpu->guest_debug = 0;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ciout:
7138c2ecf20Sopenharmony_ci	return ret;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	int r = -EINTR;
7198c2ecf20Sopenharmony_ci	int cpu;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	vcpu_load(vcpu);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	kvm_sigset_activate(vcpu);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (vcpu->mmio_needed) {
7268c2ecf20Sopenharmony_ci		if (!vcpu->mmio_is_write)
7278c2ecf20Sopenharmony_ci			_kvm_complete_mmio_read(vcpu, vcpu->run);
7288c2ecf20Sopenharmony_ci		vcpu->mmio_needed = 0;
7298c2ecf20Sopenharmony_ci	} else if (vcpu->arch.is_hypcall) {
7308c2ecf20Sopenharmony_ci		/* set return value for hypercall v0 register */
7318c2ecf20Sopenharmony_ci		vcpu->arch.gprs[REG_A0] = vcpu->run->hypercall.ret;
7328c2ecf20Sopenharmony_ci		vcpu->arch.is_hypcall = 0;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (vcpu->run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) {
7368c2ecf20Sopenharmony_ci		if (!vcpu->run->iocsr_io.is_write)
7378c2ecf20Sopenharmony_ci			_kvm_complete_iocsr_read(vcpu, vcpu->run);
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	/* clear exit_reason */
7418c2ecf20Sopenharmony_ci	vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
7428c2ecf20Sopenharmony_ci	if (vcpu->run->immediate_exit)
7438c2ecf20Sopenharmony_ci		goto out;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	lose_fpu(1);
7468c2ecf20Sopenharmony_ci	lose_lbt(1);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
7498c2ecf20Sopenharmony_ci	if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu))
7508c2ecf20Sopenharmony_ci		kvm_update_stolen_time(vcpu);
7518c2ecf20Sopenharmony_ci#endif
7528c2ecf20Sopenharmony_ci	local_irq_disable();
7538c2ecf20Sopenharmony_ci	guest_enter_irqoff();
7548c2ecf20Sopenharmony_ci	trace_kvm_enter(vcpu);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/*
7578c2ecf20Sopenharmony_ci	 * Make sure the read of VCPU requests in vcpu_run() callback is not
7588c2ecf20Sopenharmony_ci	 * reordered ahead of the write to vcpu->mode, or we could miss a TLB
7598c2ecf20Sopenharmony_ci	 * flush request while the requester sees the VCPU as outside of guest
7608c2ecf20Sopenharmony_ci	 * mode and not needing an IPI.
7618c2ecf20Sopenharmony_ci	 */
7628c2ecf20Sopenharmony_ci	smp_store_mb(vcpu->mode, IN_GUEST_MODE);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	cpu = smp_processor_id();
7658c2ecf20Sopenharmony_ci	kvm_acquire_timer(vcpu);
7668c2ecf20Sopenharmony_ci	/* Check if we have any exceptions/interrupts pending */
7678c2ecf20Sopenharmony_ci	_kvm_deliver_intr(vcpu);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	_kvm_check_requests(vcpu, cpu);
7708c2ecf20Sopenharmony_ci	_kvm_update_vmid(vcpu, cpu);
7718c2ecf20Sopenharmony_ci	r = kvm_enter_guest(vcpu->run, vcpu);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	trace_kvm_out(vcpu);
7748c2ecf20Sopenharmony_ci	guest_exit_irqoff();
7758c2ecf20Sopenharmony_ci	local_irq_enable();
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ciout:
7788c2ecf20Sopenharmony_ci	kvm_sigset_deactivate(vcpu);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	vcpu_put(vcpu);
7818c2ecf20Sopenharmony_ci	return r;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ciint kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
7858c2ecf20Sopenharmony_ci			     struct kvm_loongarch_interrupt *irq)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	int intr = (int)irq->irq;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	if (intr < 0) {
7908c2ecf20Sopenharmony_ci		_kvm_dequeue_irq(vcpu, -intr);
7918c2ecf20Sopenharmony_ci		return 0;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	_kvm_queue_irq(vcpu, intr);
7958c2ecf20Sopenharmony_ci	kvm_vcpu_kick(vcpu);
7968c2ecf20Sopenharmony_ci	return 0;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
8008c2ecf20Sopenharmony_ci				    struct kvm_mp_state *mp_state)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
8068c2ecf20Sopenharmony_ci				    struct kvm_mp_state *mp_state)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci/**
8128c2ecf20Sopenharmony_ci * kvm_migrate_count() - Migrate timer.
8138c2ecf20Sopenharmony_ci * @vcpu:       Virtual CPU.
8148c2ecf20Sopenharmony_ci *
8158c2ecf20Sopenharmony_ci * Migrate hrtimer to the current CPU by cancelling and restarting it
8168c2ecf20Sopenharmony_ci * if it was running prior to being cancelled.
8178c2ecf20Sopenharmony_ci *
8188c2ecf20Sopenharmony_ci * Must be called when the VCPU is migrated to a different CPU to ensure that
8198c2ecf20Sopenharmony_ci * timer expiry during guest execution interrupts the guest and causes the
8208c2ecf20Sopenharmony_ci * interrupt to be delivered in a timely manner.
8218c2ecf20Sopenharmony_ci */
8228c2ecf20Sopenharmony_cistatic void kvm_migrate_count(struct kvm_vcpu *vcpu)
8238c2ecf20Sopenharmony_ci{
8248c2ecf20Sopenharmony_ci	if (hrtimer_cancel(&vcpu->arch.swtimer))
8258c2ecf20Sopenharmony_ci		hrtimer_restart(&vcpu->arch.swtimer);
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct kvm_context *context;
8318c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
8328c2ecf20Sopenharmony_ci	bool migrated, all;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	/*
8358c2ecf20Sopenharmony_ci	 * Have we migrated to a different CPU?
8368c2ecf20Sopenharmony_ci	 * If so, any old guest TLB state may be stale.
8378c2ecf20Sopenharmony_ci	 */
8388c2ecf20Sopenharmony_ci	migrated = (vcpu->arch.last_sched_cpu != cpu);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	/*
8418c2ecf20Sopenharmony_ci	 * Was this the last VCPU to run on this CPU?
8428c2ecf20Sopenharmony_ci	 * If not, any old guest state from this VCPU will have been clobbered.
8438c2ecf20Sopenharmony_ci	 */
8448c2ecf20Sopenharmony_ci	context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
8458c2ecf20Sopenharmony_ci	all = migrated || (context->last_vcpu != vcpu);
8468c2ecf20Sopenharmony_ci	context->last_vcpu = vcpu;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/*
8498c2ecf20Sopenharmony_ci	 * Restore timer state regardless
8508c2ecf20Sopenharmony_ci	 */
8518c2ecf20Sopenharmony_ci	kvm_restore_timer(vcpu);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	/* Control guest page CCA attribute */
8548c2ecf20Sopenharmony_ci	kvm_change_csr_gcfg(KVM_GCFG_MATC_MASK, KVM_GCFG_MATC_ROOT);
8558c2ecf20Sopenharmony_ci	/* Restore hardware perf csr */
8568c2ecf20Sopenharmony_ci	kvm_restore_hw_perf(vcpu);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
8598c2ecf20Sopenharmony_ci	kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
8608c2ecf20Sopenharmony_ci#endif
8618c2ecf20Sopenharmony_ci	/* Don't bother restoring registers multiple times unless necessary */
8628c2ecf20Sopenharmony_ci	if (!all)
8638c2ecf20Sopenharmony_ci		return 0;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	kvm_write_csr_gcntc((ulong)vcpu->kvm->arch.stablecounter_gftoffset);
8668c2ecf20Sopenharmony_ci	/*
8678c2ecf20Sopenharmony_ci	 * Restore guest CSR registers
8688c2ecf20Sopenharmony_ci	 */
8698c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_CRMD);
8708c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_PRMD);
8718c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_EUEN);
8728c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_MISC);
8738c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_ECFG);
8748c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_ERA);
8758c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_BADV);
8768c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_BADI);
8778c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_EENTRY);
8788c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBIDX);
8798c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBEHI);
8808c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBELO0);
8818c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBELO1);
8828c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_ASID);
8838c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_PGDL);
8848c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_PGDH);
8858c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_PWCTL0);
8868c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_PWCTL1);
8878c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_STLBPGSIZE);
8888c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_RVACFG);
8898c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_CPUID);
8908c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS0);
8918c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS1);
8928c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS2);
8938c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS3);
8948c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS4);
8958c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS5);
8968c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS6);
8978c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_KS7);
8988c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TMID);
8998c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_CNTC);
9008c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRENTRY);
9018c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRBADV);
9028c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRERA);
9038c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRSAVE);
9048c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRELO0);
9058c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRELO1);
9068c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBREHI);
9078c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_TLBRPRMD);
9088c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_DMWIN0);
9098c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_DMWIN1);
9108c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_DMWIN2);
9118c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_DMWIN3);
9128c2ecf20Sopenharmony_ci	kvm_restore_hw_gcsr(csr, KVM_CSR_LLBCTL);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	/* restore Root.Guestexcept from unused Guest guestexcept register */
9158c2ecf20Sopenharmony_ci	kvm_write_csr_gintc(csr->csrs[KVM_CSR_GINTC]);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	/*
9188c2ecf20Sopenharmony_ci	 * We should clear linked load bit to break interrupted atomics. This
9198c2ecf20Sopenharmony_ci	 * prevents a SC on the next VCPU from succeeding by matching a LL on
9208c2ecf20Sopenharmony_ci	 * the previous VCPU.
9218c2ecf20Sopenharmony_ci	 */
9228c2ecf20Sopenharmony_ci	if (vcpu->kvm->created_vcpus > 1)
9238c2ecf20Sopenharmony_ci		kvm_set_gcsr_llbctl(KVM_LLBCTL_WCLLB);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	return 0;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci/* Restore ASID once we are scheduled back after preemption */
9298c2ecf20Sopenharmony_civoid kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	unsigned long flags;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	local_irq_save(flags);
9348c2ecf20Sopenharmony_ci	vcpu->cpu = cpu;
9358c2ecf20Sopenharmony_ci	if (vcpu->arch.last_sched_cpu != cpu) {
9368c2ecf20Sopenharmony_ci		kvm_debug("[%d->%d]KVM VCPU[%d] switch\n",
9378c2ecf20Sopenharmony_ci				vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
9388c2ecf20Sopenharmony_ci		/*
9398c2ecf20Sopenharmony_ci		 * Migrate the timer interrupt to the current CPU so that it
9408c2ecf20Sopenharmony_ci		 * always interrupts the guest and synchronously triggers a
9418c2ecf20Sopenharmony_ci		 * guest timer interrupt.
9428c2ecf20Sopenharmony_ci		 */
9438c2ecf20Sopenharmony_ci		kvm_migrate_count(vcpu);
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	/* restore guest state to registers */
9478c2ecf20Sopenharmony_ci	_kvm_vcpu_load(vcpu, cpu);
9488c2ecf20Sopenharmony_ci	kvm_steal_time_clear_preempted(vcpu);
9498c2ecf20Sopenharmony_ci	local_irq_restore(flags);
9508c2ecf20Sopenharmony_ci}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_cistatic int _kvm_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	kvm_lose_fpu(vcpu);
9578c2ecf20Sopenharmony_ci	kvm_lose_hw_perf(vcpu);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_CRMD);
9608c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PRMD);
9618c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_EUEN);
9628c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_MISC);
9638c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_ECFG);
9648c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_ERA);
9658c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_BADV);
9668c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_BADI);
9678c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_EENTRY);
9688c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBIDX);
9698c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBEHI);
9708c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBELO0);
9718c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBELO1);
9728c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_ASID);
9738c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PGDL);
9748c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PGDH);
9758c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PGD);
9768c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PWCTL0);
9778c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PWCTL1);
9788c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_STLBPGSIZE);
9798c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_RVACFG);
9808c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_CPUID);
9818c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PRCFG1);
9828c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PRCFG2);
9838c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_PRCFG3);
9848c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS0);
9858c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS1);
9868c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS2);
9878c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS3);
9888c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS4);
9898c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS5);
9908c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS6);
9918c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_KS7);
9928c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TMID);
9938c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_CNTC);
9948c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_LLBCTL);
9958c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRENTRY);
9968c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRBADV);
9978c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRERA);
9988c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRSAVE);
9998c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRELO0);
10008c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRELO1);
10018c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBREHI);
10028c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_TLBRPRMD);
10038c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_DMWIN0);
10048c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_DMWIN1);
10058c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_DMWIN2);
10068c2ecf20Sopenharmony_ci	kvm_save_hw_gcsr(csr, KVM_CSR_DMWIN3);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* save Root.Guestexcept in unused Guest guestexcept register */
10098c2ecf20Sopenharmony_ci	kvm_save_timer(vcpu);
10108c2ecf20Sopenharmony_ci	csr->csrs[KVM_CSR_GINTC] = kvm_read_csr_gintc();
10118c2ecf20Sopenharmony_ci	return 0;
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci/* ASID can change if another task is scheduled during preemption */
10158c2ecf20Sopenharmony_civoid kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	unsigned long flags;
10188c2ecf20Sopenharmony_ci	int cpu;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	local_irq_save(flags);
10218c2ecf20Sopenharmony_ci	cpu = smp_processor_id();
10228c2ecf20Sopenharmony_ci	vcpu->arch.last_sched_cpu = cpu;
10238c2ecf20Sopenharmony_ci	vcpu->cpu = -1;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	/* save guest state in registers */
10268c2ecf20Sopenharmony_ci	_kvm_vcpu_put(vcpu, cpu);
10278c2ecf20Sopenharmony_ci	kvm_steal_time_set_preempted(vcpu);
10288c2ecf20Sopenharmony_ci	local_irq_restore(flags);
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic int _kvm_get_one_reg(struct kvm_vcpu *vcpu,
10328c2ecf20Sopenharmony_ci		const struct kvm_one_reg *reg, s64 *v)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
10358c2ecf20Sopenharmony_ci	int reg_idx, ret;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if ((reg->id & KVM_IOC_CSRID(0)) == KVM_IOC_CSRID(0)) {
10388c2ecf20Sopenharmony_ci		reg_idx = KVM_GET_IOC_CSRIDX(reg->id);
10398c2ecf20Sopenharmony_ci		ret = _kvm_getcsr(vcpu, reg_idx, v, 0);
10408c2ecf20Sopenharmony_ci		if (ret == 0)
10418c2ecf20Sopenharmony_ci			return ret;
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	switch (reg->id) {
10458c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR0:
10468c2ecf20Sopenharmony_ci		*v = vcpu->arch.lbt.scr0;
10478c2ecf20Sopenharmony_ci		break;
10488c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR1:
10498c2ecf20Sopenharmony_ci		*v = vcpu->arch.lbt.scr1;
10508c2ecf20Sopenharmony_ci		break;
10518c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR2:
10528c2ecf20Sopenharmony_ci		*v = vcpu->arch.lbt.scr2;
10538c2ecf20Sopenharmony_ci		break;
10548c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR3:
10558c2ecf20Sopenharmony_ci		*v = vcpu->arch.lbt.scr3;
10568c2ecf20Sopenharmony_ci		break;
10578c2ecf20Sopenharmony_ci	case KVM_REG_LBT_FLAGS:
10588c2ecf20Sopenharmony_ci		*v = vcpu->arch.lbt.eflags;
10598c2ecf20Sopenharmony_ci		break;
10608c2ecf20Sopenharmony_ci	case KVM_REG_LBT_FTOP:
10618c2ecf20Sopenharmony_ci		*v = vcpu->arch.fpu.ftop;
10628c2ecf20Sopenharmony_ci		break;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	case KVM_REG_LOONGARCH_COUNTER:
10658c2ecf20Sopenharmony_ci		*v = drdtime() + vcpu->kvm->arch.stablecounter_gftoffset;
10668c2ecf20Sopenharmony_ci		break;
10678c2ecf20Sopenharmony_ci	default:
10688c2ecf20Sopenharmony_ci		if ((reg->id & KVM_REG_LOONGARCH_MASK) != KVM_REG_LOONGARCH_CSR)
10698c2ecf20Sopenharmony_ci			return -EINVAL;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci		reg_idx = KVM_GET_IOC_CSRIDX(reg->id);
10728c2ecf20Sopenharmony_ci		if (reg_idx < CSR_ALL_SIZE)
10738c2ecf20Sopenharmony_ci			*v = kvm_read_sw_gcsr(csr, reg_idx);
10748c2ecf20Sopenharmony_ci		else
10758c2ecf20Sopenharmony_ci			return -EINVAL;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci	return 0;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic int _kvm_set_one_reg(struct kvm_vcpu *vcpu,
10818c2ecf20Sopenharmony_ci		const struct kvm_one_reg *reg,
10828c2ecf20Sopenharmony_ci		s64 v)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
10858c2ecf20Sopenharmony_ci	struct gfn_to_pfn_cache *cache;
10868c2ecf20Sopenharmony_ci	int ret = 0;
10878c2ecf20Sopenharmony_ci	unsigned long flags;
10888c2ecf20Sopenharmony_ci	u64 val;
10898c2ecf20Sopenharmony_ci	int reg_idx;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	val = v;
10928c2ecf20Sopenharmony_ci	if ((reg->id & KVM_IOC_CSRID(0)) == KVM_IOC_CSRID(0)) {
10938c2ecf20Sopenharmony_ci		reg_idx = KVM_GET_IOC_CSRIDX(reg->id);
10948c2ecf20Sopenharmony_ci		ret = _kvm_setcsr(vcpu, reg_idx, &val, 0);
10958c2ecf20Sopenharmony_ci		if (ret == 0)
10968c2ecf20Sopenharmony_ci			return ret;
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	switch (reg->id) {
11008c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR0:
11018c2ecf20Sopenharmony_ci		vcpu->arch.lbt.scr0 = val;
11028c2ecf20Sopenharmony_ci		break;
11038c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR1:
11048c2ecf20Sopenharmony_ci		vcpu->arch.lbt.scr1 = val;
11058c2ecf20Sopenharmony_ci		break;
11068c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR2:
11078c2ecf20Sopenharmony_ci		vcpu->arch.lbt.scr2 = val;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	case KVM_REG_LBT_SCR3:
11108c2ecf20Sopenharmony_ci		vcpu->arch.lbt.scr3 = val;
11118c2ecf20Sopenharmony_ci		break;
11128c2ecf20Sopenharmony_ci	case KVM_REG_LBT_FLAGS:
11138c2ecf20Sopenharmony_ci		vcpu->arch.lbt.eflags = val;
11148c2ecf20Sopenharmony_ci		break;
11158c2ecf20Sopenharmony_ci	case KVM_REG_LBT_FTOP:
11168c2ecf20Sopenharmony_ci		vcpu->arch.fpu.ftop = val;
11178c2ecf20Sopenharmony_ci		break;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	case KVM_REG_LOONGARCH_COUNTER:
11208c2ecf20Sopenharmony_ci		local_irq_save(flags);
11218c2ecf20Sopenharmony_ci		/*
11228c2ecf20Sopenharmony_ci		 * gftoffset is relative with board, not vcpu
11238c2ecf20Sopenharmony_ci		 * only set for the first time for smp system
11248c2ecf20Sopenharmony_ci		 */
11258c2ecf20Sopenharmony_ci		if (!vcpu->kvm->arch.stablecounter_gftoffset)
11268c2ecf20Sopenharmony_ci			vcpu->kvm->arch.stablecounter_gftoffset = (signed long)(v - drdtime());
11278c2ecf20Sopenharmony_ci		kvm_write_csr_gcntc((ulong)vcpu->kvm->arch.stablecounter_gftoffset);
11288c2ecf20Sopenharmony_ci		local_irq_restore(flags);
11298c2ecf20Sopenharmony_ci		break;
11308c2ecf20Sopenharmony_ci	case KVM_REG_LOONGARCH_VCPU_RESET:
11318c2ecf20Sopenharmony_ci		cache = &vcpu->arch.st.cache;
11328c2ecf20Sopenharmony_ci		kvm_reset_timer(vcpu);
11338c2ecf20Sopenharmony_ci		if (vcpu->vcpu_id == 0)
11348c2ecf20Sopenharmony_ci			kvm_setup_ls3a_extirq(vcpu->kvm);
11358c2ecf20Sopenharmony_ci		memset(&vcpu->arch.irq_pending, 0, sizeof(vcpu->arch.irq_pending));
11368c2ecf20Sopenharmony_ci		memset(&vcpu->arch.irq_clear, 0, sizeof(vcpu->arch.irq_clear));
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		if (vcpu->arch.st.guest_addr) {
11398c2ecf20Sopenharmony_ci			kvm_release_pfn(cache->pfn, cache->dirty, cache);
11408c2ecf20Sopenharmony_ci			/* disable pv timer when cpu resetting */
11418c2ecf20Sopenharmony_ci			vcpu->arch.st.guest_addr = 0;
11428c2ecf20Sopenharmony_ci		}
11438c2ecf20Sopenharmony_ci		vcpu->kvm->arch.stablecounter_gftoffset = 0;
11448c2ecf20Sopenharmony_ci		break;
11458c2ecf20Sopenharmony_ci	default:
11468c2ecf20Sopenharmony_ci		if ((reg->id & KVM_REG_LOONGARCH_MASK) != KVM_REG_LOONGARCH_CSR)
11478c2ecf20Sopenharmony_ci			return -EINVAL;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci		reg_idx = KVM_GET_IOC_CSRIDX(reg->id);
11508c2ecf20Sopenharmony_ci		if (reg_idx < CSR_ALL_SIZE)
11518c2ecf20Sopenharmony_ci			kvm_write_sw_gcsr(csr, reg_idx, v);
11528c2ecf20Sopenharmony_ci		else
11538c2ecf20Sopenharmony_ci			return -EINVAL;
11548c2ecf20Sopenharmony_ci	}
11558c2ecf20Sopenharmony_ci	return ret;
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_cistatic int _kvm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
11598c2ecf20Sopenharmony_ci{
11608c2ecf20Sopenharmony_ci	int ret;
11618c2ecf20Sopenharmony_ci	s64 v;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	ret = _kvm_get_one_reg(vcpu, reg, &v);
11648c2ecf20Sopenharmony_ci	if (ret)
11658c2ecf20Sopenharmony_ci		return ret;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	ret = -EINVAL;
11688c2ecf20Sopenharmony_ci	if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) {
11698c2ecf20Sopenharmony_ci		u64 __user *uaddr64 = (u64 __user *)(long)reg->addr;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci		ret = put_user(v, uaddr64);
11728c2ecf20Sopenharmony_ci	} else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) {
11738c2ecf20Sopenharmony_ci		u32 __user *uaddr32 = (u32 __user *)(long)reg->addr;
11748c2ecf20Sopenharmony_ci		u32 v32 = (u32)v;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci		ret = put_user(v32, uaddr32);
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	return ret;
11808c2ecf20Sopenharmony_ci}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_cistatic int _kvm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	s64 v;
11858c2ecf20Sopenharmony_ci	int ret;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	ret = -EINVAL;
11888c2ecf20Sopenharmony_ci	if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) {
11898c2ecf20Sopenharmony_ci		u64 __user *uaddr64 = (u64 __user *)(long)reg->addr;
11908c2ecf20Sopenharmony_ci		ret = get_user(v, uaddr64);
11918c2ecf20Sopenharmony_ci	} else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) {
11928c2ecf20Sopenharmony_ci		u32 __user *uaddr32 = (u32 __user *)(long)reg->addr;
11938c2ecf20Sopenharmony_ci		s32 v32;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci		ret = get_user(v32, uaddr32);
11968c2ecf20Sopenharmony_ci		v = (s64)v32;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	if (ret)
12008c2ecf20Sopenharmony_ci		return -EFAULT;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	return _kvm_set_one_reg(vcpu, reg, v);
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
12068c2ecf20Sopenharmony_ci				     struct kvm_enable_cap *cap)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	int r = 0;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	if (!kvm_vm_ioctl_check_extension(vcpu->kvm, cap->cap))
12118c2ecf20Sopenharmony_ci		return -EINVAL;
12128c2ecf20Sopenharmony_ci	if (cap->flags)
12138c2ecf20Sopenharmony_ci		return -EINVAL;
12148c2ecf20Sopenharmony_ci	if (cap->args[0])
12158c2ecf20Sopenharmony_ci		return -EINVAL;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	switch (cap->cap) {
12188c2ecf20Sopenharmony_ci	case KVM_CAP_LOONGARCH_FPU:
12198c2ecf20Sopenharmony_ci	case KVM_CAP_LOONGARCH_LSX:
12208c2ecf20Sopenharmony_ci		break;
12218c2ecf20Sopenharmony_ci	default:
12228c2ecf20Sopenharmony_ci		r = -EINVAL;
12238c2ecf20Sopenharmony_ci		break;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	return r;
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cilong kvm_arch_vcpu_async_ioctl(struct file *filp, unsigned int ioctl,
12308c2ecf20Sopenharmony_ci			       unsigned long arg)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu = filp->private_data;
12338c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	if (ioctl == KVM_INTERRUPT) {
12368c2ecf20Sopenharmony_ci		struct kvm_loongarch_interrupt irq;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci		if (copy_from_user(&irq, argp, sizeof(irq)))
12398c2ecf20Sopenharmony_ci			return -EFAULT;
12408c2ecf20Sopenharmony_ci		kvm_debug("[%d] %s: irq: %d\n", vcpu->vcpu_id, __func__,
12418c2ecf20Sopenharmony_ci			  irq.irq);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci		return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
12448c2ecf20Sopenharmony_ci	}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
12478c2ecf20Sopenharmony_ci}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ciint kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
12508c2ecf20Sopenharmony_ci			  bool line_status)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	u32 irq = irq_level->irq;
12538c2ecf20Sopenharmony_ci	unsigned int irq_type, vcpu_idx, irq_num, ret;
12548c2ecf20Sopenharmony_ci	int nrcpus = atomic_read(&kvm->online_vcpus);
12558c2ecf20Sopenharmony_ci	bool level = irq_level->level;
12568c2ecf20Sopenharmony_ci	unsigned long flags;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	irq_type = (irq >> KVM_LOONGSON_IRQ_TYPE_SHIFT) & KVM_LOONGSON_IRQ_TYPE_MASK;
12598c2ecf20Sopenharmony_ci	vcpu_idx = (irq >> KVM_LOONGSON_IRQ_VCPU_SHIFT) & KVM_LOONGSON_IRQ_VCPU_MASK;
12608c2ecf20Sopenharmony_ci	irq_num = (irq >> KVM_LOONGSON_IRQ_NUM_SHIFT) & KVM_LOONGSON_IRQ_NUM_MASK;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	switch (irq_type) {
12638c2ecf20Sopenharmony_ci	case KVM_LOONGSON_IRQ_TYPE_IOAPIC:
12648c2ecf20Sopenharmony_ci		if (!ls7a_ioapic_in_kernel(kvm))
12658c2ecf20Sopenharmony_ci			return -ENXIO;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci		if (vcpu_idx >= nrcpus)
12688c2ecf20Sopenharmony_ci			return -EINVAL;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		ls7a_ioapic_lock(ls7a_ioapic_irqchip(kvm), &flags);
12718c2ecf20Sopenharmony_ci		ret = kvm_ls7a_ioapic_set_irq(kvm, irq_num, level);
12728c2ecf20Sopenharmony_ci		ls7a_ioapic_unlock(ls7a_ioapic_irqchip(kvm), &flags);
12738c2ecf20Sopenharmony_ci		return ret;
12748c2ecf20Sopenharmony_ci	}
12758c2ecf20Sopenharmony_ci	kvm->stat.vm_ioctl_irq_line++;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	return -EINVAL;
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cistatic int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct loongarch_kvm_irqchip *chip)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	int r, dlen;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	r = 0;
12858c2ecf20Sopenharmony_ci	dlen = chip->len - sizeof(struct loongarch_kvm_irqchip);
12868c2ecf20Sopenharmony_ci	switch (chip->chip_id) {
12878c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS7A_IOAPIC:
12888c2ecf20Sopenharmony_ci		if (dlen != sizeof(struct kvm_ls7a_ioapic_state)) {
12898c2ecf20Sopenharmony_ci			kvm_err("get ls7a state err dlen:%d\n", dlen);
12908c2ecf20Sopenharmony_ci			goto dlen_err;
12918c2ecf20Sopenharmony_ci		}
12928c2ecf20Sopenharmony_ci		r = kvm_get_ls7a_ioapic(kvm, (void *)chip->data);
12938c2ecf20Sopenharmony_ci		break;
12948c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_GIPI:
12958c2ecf20Sopenharmony_ci		if (dlen != sizeof(gipiState)) {
12968c2ecf20Sopenharmony_ci			kvm_err("get gipi state err dlen:%d\n", dlen);
12978c2ecf20Sopenharmony_ci			goto dlen_err;
12988c2ecf20Sopenharmony_ci		}
12998c2ecf20Sopenharmony_ci		r = kvm_get_ls3a_ipi(kvm, (void *)chip->data);
13008c2ecf20Sopenharmony_ci		break;
13018c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_HT_IRQ:
13028c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_ROUTE:
13038c2ecf20Sopenharmony_ci		break;
13048c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_EXTIRQ:
13058c2ecf20Sopenharmony_ci		if (dlen != sizeof(struct kvm_loongarch_ls3a_extirq_state)) {
13068c2ecf20Sopenharmony_ci			kvm_err("get extioi state err dlen:%d\n", dlen);
13078c2ecf20Sopenharmony_ci			goto dlen_err;
13088c2ecf20Sopenharmony_ci		}
13098c2ecf20Sopenharmony_ci		r = kvm_get_ls3a_extirq(kvm, (void *)chip->data);
13108c2ecf20Sopenharmony_ci		break;
13118c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_IPMASK:
13128c2ecf20Sopenharmony_ci		break;
13138c2ecf20Sopenharmony_ci	default:
13148c2ecf20Sopenharmony_ci		r = -EINVAL;
13158c2ecf20Sopenharmony_ci		break;
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci	return r;
13188c2ecf20Sopenharmony_cidlen_err:
13198c2ecf20Sopenharmony_ci	r = -EINVAL;
13208c2ecf20Sopenharmony_ci	return r;
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct loongarch_kvm_irqchip *chip)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	int r, dlen;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	r = 0;
13288c2ecf20Sopenharmony_ci	dlen = chip->len - sizeof(struct loongarch_kvm_irqchip);
13298c2ecf20Sopenharmony_ci	switch (chip->chip_id) {
13308c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS7A_IOAPIC:
13318c2ecf20Sopenharmony_ci		if (dlen != sizeof(struct kvm_ls7a_ioapic_state)) {
13328c2ecf20Sopenharmony_ci			kvm_err("set ls7a state err dlen:%d\n", dlen);
13338c2ecf20Sopenharmony_ci			goto dlen_err;
13348c2ecf20Sopenharmony_ci		}
13358c2ecf20Sopenharmony_ci		r = kvm_set_ls7a_ioapic(kvm, (void *)chip->data);
13368c2ecf20Sopenharmony_ci		break;
13378c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_GIPI:
13388c2ecf20Sopenharmony_ci		if (dlen != sizeof(gipiState)) {
13398c2ecf20Sopenharmony_ci			kvm_err("set gipi state err dlen:%d\n", dlen);
13408c2ecf20Sopenharmony_ci			goto dlen_err;
13418c2ecf20Sopenharmony_ci		}
13428c2ecf20Sopenharmony_ci		r = kvm_set_ls3a_ipi(kvm, (void *)chip->data);
13438c2ecf20Sopenharmony_ci		break;
13448c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_HT_IRQ:
13458c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_ROUTE:
13468c2ecf20Sopenharmony_ci		break;
13478c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_EXTIRQ:
13488c2ecf20Sopenharmony_ci		if (dlen != sizeof(struct kvm_loongarch_ls3a_extirq_state)) {
13498c2ecf20Sopenharmony_ci			kvm_err("set extioi state err dlen:%d\n", dlen);
13508c2ecf20Sopenharmony_ci			goto dlen_err;
13518c2ecf20Sopenharmony_ci		}
13528c2ecf20Sopenharmony_ci		r = kvm_set_ls3a_extirq(kvm, (void *)chip->data);
13538c2ecf20Sopenharmony_ci		break;
13548c2ecf20Sopenharmony_ci	case KVM_IRQCHIP_LS3A_IPMASK:
13558c2ecf20Sopenharmony_ci		break;
13568c2ecf20Sopenharmony_ci	default:
13578c2ecf20Sopenharmony_ci		r = -EINVAL;
13588c2ecf20Sopenharmony_ci		break;
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci	return r;
13618c2ecf20Sopenharmony_cidlen_err:
13628c2ecf20Sopenharmony_ci	r = -EINVAL;
13638c2ecf20Sopenharmony_ci	return r;
13648c2ecf20Sopenharmony_ci}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci/*
13678c2ecf20Sopenharmony_ci * Read or write a bunch of msrs. All parameters are kernel addresses.
13688c2ecf20Sopenharmony_ci *
13698c2ecf20Sopenharmony_ci * @return number of msrs set successfully.
13708c2ecf20Sopenharmony_ci */
13718c2ecf20Sopenharmony_cistatic int _kvm_csr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
13728c2ecf20Sopenharmony_ci		struct kvm_csr_entry *entries,
13738c2ecf20Sopenharmony_ci		int (*do_csr)(struct kvm_vcpu *vcpu,
13748c2ecf20Sopenharmony_ci			unsigned index, u64 *data, int force))
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	int i;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	for (i = 0; i < msrs->ncsrs; ++i)
13798c2ecf20Sopenharmony_ci		if (do_csr(vcpu, entries[i].index, &entries[i].data, 1))
13808c2ecf20Sopenharmony_ci			break;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	return i;
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_cistatic int kvm_csr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs,
13868c2ecf20Sopenharmony_ci		int (*do_csr)(struct kvm_vcpu *vcpu,
13878c2ecf20Sopenharmony_ci			unsigned index, u64 *data, int force))
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct kvm_msrs msrs;
13908c2ecf20Sopenharmony_ci	struct kvm_csr_entry *entries;
13918c2ecf20Sopenharmony_ci	int r, n;
13928c2ecf20Sopenharmony_ci	unsigned size;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	r = -EFAULT;
13958c2ecf20Sopenharmony_ci	if (copy_from_user(&msrs, user_msrs, sizeof msrs))
13968c2ecf20Sopenharmony_ci		goto out;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	r = -E2BIG;
13998c2ecf20Sopenharmony_ci	if (msrs.ncsrs >= CSR_ALL_SIZE)
14008c2ecf20Sopenharmony_ci		goto out;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	size = sizeof(struct kvm_csr_entry) * msrs.ncsrs;
14038c2ecf20Sopenharmony_ci	entries = memdup_user(user_msrs->entries, size);
14048c2ecf20Sopenharmony_ci	if (IS_ERR(entries)) {
14058c2ecf20Sopenharmony_ci		r = PTR_ERR(entries);
14068c2ecf20Sopenharmony_ci		goto out;
14078c2ecf20Sopenharmony_ci	}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	r = n = _kvm_csr_io(vcpu, &msrs, entries, do_csr);
14108c2ecf20Sopenharmony_ci	if (r < 0)
14118c2ecf20Sopenharmony_ci		goto out_free;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	r = -EFAULT;
14148c2ecf20Sopenharmony_ci	if (copy_to_user(user_msrs->entries, entries, size))
14158c2ecf20Sopenharmony_ci		goto out_free;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	r = n;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ciout_free:
14208c2ecf20Sopenharmony_ci	kfree(entries);
14218c2ecf20Sopenharmony_ciout:
14228c2ecf20Sopenharmony_ci	return r;
14238c2ecf20Sopenharmony_ci}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_cistatic int _kvm_vcpu_set_attr(struct kvm_vcpu *vcpu,
14268c2ecf20Sopenharmony_ci				struct kvm_device_attr *attr)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	int ret = -ENXIO;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	switch (attr->group) {
14318c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
14328c2ecf20Sopenharmony_ci	case KVM_LARCH_VCPU_PVTIME_CTRL:
14338c2ecf20Sopenharmony_ci		ret = _kvm_pvtime_set_attr(vcpu, attr);
14348c2ecf20Sopenharmony_ci		break;
14358c2ecf20Sopenharmony_ci#endif
14368c2ecf20Sopenharmony_ci	default:
14378c2ecf20Sopenharmony_ci		ret = -ENXIO;
14388c2ecf20Sopenharmony_ci		break;
14398c2ecf20Sopenharmony_ci	}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	return ret;
14428c2ecf20Sopenharmony_ci}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_cistatic int _kvm_vcpu_get_attr(struct kvm_vcpu *vcpu,
14458c2ecf20Sopenharmony_ci				struct kvm_device_attr *attr)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	int ret = -ENXIO;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	switch (attr->group) {
14508c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
14518c2ecf20Sopenharmony_ci	case KVM_LARCH_VCPU_PVTIME_CTRL:
14528c2ecf20Sopenharmony_ci		ret = _kvm_pvtime_get_attr(vcpu, attr);
14538c2ecf20Sopenharmony_ci		break;
14548c2ecf20Sopenharmony_ci#endif
14558c2ecf20Sopenharmony_ci	default:
14568c2ecf20Sopenharmony_ci		ret = -ENXIO;
14578c2ecf20Sopenharmony_ci		break;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	return ret;
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic int _kvm_vcpu_has_attr(struct kvm_vcpu *vcpu,
14648c2ecf20Sopenharmony_ci				struct kvm_device_attr *attr)
14658c2ecf20Sopenharmony_ci{
14668c2ecf20Sopenharmony_ci	int ret = -ENXIO;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	switch (attr->group) {
14698c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT
14708c2ecf20Sopenharmony_ci	case KVM_LARCH_VCPU_PVTIME_CTRL:
14718c2ecf20Sopenharmony_ci		ret = _kvm_pvtime_has_attr(vcpu, attr);
14728c2ecf20Sopenharmony_ci		break;
14738c2ecf20Sopenharmony_ci#endif
14748c2ecf20Sopenharmony_ci	default:
14758c2ecf20Sopenharmony_ci		ret = -ENXIO;
14768c2ecf20Sopenharmony_ci		break;
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	return ret;
14808c2ecf20Sopenharmony_ci}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_cilong kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl,
14838c2ecf20Sopenharmony_ci			 unsigned long arg)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	struct kvm_vcpu *vcpu = filp->private_data;
14868c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
14878c2ecf20Sopenharmony_ci	struct kvm_device_attr attr;
14888c2ecf20Sopenharmony_ci	long r;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	vcpu_load(vcpu);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	switch (ioctl) {
14938c2ecf20Sopenharmony_ci	case KVM_SET_ONE_REG:
14948c2ecf20Sopenharmony_ci	case KVM_GET_ONE_REG: {
14958c2ecf20Sopenharmony_ci		struct kvm_one_reg reg;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		r = -EFAULT;
14988c2ecf20Sopenharmony_ci		if (copy_from_user(&reg, argp, sizeof(reg)))
14998c2ecf20Sopenharmony_ci			break;
15008c2ecf20Sopenharmony_ci		if (ioctl == KVM_SET_ONE_REG)
15018c2ecf20Sopenharmony_ci			r = _kvm_set_reg(vcpu, &reg);
15028c2ecf20Sopenharmony_ci		else
15038c2ecf20Sopenharmony_ci			r = _kvm_get_reg(vcpu, &reg);
15048c2ecf20Sopenharmony_ci		break;
15058c2ecf20Sopenharmony_ci	}
15068c2ecf20Sopenharmony_ci	case KVM_ENABLE_CAP: {
15078c2ecf20Sopenharmony_ci		struct kvm_enable_cap cap;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci		r = -EFAULT;
15108c2ecf20Sopenharmony_ci		if (copy_from_user(&cap, argp, sizeof(cap)))
15118c2ecf20Sopenharmony_ci			break;
15128c2ecf20Sopenharmony_ci		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
15138c2ecf20Sopenharmony_ci		break;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci	case KVM_CHECK_EXTENSION: {
15168c2ecf20Sopenharmony_ci		unsigned int ext;
15178c2ecf20Sopenharmony_ci		if (copy_from_user(&ext, argp, sizeof(ext)))
15188c2ecf20Sopenharmony_ci			return -EFAULT;
15198c2ecf20Sopenharmony_ci		switch (ext) {
15208c2ecf20Sopenharmony_ci		case KVM_CAP_LOONGARCH_FPU:
15218c2ecf20Sopenharmony_ci			r = !!cpu_has_fpu;
15228c2ecf20Sopenharmony_ci			break;
15238c2ecf20Sopenharmony_ci		case KVM_CAP_LOONGARCH_LSX:
15248c2ecf20Sopenharmony_ci			r = !!cpu_has_lsx;
15258c2ecf20Sopenharmony_ci			break;
15268c2ecf20Sopenharmony_ci		default:
15278c2ecf20Sopenharmony_ci			break;
15288c2ecf20Sopenharmony_ci		}
15298c2ecf20Sopenharmony_ci		break;
15308c2ecf20Sopenharmony_ci	}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	case KVM_LOONGARCH_GET_VCPU_STATE:
15338c2ecf20Sopenharmony_ci	{
15348c2ecf20Sopenharmony_ci		int i;
15358c2ecf20Sopenharmony_ci		struct  kvm_loongarch_vcpu_state vcpu_state;
15368c2ecf20Sopenharmony_ci		r = -EFAULT;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		vcpu_state.online_vcpus = vcpu->kvm->arch.online_vcpus;
15398c2ecf20Sopenharmony_ci		vcpu_state.is_migrate = 1;
15408c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
15418c2ecf20Sopenharmony_ci			vcpu_state.core_ext_ioisr[i] = vcpu->arch.core_ext_ioisr[i];
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		vcpu_state.irq_pending =  vcpu->arch.irq_pending;
15448c2ecf20Sopenharmony_ci		vcpu_state.irq_clear =  vcpu->arch.irq_clear;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &vcpu_state, sizeof(struct kvm_loongarch_vcpu_state)))
15478c2ecf20Sopenharmony_ci			break;
15488c2ecf20Sopenharmony_ci		r = 0;
15498c2ecf20Sopenharmony_ci		break;
15508c2ecf20Sopenharmony_ci	}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	case KVM_LOONGARCH_SET_VCPU_STATE:
15538c2ecf20Sopenharmony_ci	{
15548c2ecf20Sopenharmony_ci		int i;
15558c2ecf20Sopenharmony_ci		struct kvm_loongarch_vcpu_state vcpu_state;
15568c2ecf20Sopenharmony_ci		r = -EFAULT;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci		if (copy_from_user(&vcpu_state, argp, sizeof(struct kvm_loongarch_vcpu_state)))
15598c2ecf20Sopenharmony_ci			return -EFAULT;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci		vcpu->kvm->arch.online_vcpus = vcpu_state.online_vcpus;
15628c2ecf20Sopenharmony_ci		vcpu->kvm->arch.is_migrate = vcpu_state.is_migrate;
15638c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
15648c2ecf20Sopenharmony_ci			 vcpu->arch.core_ext_ioisr[i] = vcpu_state.core_ext_ioisr[i];
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci		vcpu->arch.irq_pending = vcpu_state.irq_pending;
15678c2ecf20Sopenharmony_ci		vcpu->arch.irq_clear = vcpu_state.irq_clear;
15688c2ecf20Sopenharmony_ci		r = 0;
15698c2ecf20Sopenharmony_ci		break;
15708c2ecf20Sopenharmony_ci	}
15718c2ecf20Sopenharmony_ci	case KVM_GET_MSRS: {
15728c2ecf20Sopenharmony_ci		r = kvm_csr_io(vcpu, argp, _kvm_getcsr);
15738c2ecf20Sopenharmony_ci		break;
15748c2ecf20Sopenharmony_ci	}
15758c2ecf20Sopenharmony_ci	case KVM_SET_MSRS: {
15768c2ecf20Sopenharmony_ci		r = kvm_csr_io(vcpu, argp, _kvm_setcsr);
15778c2ecf20Sopenharmony_ci		break;
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci	case KVM_SET_DEVICE_ATTR: {
15808c2ecf20Sopenharmony_ci		r = -EFAULT;
15818c2ecf20Sopenharmony_ci		if (copy_from_user(&attr, argp, sizeof(attr)))
15828c2ecf20Sopenharmony_ci			break;
15838c2ecf20Sopenharmony_ci		r = _kvm_vcpu_set_attr(vcpu, &attr);
15848c2ecf20Sopenharmony_ci		break;
15858c2ecf20Sopenharmony_ci	}
15868c2ecf20Sopenharmony_ci	case KVM_GET_DEVICE_ATTR: {
15878c2ecf20Sopenharmony_ci		r = -EFAULT;
15888c2ecf20Sopenharmony_ci		if (copy_from_user(&attr, argp, sizeof(attr)))
15898c2ecf20Sopenharmony_ci			break;
15908c2ecf20Sopenharmony_ci		r = _kvm_vcpu_get_attr(vcpu, &attr);
15918c2ecf20Sopenharmony_ci		break;
15928c2ecf20Sopenharmony_ci	}
15938c2ecf20Sopenharmony_ci	case KVM_HAS_DEVICE_ATTR: {
15948c2ecf20Sopenharmony_ci		r = -EFAULT;
15958c2ecf20Sopenharmony_ci		if (copy_from_user(&attr, argp, sizeof(attr)))
15968c2ecf20Sopenharmony_ci			break;
15978c2ecf20Sopenharmony_ci		r = _kvm_vcpu_has_attr(vcpu, &attr);
15988c2ecf20Sopenharmony_ci		break;
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci	default:
16018c2ecf20Sopenharmony_ci		r = -ENOIOCTLCMD;
16028c2ecf20Sopenharmony_ci	}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	vcpu_put(vcpu);
16058c2ecf20Sopenharmony_ci	return r;
16068c2ecf20Sopenharmony_ci}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_civoid kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
16098c2ecf20Sopenharmony_ci{
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_civoid kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
16148c2ecf20Sopenharmony_ci					struct kvm_memory_slot *memslot)
16158c2ecf20Sopenharmony_ci{
16168c2ecf20Sopenharmony_ci	/*
16178c2ecf20Sopenharmony_ci	 * FIXME: disable THP to improve vm migration success ratio,
16188c2ecf20Sopenharmony_ci	 * how to know migration failure to enable THP again
16198c2ecf20Sopenharmony_ci	 */
16208c2ecf20Sopenharmony_ci	memslot->arch.flags |= KVM_MEMSLOT_DISABLE_THP;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	/* Let implementation handle TLB/GVA invalidation */
16238c2ecf20Sopenharmony_ci	kvm_flush_remote_tlbs(kvm);
16248c2ecf20Sopenharmony_ci}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_cilong kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct kvm *kvm = filp->private_data;
16298c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
16308c2ecf20Sopenharmony_ci	long r;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	switch (ioctl) {
16338c2ecf20Sopenharmony_ci	case KVM_CREATE_IRQCHIP:
16348c2ecf20Sopenharmony_ci	{
16358c2ecf20Sopenharmony_ci		mutex_lock(&kvm->lock);
16368c2ecf20Sopenharmony_ci		r = -EEXIST;
16378c2ecf20Sopenharmony_ci		if (kvm->arch.v_ioapic)
16388c2ecf20Sopenharmony_ci			goto create_irqchip_unlock;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci		r = kvm_create_ls7a_ioapic(kvm);
16418c2ecf20Sopenharmony_ci		if (r < 0)
16428c2ecf20Sopenharmony_ci			goto create_irqchip_unlock;
16438c2ecf20Sopenharmony_ci		r = kvm_create_ls3a_ipi(kvm);
16448c2ecf20Sopenharmony_ci		if (r < 0) {
16458c2ecf20Sopenharmony_ci			mutex_lock(&kvm->slots_lock);
16468c2ecf20Sopenharmony_ci			kvm_destroy_ls7a_ioapic(kvm);
16478c2ecf20Sopenharmony_ci			mutex_unlock(&kvm->slots_lock);
16488c2ecf20Sopenharmony_ci			goto create_irqchip_unlock;
16498c2ecf20Sopenharmony_ci		}
16508c2ecf20Sopenharmony_ci		r = kvm_create_ls3a_ext_irq(kvm);
16518c2ecf20Sopenharmony_ci		if (r < 0) {
16528c2ecf20Sopenharmony_ci			mutex_lock(&kvm->slots_lock);
16538c2ecf20Sopenharmony_ci			kvm_destroy_ls3a_ipi(kvm);
16548c2ecf20Sopenharmony_ci			kvm_destroy_ls7a_ioapic(kvm);
16558c2ecf20Sopenharmony_ci			mutex_unlock(&kvm->slots_lock);
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci		kvm_ls7a_setup_default_irq_routing(kvm);
16588c2ecf20Sopenharmony_ci		irqchip_debug_init(kvm);
16598c2ecf20Sopenharmony_ci		/* Write kvm->irq_routing before kvm->arch.vpic.  */
16608c2ecf20Sopenharmony_ci		smp_wmb();
16618c2ecf20Sopenharmony_cicreate_irqchip_unlock:
16628c2ecf20Sopenharmony_ci		mutex_unlock(&kvm->lock);
16638c2ecf20Sopenharmony_ci		break;
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci	case KVM_GET_IRQCHIP: {
16668c2ecf20Sopenharmony_ci		struct loongarch_kvm_irqchip *kchip;
16678c2ecf20Sopenharmony_ci		struct loongarch_kvm_irqchip uchip;
16688c2ecf20Sopenharmony_ci		if (copy_from_user(&uchip, argp, sizeof(struct loongarch_kvm_irqchip)))
16698c2ecf20Sopenharmony_ci			goto out;
16708c2ecf20Sopenharmony_ci		kchip = memdup_user(argp, uchip.len);
16718c2ecf20Sopenharmony_ci		if (IS_ERR(kchip)) {
16728c2ecf20Sopenharmony_ci			r = PTR_ERR(kchip);
16738c2ecf20Sopenharmony_ci			goto out;
16748c2ecf20Sopenharmony_ci		}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci		r = -ENXIO;
16778c2ecf20Sopenharmony_ci		if (!ls7a_ioapic_in_kernel(kvm))
16788c2ecf20Sopenharmony_ci			goto get_irqchip_out;
16798c2ecf20Sopenharmony_ci		r = kvm_vm_ioctl_get_irqchip(kvm, kchip);
16808c2ecf20Sopenharmony_ci		if (r)
16818c2ecf20Sopenharmony_ci			goto get_irqchip_out;
16828c2ecf20Sopenharmony_ci		if (copy_to_user(argp, kchip, kchip->len))
16838c2ecf20Sopenharmony_ci			goto get_irqchip_out;
16848c2ecf20Sopenharmony_ci		r = 0;
16858c2ecf20Sopenharmony_ciget_irqchip_out:
16868c2ecf20Sopenharmony_ci		kfree(kchip);
16878c2ecf20Sopenharmony_ci		break;
16888c2ecf20Sopenharmony_ci	}
16898c2ecf20Sopenharmony_ci	case KVM_SET_IRQCHIP: {
16908c2ecf20Sopenharmony_ci		struct loongarch_kvm_irqchip *kchip;
16918c2ecf20Sopenharmony_ci		struct loongarch_kvm_irqchip uchip;
16928c2ecf20Sopenharmony_ci		if (copy_from_user(&uchip, argp, sizeof(struct loongarch_kvm_irqchip)))
16938c2ecf20Sopenharmony_ci			goto out;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci		kchip = memdup_user(argp, uchip.len);
16968c2ecf20Sopenharmony_ci		if (IS_ERR(kchip)) {
16978c2ecf20Sopenharmony_ci			r = PTR_ERR(kchip);
16988c2ecf20Sopenharmony_ci			goto out;
16998c2ecf20Sopenharmony_ci		}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci		r = -ENXIO;
17028c2ecf20Sopenharmony_ci		if (!ls7a_ioapic_in_kernel(kvm))
17038c2ecf20Sopenharmony_ci			goto set_irqchip_out;
17048c2ecf20Sopenharmony_ci		r = kvm_vm_ioctl_set_irqchip(kvm, kchip);
17058c2ecf20Sopenharmony_ci		if (r)
17068c2ecf20Sopenharmony_ci			goto set_irqchip_out;
17078c2ecf20Sopenharmony_ci		r = 0;
17088c2ecf20Sopenharmony_ciset_irqchip_out:
17098c2ecf20Sopenharmony_ci		kfree(kchip);
17108c2ecf20Sopenharmony_ci		break;
17118c2ecf20Sopenharmony_ci	}
17128c2ecf20Sopenharmony_ci	case KVM_LOONGARCH_GET_IOCSR:
17138c2ecf20Sopenharmony_ci	{
17148c2ecf20Sopenharmony_ci		r = _kvm_get_iocsr(kvm, argp);
17158c2ecf20Sopenharmony_ci		break;
17168c2ecf20Sopenharmony_ci	}
17178c2ecf20Sopenharmony_ci	case KVM_LOONGARCH_SET_IOCSR:
17188c2ecf20Sopenharmony_ci	{
17198c2ecf20Sopenharmony_ci		r = _kvm_set_iocsr(kvm, argp);
17208c2ecf20Sopenharmony_ci		break;
17218c2ecf20Sopenharmony_ci	}
17228c2ecf20Sopenharmony_ci	case KVM_LOONGARCH_SET_CPUCFG:
17238c2ecf20Sopenharmony_ci	{
17248c2ecf20Sopenharmony_ci		r = 0;
17258c2ecf20Sopenharmony_ci		if (copy_from_user(&kvm->arch.cpucfgs, argp, sizeof(struct kvm_cpucfg)))
17268c2ecf20Sopenharmony_ci			r = -EFAULT;
17278c2ecf20Sopenharmony_ci		break;
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci	case KVM_LOONGARCH_GET_CPUCFG:
17308c2ecf20Sopenharmony_ci	{
17318c2ecf20Sopenharmony_ci		r = 0;
17328c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &kvm->arch.cpucfgs, sizeof(struct kvm_cpucfg)))
17338c2ecf20Sopenharmony_ci		   r = -EFAULT;
17348c2ecf20Sopenharmony_ci		break;
17358c2ecf20Sopenharmony_ci	}
17368c2ecf20Sopenharmony_ci	default:
17378c2ecf20Sopenharmony_ci		r = -ENOIOCTLCMD;
17388c2ecf20Sopenharmony_ci	}
17398c2ecf20Sopenharmony_ciout:
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	return r;
17428c2ecf20Sopenharmony_ci}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ciint kvm_arch_init(void *opaque)
17458c2ecf20Sopenharmony_ci{
17468c2ecf20Sopenharmony_ci	struct kvm_context *context;
17478c2ecf20Sopenharmony_ci	unsigned long vpid_mask;
17488c2ecf20Sopenharmony_ci	int cpu;
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	vmcs = alloc_percpu(struct kvm_context);
17518c2ecf20Sopenharmony_ci	if (!vmcs) {
17528c2ecf20Sopenharmony_ci		printk(KERN_ERR "kvm: failed to allocate percpu kvm_context\n");
17538c2ecf20Sopenharmony_ci		return -ENOMEM;
17548c2ecf20Sopenharmony_ci	}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	vpid_mask = kvm_read_csr_gstat();
17578c2ecf20Sopenharmony_ci	vpid_mask = (vpid_mask & KVM_GSTAT_GIDBIT) >> KVM_GSTAT_GIDBIT_SHIFT;
17588c2ecf20Sopenharmony_ci	if (vpid_mask)
17598c2ecf20Sopenharmony_ci		vpid_mask = GENMASK(vpid_mask - 1, 0);
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
17628c2ecf20Sopenharmony_ci		context = per_cpu_ptr(vmcs, cpu);
17638c2ecf20Sopenharmony_ci		context->gid_mask = vpid_mask;
17648c2ecf20Sopenharmony_ci		context->gid_ver_mask = ~context->gid_mask;
17658c2ecf20Sopenharmony_ci		context->gid_fisrt_ver = context->gid_mask + 1;
17668c2ecf20Sopenharmony_ci		context->vpid_cache = context->gid_mask + 1;
17678c2ecf20Sopenharmony_ci		context->last_vcpu = NULL;
17688c2ecf20Sopenharmony_ci	}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	_kvm_init_fault();
17718c2ecf20Sopenharmony_ci	return 0;
17728c2ecf20Sopenharmony_ci}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_civoid kvm_arch_exit(void)
17758c2ecf20Sopenharmony_ci{
17768c2ecf20Sopenharmony_ci	free_percpu(vmcs);
17778c2ecf20Sopenharmony_ci}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
17808c2ecf20Sopenharmony_ci				  struct kvm_sregs *sregs)
17818c2ecf20Sopenharmony_ci{
17828c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
17838c2ecf20Sopenharmony_ci}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
17868c2ecf20Sopenharmony_ci				  struct kvm_sregs *sregs)
17878c2ecf20Sopenharmony_ci{
17888c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
17898c2ecf20Sopenharmony_ci}
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_civoid kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
17928c2ecf20Sopenharmony_ci{
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
17968c2ecf20Sopenharmony_ci{
17978c2ecf20Sopenharmony_ci	int i = 0;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	/* no need vcpu_load and vcpu_put */
18008c2ecf20Sopenharmony_ci	fpu->fcsr = vcpu->arch.fpu.fcsr;
18018c2ecf20Sopenharmony_ci	fpu->fcc = vcpu->arch.fpu.fcc;
18028c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_FPU_REGS; i++)
18038c2ecf20Sopenharmony_ci		memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], FPU_REG_WIDTH / 64);
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	return 0;
18068c2ecf20Sopenharmony_ci}
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
18098c2ecf20Sopenharmony_ci{
18108c2ecf20Sopenharmony_ci	int i = 0;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	/* no need vcpu_load and vcpu_put */
18138c2ecf20Sopenharmony_ci	vcpu->arch.fpu.fcsr = fpu->fcsr;
18148c2ecf20Sopenharmony_ci	vcpu->arch.fpu.fcc = fpu->fcc;
18158c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_FPU_REGS; i++)
18168c2ecf20Sopenharmony_ci		memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], FPU_REG_WIDTH / 64);
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	return 0;
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_civm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
18228c2ecf20Sopenharmony_ci{
18238c2ecf20Sopenharmony_ci	return VM_FAULT_SIGBUS;
18248c2ecf20Sopenharmony_ci}
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ciint kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
18278c2ecf20Sopenharmony_ci{
18288c2ecf20Sopenharmony_ci	int r;
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	switch (ext) {
18318c2ecf20Sopenharmony_ci	case KVM_CAP_ONE_REG:
18328c2ecf20Sopenharmony_ci	case KVM_CAP_ENABLE_CAP:
18338c2ecf20Sopenharmony_ci	case KVM_CAP_READONLY_MEM:
18348c2ecf20Sopenharmony_ci	case KVM_CAP_SYNC_MMU:
18358c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_LS_KVM_MSI
18368c2ecf20Sopenharmony_ci	case KVM_CAP_SIGNAL_MSI:
18378c2ecf20Sopenharmony_ci#endif
18388c2ecf20Sopenharmony_ci	case KVM_CAP_IMMEDIATE_EXIT:
18398c2ecf20Sopenharmony_ci		r = 1;
18408c2ecf20Sopenharmony_ci		break;
18418c2ecf20Sopenharmony_ci	case KVM_CAP_NR_VCPUS:
18428c2ecf20Sopenharmony_ci		r = num_online_cpus();
18438c2ecf20Sopenharmony_ci		break;
18448c2ecf20Sopenharmony_ci	case KVM_CAP_MAX_VCPUS:
18458c2ecf20Sopenharmony_ci		r = KVM_MAX_VCPUS;
18468c2ecf20Sopenharmony_ci		break;
18478c2ecf20Sopenharmony_ci	case KVM_CAP_MAX_VCPU_ID:
18488c2ecf20Sopenharmony_ci		r = KVM_MAX_VCPU_ID;
18498c2ecf20Sopenharmony_ci		break;
18508c2ecf20Sopenharmony_ci	case KVM_CAP_LOONGARCH_FPU:
18518c2ecf20Sopenharmony_ci		/* We don't handle systems with inconsistent cpu_has_fpu */
18528c2ecf20Sopenharmony_ci		r = !!cpu_has_fpu;
18538c2ecf20Sopenharmony_ci		break;
18548c2ecf20Sopenharmony_ci	case KVM_CAP_LOONGARCH_LSX:
18558c2ecf20Sopenharmony_ci		/*
18568c2ecf20Sopenharmony_ci		 * We don't support LSX vector partitioning yet:
18578c2ecf20Sopenharmony_ci		 * 1) It would require explicit support which can't be tested
18588c2ecf20Sopenharmony_ci		 *    yet due to lack of support in current hardware.
18598c2ecf20Sopenharmony_ci		 * 2) It extends the state that would need to be saved/restored
18608c2ecf20Sopenharmony_ci		 *    by e.g. QEMU for migration.
18618c2ecf20Sopenharmony_ci		 *
18628c2ecf20Sopenharmony_ci		 * When vector partitioning hardware becomes available, support
18638c2ecf20Sopenharmony_ci		 * could be added by requiring a flag when enabling
18648c2ecf20Sopenharmony_ci		 * KVM_CAP_LOONGARCH_LSX capability to indicate that userland knows
18658c2ecf20Sopenharmony_ci		 * to save/restore the appropriate extra state.
18668c2ecf20Sopenharmony_ci		 */
18678c2ecf20Sopenharmony_ci		r = cpu_has_lsx;
18688c2ecf20Sopenharmony_ci		break;
18698c2ecf20Sopenharmony_ci	case KVM_CAP_IRQCHIP:
18708c2ecf20Sopenharmony_ci	case KVM_CAP_IOEVENTFD:
18718c2ecf20Sopenharmony_ci		/* we wouldn't be here unless cpu_has_lvz */
18728c2ecf20Sopenharmony_ci		r = 1;
18738c2ecf20Sopenharmony_ci		break;
18748c2ecf20Sopenharmony_ci	case KVM_CAP_LOONGARCH_VZ:
18758c2ecf20Sopenharmony_ci		/* get user defined kvm version */
18768c2ecf20Sopenharmony_ci		r = KVM_LOONGARCH_VERSION;
18778c2ecf20Sopenharmony_ci		break;
18788c2ecf20Sopenharmony_ci	default:
18798c2ecf20Sopenharmony_ci		r = 0;
18808c2ecf20Sopenharmony_ci		break;
18818c2ecf20Sopenharmony_ci	}
18828c2ecf20Sopenharmony_ci	return r;
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ciint kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
18868c2ecf20Sopenharmony_ci{
18878c2ecf20Sopenharmony_ci	return _kvm_pending_timer(vcpu) ||
18888c2ecf20Sopenharmony_ci		kvm_read_hw_gcsr(KVM_CSR_ESTAT) & (1 << INT_TI);
18898c2ecf20Sopenharmony_ci}
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ciint kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)
18928c2ecf20Sopenharmony_ci{
18938c2ecf20Sopenharmony_ci	int i;
18948c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	if (!vcpu)
18978c2ecf20Sopenharmony_ci		return -1;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	kvm_debug("VCPU Register Dump:\n");
19008c2ecf20Sopenharmony_ci	kvm_debug("\tpc = 0x%08lx\n", vcpu->arch.pc);
19018c2ecf20Sopenharmony_ci	kvm_debug("\texceptions: %08lx\n", vcpu->arch.irq_pending);
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	for (i = 0; i < 32; i += 4) {
19048c2ecf20Sopenharmony_ci		kvm_debug("\tgpr%02d: %08lx %08lx %08lx %08lx\n", i,
19058c2ecf20Sopenharmony_ci		       vcpu->arch.gprs[i],
19068c2ecf20Sopenharmony_ci		       vcpu->arch.gprs[i + 1],
19078c2ecf20Sopenharmony_ci		       vcpu->arch.gprs[i + 2], vcpu->arch.gprs[i + 3]);
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	csr = vcpu->arch.csr;
19118c2ecf20Sopenharmony_ci	kvm_debug("\tCRMOD: 0x%08lx, exst: 0x%08lx\n",
19128c2ecf20Sopenharmony_ci		  kvm_read_hw_gcsr(KVM_CSR_CRMD),
19138c2ecf20Sopenharmony_ci		  kvm_read_hw_gcsr(KVM_CSR_ESTAT));
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	kvm_debug("\tERA: 0x%08lx\n", kvm_read_hw_gcsr(KVM_CSR_ERA));
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	return 0;
19188c2ecf20Sopenharmony_ci}
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
19218c2ecf20Sopenharmony_ci{
19228c2ecf20Sopenharmony_ci	int i;
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	vcpu_load(vcpu);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
19278c2ecf20Sopenharmony_ci		vcpu->arch.gprs[i] = regs->gpr[i];
19288c2ecf20Sopenharmony_ci	vcpu->arch.gprs[0] = 0; /* zero is special, and cannot be set. */
19298c2ecf20Sopenharmony_ci	vcpu->arch.pc = regs->pc;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	vcpu_put(vcpu);
19328c2ecf20Sopenharmony_ci	return 0;
19338c2ecf20Sopenharmony_ci}
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
19368c2ecf20Sopenharmony_ci{
19378c2ecf20Sopenharmony_ci	int i;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	vcpu_load(vcpu);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
19428c2ecf20Sopenharmony_ci		regs->gpr[i] = vcpu->arch.gprs[i];
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	regs->pc = vcpu->arch.pc;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	vcpu_put(vcpu);
19478c2ecf20Sopenharmony_ci	return 0;
19488c2ecf20Sopenharmony_ci}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
19518c2ecf20Sopenharmony_ci				  struct kvm_translation *tr)
19528c2ecf20Sopenharmony_ci{
19538c2ecf20Sopenharmony_ci	return 0;
19548c2ecf20Sopenharmony_ci}
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_LBT
19578c2ecf20Sopenharmony_ci/* Enable FPU for guest and restore context */
19588c2ecf20Sopenharmony_civoid kvm_own_lbt(struct kvm_vcpu *vcpu)
19598c2ecf20Sopenharmony_ci{
19608c2ecf20Sopenharmony_ci	preempt_disable();
19618c2ecf20Sopenharmony_ci	if (!(vcpu->arch.aux_inuse & KVM_LARCH_LBT)) {
19628c2ecf20Sopenharmony_ci		kvm_set_csr_euen(KVM_EUEN_LBTEN);
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci		/* If guest lbt state not active, restore it now */
19658c2ecf20Sopenharmony_ci		kvm_restore_lbt(vcpu);
19668c2ecf20Sopenharmony_ci		vcpu->arch.aux_inuse |= KVM_LARCH_LBT;
19678c2ecf20Sopenharmony_ci	}
19688c2ecf20Sopenharmony_ci	preempt_enable();
19698c2ecf20Sopenharmony_ci}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_cistatic void kvm_enable_lbt_fpu(struct kvm_vcpu *vcpu, unsigned long fcsr)
19728c2ecf20Sopenharmony_ci{
19738c2ecf20Sopenharmony_ci	/*
19748c2ecf20Sopenharmony_ci	 * if TM is enabled, top register save/restore will
19758c2ecf20Sopenharmony_ci	 * cause lbt exception, here enable lbt in advanced
19768c2ecf20Sopenharmony_ci	 */
19778c2ecf20Sopenharmony_ci	if (fcsr & FPU_CSR_TM)
19788c2ecf20Sopenharmony_ci		kvm_own_lbt(vcpu);
19798c2ecf20Sopenharmony_ci}
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_cistatic void kvm_lose_lbt(struct kvm_vcpu *vcpu)
19828c2ecf20Sopenharmony_ci{
19838c2ecf20Sopenharmony_ci	preempt_disable();
19848c2ecf20Sopenharmony_ci	if (vcpu->arch.aux_inuse & KVM_LARCH_LBT) {
19858c2ecf20Sopenharmony_ci		kvm_save_lbt(vcpu);
19868c2ecf20Sopenharmony_ci		kvm_clear_csr_euen(KVM_EUEN_LBTEN);
19878c2ecf20Sopenharmony_ci		vcpu->arch.aux_inuse &= ~KVM_LARCH_LBT;
19888c2ecf20Sopenharmony_ci	}
19898c2ecf20Sopenharmony_ci	preempt_enable();
19908c2ecf20Sopenharmony_ci}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci#else
19938c2ecf20Sopenharmony_civoid kvm_own_lbt(struct kvm_vcpu *vcpu) { }
19948c2ecf20Sopenharmony_cistatic void kvm_enable_lbt_fpu(struct kvm_vcpu *vcpu, unsigned long fcsr) { }
19958c2ecf20Sopenharmony_cistatic void kvm_lose_lbt(struct kvm_vcpu *vcpu) { }
19968c2ecf20Sopenharmony_ci#endif
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci/* Enable FPU for guest and restore context */
19998c2ecf20Sopenharmony_civoid kvm_own_fpu(struct kvm_vcpu *vcpu)
20008c2ecf20Sopenharmony_ci{
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	preempt_disable();
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	/*
20058c2ecf20Sopenharmony_ci	 * Enable FPU for guest
20068c2ecf20Sopenharmony_ci	 * We set FR and FRE according to guest context
20078c2ecf20Sopenharmony_ci	 */
20088c2ecf20Sopenharmony_ci	kvm_enable_lbt_fpu(vcpu, vcpu->arch.fpu.fcsr);
20098c2ecf20Sopenharmony_ci	kvm_set_csr_euen(KVM_EUEN_FPEN);
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	/* If guest FPU state not active, restore it now */
20128c2ecf20Sopenharmony_ci	kvm_restore_fpu(vcpu);
20138c2ecf20Sopenharmony_ci	vcpu->arch.aux_inuse |= KVM_LARCH_FPU;
20148c2ecf20Sopenharmony_ci	trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_FPU);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	preempt_enable();
20178c2ecf20Sopenharmony_ci}
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_LSX
20208c2ecf20Sopenharmony_ci/* Enable LSX for guest and restore context */
20218c2ecf20Sopenharmony_civoid kvm_own_lsx(struct kvm_vcpu *vcpu)
20228c2ecf20Sopenharmony_ci{
20238c2ecf20Sopenharmony_ci	preempt_disable();
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	/* Enable LSX for guest */
20268c2ecf20Sopenharmony_ci	kvm_enable_lbt_fpu(vcpu, vcpu->arch.fpu.fcsr);
20278c2ecf20Sopenharmony_ci	kvm_set_csr_euen(KVM_EUEN_LSXEN | KVM_EUEN_FPEN);
20288c2ecf20Sopenharmony_ci	switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
20298c2ecf20Sopenharmony_ci	case KVM_LARCH_FPU:
20308c2ecf20Sopenharmony_ci		/*
20318c2ecf20Sopenharmony_ci		 * Guest FPU state already loaded,
20328c2ecf20Sopenharmony_ci		 * only restore upper LSX state
20338c2ecf20Sopenharmony_ci		 */
20348c2ecf20Sopenharmony_ci		kvm_restore_lsx_upper(vcpu);
20358c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE,
20368c2ecf20Sopenharmony_ci					KVM_TRACE_AUX_LSX);
20378c2ecf20Sopenharmony_ci		break;
20388c2ecf20Sopenharmony_ci	default:
20398c2ecf20Sopenharmony_ci		/* Neither FP or LSX already active,
20408c2ecf20Sopenharmony_ci		 * restore full LSX state
20418c2ecf20Sopenharmony_ci		 */
20428c2ecf20Sopenharmony_ci		kvm_restore_lsx(vcpu);
20438c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE,
20448c2ecf20Sopenharmony_ci				KVM_TRACE_AUX_FPU_LSX);
20458c2ecf20Sopenharmony_ci	break;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU;
20498c2ecf20Sopenharmony_ci	preempt_enable();
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ci#endif
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_LASX
20548c2ecf20Sopenharmony_ci/* Enable LASX for guest and restore context */
20558c2ecf20Sopenharmony_civoid kvm_own_lasx(struct kvm_vcpu *vcpu)
20568c2ecf20Sopenharmony_ci{
20578c2ecf20Sopenharmony_ci	preempt_disable();
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	kvm_enable_lbt_fpu(vcpu, vcpu->arch.fpu.fcsr);
20608c2ecf20Sopenharmony_ci	kvm_set_csr_euen(KVM_EUEN_FPEN | KVM_EUEN_LSXEN | KVM_EUEN_LASXEN);
20618c2ecf20Sopenharmony_ci	switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) {
20628c2ecf20Sopenharmony_ci	case KVM_LARCH_LSX | KVM_LARCH_FPU:
20638c2ecf20Sopenharmony_ci	case KVM_LARCH_LSX:
20648c2ecf20Sopenharmony_ci		/*
20658c2ecf20Sopenharmony_ci		 * Guest LSX state already loaded, only restore upper LASX state
20668c2ecf20Sopenharmony_ci		 */
20678c2ecf20Sopenharmony_ci		kvm_restore_lasx_upper(vcpu);
20688c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX);
20698c2ecf20Sopenharmony_ci		break;
20708c2ecf20Sopenharmony_ci	case KVM_LARCH_FPU:
20718c2ecf20Sopenharmony_ci		/*
20728c2ecf20Sopenharmony_ci		 * Guest FP state already loaded, only restore 64~256 LASX state
20738c2ecf20Sopenharmony_ci		 */
20748c2ecf20Sopenharmony_ci		kvm_restore_lsx_upper(vcpu);
20758c2ecf20Sopenharmony_ci		kvm_restore_lasx_upper(vcpu);
20768c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX);
20778c2ecf20Sopenharmony_ci		break;
20788c2ecf20Sopenharmony_ci	default:
20798c2ecf20Sopenharmony_ci		/* Neither FP or LSX already active, restore full LASX state */
20808c2ecf20Sopenharmony_ci		kvm_restore_lasx(vcpu);
20818c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE,
20828c2ecf20Sopenharmony_ci			      KVM_TRACE_AUX_FPU_LSX_LASX);
20838c2ecf20Sopenharmony_ci		break;
20848c2ecf20Sopenharmony_ci	}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU;
20878c2ecf20Sopenharmony_ci	preempt_enable();
20888c2ecf20Sopenharmony_ci}
20898c2ecf20Sopenharmony_ci#endif
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci/* Save and disable FPU & LSX & LASX */
20928c2ecf20Sopenharmony_civoid kvm_lose_fpu(struct kvm_vcpu *vcpu)
20938c2ecf20Sopenharmony_ci{
20948c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_LBT
20958c2ecf20Sopenharmony_ci	unsigned long fcsr;
20968c2ecf20Sopenharmony_ci#endif
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	preempt_disable();
20998c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_LBT
21008c2ecf20Sopenharmony_ci	if (vcpu->arch.aux_inuse & KVM_LARCH_FP_ALL) {
21018c2ecf20Sopenharmony_ci		if (!(vcpu->arch.aux_inuse & KVM_LARCH_LBT)) {
21028c2ecf20Sopenharmony_ci			fcsr = read_fcsr(LOONGARCH_FCSR0);
21038c2ecf20Sopenharmony_ci			kvm_enable_lbt_fpu(vcpu, fcsr);
21048c2ecf20Sopenharmony_ci		}
21058c2ecf20Sopenharmony_ci	}
21068c2ecf20Sopenharmony_ci#endif
21078c2ecf20Sopenharmony_ci	if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) {
21088c2ecf20Sopenharmony_ci		kvm_save_lasx(vcpu);
21098c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU_LSX_LASX);
21108c2ecf20Sopenharmony_ci		/* Disable LASX & MAS & FPU */
21118c2ecf20Sopenharmony_ci		kvm_clear_csr_euen(KVM_EUEN_FPEN | KVM_EUEN_LSXEN | KVM_EUEN_LASXEN);
21128c2ecf20Sopenharmony_ci	} else if (vcpu->arch.aux_inuse & KVM_LARCH_LSX) {
21138c2ecf20Sopenharmony_ci		kvm_save_lsx(vcpu);
21148c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU_LSX);
21158c2ecf20Sopenharmony_ci		/* Disable LSX & FPU */
21168c2ecf20Sopenharmony_ci		kvm_clear_csr_euen(KVM_EUEN_FPEN | KVM_EUEN_LSXEN);
21178c2ecf20Sopenharmony_ci	} else if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
21188c2ecf20Sopenharmony_ci		kvm_save_fpu(vcpu);
21198c2ecf20Sopenharmony_ci		trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
21208c2ecf20Sopenharmony_ci		/* Disable FPU */
21218c2ecf20Sopenharmony_ci		kvm_clear_csr_euen(KVM_EUEN_FPEN);
21228c2ecf20Sopenharmony_ci	}
21238c2ecf20Sopenharmony_ci	vcpu->arch.aux_inuse &= ~KVM_LARCH_FP_ALL;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	kvm_lose_lbt(vcpu);
21268c2ecf20Sopenharmony_ci	preempt_enable();
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_civoid kvm_lose_hw_perf(struct kvm_vcpu *vcpu)
21308c2ecf20Sopenharmony_ci{
21318c2ecf20Sopenharmony_ci	if (vcpu->arch.aux_inuse & KVM_LARCH_PERF) {
21328c2ecf20Sopenharmony_ci		struct loongarch_csrs *csr = vcpu->arch.csr;
21338c2ecf20Sopenharmony_ci		/* save guest pmu csr */
21348c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCTRL0);
21358c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCNTR0);
21368c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCTRL1);
21378c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCNTR1);
21388c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCTRL2);
21398c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCNTR2);
21408c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCTRL3);
21418c2ecf20Sopenharmony_ci		kvm_save_hw_gcsr(csr, KVM_CSR_PERFCNTR3);
21428c2ecf20Sopenharmony_ci		if (((kvm_read_sw_gcsr(csr, KVM_CSR_PERFCTRL0) |
21438c2ecf20Sopenharmony_ci			kvm_read_sw_gcsr(csr, KVM_CSR_PERFCTRL1) |
21448c2ecf20Sopenharmony_ci			kvm_read_sw_gcsr(csr, KVM_CSR_PERFCTRL2) |
21458c2ecf20Sopenharmony_ci			kvm_read_sw_gcsr(csr, KVM_CSR_PERFCTRL3))
21468c2ecf20Sopenharmony_ci			& KVM_PMU_PLV_ENABLE) == 0)
21478c2ecf20Sopenharmony_ci			vcpu->arch.aux_inuse &= ~KVM_LARCH_PERF;
21488c2ecf20Sopenharmony_ci		/* config host pmu csr */
21498c2ecf20Sopenharmony_ci		kvm_write_csr_gcfg(kvm_read_csr_gcfg() & ~KVM_GCFG_GPERF);
21508c2ecf20Sopenharmony_ci		/* TODO: pmu csr used by host and guest at the same time */
21518c2ecf20Sopenharmony_ci		kvm_write_csr_perfctrl0(0);
21528c2ecf20Sopenharmony_ci		kvm_write_csr_perfcntr0(0);
21538c2ecf20Sopenharmony_ci		kvm_write_csr_perfctrl1(0);
21548c2ecf20Sopenharmony_ci		kvm_write_csr_perfcntr1(0);
21558c2ecf20Sopenharmony_ci		kvm_write_csr_perfctrl2(0);
21568c2ecf20Sopenharmony_ci		kvm_write_csr_perfcntr2(0);
21578c2ecf20Sopenharmony_ci		kvm_write_csr_perfctrl3(0);
21588c2ecf20Sopenharmony_ci		kvm_write_csr_perfcntr3(0);
21598c2ecf20Sopenharmony_ci	}
21608c2ecf20Sopenharmony_ci}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_civoid kvm_restore_hw_perf(struct kvm_vcpu *vcpu)
21638c2ecf20Sopenharmony_ci{
21648c2ecf20Sopenharmony_ci	if (vcpu->arch.aux_inuse & KVM_LARCH_PERF) {
21658c2ecf20Sopenharmony_ci		struct loongarch_csrs *csr = vcpu->arch.csr;
21668c2ecf20Sopenharmony_ci		/* enable guest pmu */
21678c2ecf20Sopenharmony_ci		kvm_write_csr_gcfg(kvm_read_csr_gcfg() | KVM_GCFG_GPERF);
21688c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCTRL0);
21698c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCNTR0);
21708c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCTRL1);
21718c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCNTR1);
21728c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCTRL2);
21738c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCNTR2);
21748c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCTRL3);
21758c2ecf20Sopenharmony_ci		kvm_restore_hw_gcsr(csr, KVM_CSR_PERFCNTR3);
21768c2ecf20Sopenharmony_ci	}
21778c2ecf20Sopenharmony_ci}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_cistatic int __init kvm_loongarch_init(void)
21808c2ecf20Sopenharmony_ci{
21818c2ecf20Sopenharmony_ci	int ret;
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	if (!cpu_has_lvz)
21848c2ecf20Sopenharmony_ci		return  0;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	if (ret)
21898c2ecf20Sopenharmony_ci		return ret;
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	return 0;
21928c2ecf20Sopenharmony_ci}
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_cistatic void __exit kvm_loongarch_exit(void)
21958c2ecf20Sopenharmony_ci{
21968c2ecf20Sopenharmony_ci	kvm_exit();
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_cimodule_init(kvm_loongarch_init);
22008c2ecf20Sopenharmony_cimodule_exit(kvm_loongarch_exit);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_cistatic const struct cpu_feature loongarch_kvm_feature[] = {
22038c2ecf20Sopenharmony_ci	{ .feature = cpu_feature(LOONGARCH_LVZ) },
22048c2ecf20Sopenharmony_ci	{},
22058c2ecf20Sopenharmony_ci};
22068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(cpu, loongarch_kvm_feature);
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(kvm_exit);
2209