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(®, argp, sizeof(reg))) 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci if (ioctl == KVM_SET_ONE_REG) 15018c2ecf20Sopenharmony_ci r = _kvm_set_reg(vcpu, ®); 15028c2ecf20Sopenharmony_ci else 15038c2ecf20Sopenharmony_ci r = _kvm_get_reg(vcpu, ®); 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