1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2023 Loongson Technology Corporation Limited 4 */ 5 6 #include <linux/kvm_host.h> 7 #include <asm/kvm_mmu.h> 8 #include <asm/kvm_vcpu.h> 9 10 const struct _kvm_stats_desc kvm_vm_stats_desc[] = { 11 KVM_GENERIC_VM_STATS(), 12 STATS_DESC_ICOUNTER(VM, pages), 13 STATS_DESC_ICOUNTER(VM, hugepages), 14 }; 15 16 const struct kvm_stats_header kvm_vm_stats_header = { 17 .name_size = KVM_STATS_NAME_SIZE, 18 .num_desc = ARRAY_SIZE(kvm_vm_stats_desc), 19 .id_offset = sizeof(struct kvm_stats_header), 20 .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, 21 .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + 22 sizeof(kvm_vm_stats_desc), 23 }; 24 25 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) 26 { 27 int i; 28 29 /* Allocate page table to map GPA -> RPA */ 30 kvm->arch.pgd = kvm_pgd_alloc(); 31 if (!kvm->arch.pgd) 32 return -ENOMEM; 33 34 kvm->arch.phyid_map = kvzalloc(sizeof(struct kvm_phyid_map), GFP_KERNEL_ACCOUNT); 35 if (!kvm->arch.phyid_map) { 36 free_page((unsigned long)kvm->arch.pgd); 37 kvm->arch.pgd = NULL; 38 return -ENOMEM; 39 } 40 spin_lock_init(&kvm->arch.phyid_map_lock); 41 42 kvm_init_vmcs(kvm); 43 44 /* Enable all PV features by default */ 45 kvm->arch.pv_features = BIT(KVM_FEATURE_IPI); 46 if (kvm_pvtime_supported()) 47 kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME); 48 49 kvm->arch.gpa_size = BIT(cpu_vabits - 1); 50 kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1; 51 kvm->arch.invalid_ptes[0] = 0; 52 kvm->arch.invalid_ptes[1] = (unsigned long)invalid_pte_table; 53 #if CONFIG_PGTABLE_LEVELS > 2 54 kvm->arch.invalid_ptes[2] = (unsigned long)invalid_pmd_table; 55 #endif 56 #if CONFIG_PGTABLE_LEVELS > 3 57 kvm->arch.invalid_ptes[3] = (unsigned long)invalid_pud_table; 58 #endif 59 for (i = 0; i <= kvm->arch.root_level; i++) 60 kvm->arch.pte_shifts[i] = PAGE_SHIFT + i * (PAGE_SHIFT - 3); 61 62 return 0; 63 } 64 65 void kvm_arch_destroy_vm(struct kvm *kvm) 66 { 67 kvm_destroy_vcpus(kvm); 68 free_page((unsigned long)kvm->arch.pgd); 69 kvm->arch.pgd = NULL; 70 kvfree(kvm->arch.phyid_map); 71 kvm->arch.phyid_map = NULL; 72 } 73 74 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) 75 { 76 int r; 77 78 switch (ext) { 79 case KVM_CAP_ONE_REG: 80 case KVM_CAP_ENABLE_CAP: 81 case KVM_CAP_READONLY_MEM: 82 case KVM_CAP_SYNC_MMU: 83 case KVM_CAP_IMMEDIATE_EXIT: 84 case KVM_CAP_IOEVENTFD: 85 case KVM_CAP_MP_STATE: 86 case KVM_CAP_SET_GUEST_DEBUG: 87 r = 1; 88 break; 89 case KVM_CAP_NR_VCPUS: 90 r = num_online_cpus(); 91 break; 92 case KVM_CAP_MAX_VCPUS: 93 r = KVM_MAX_VCPUS; 94 break; 95 case KVM_CAP_MAX_VCPU_ID: 96 r = KVM_MAX_VCPU_IDS; 97 break; 98 case KVM_CAP_NR_MEMSLOTS: 99 r = KVM_USER_MEM_SLOTS; 100 break; 101 default: 102 r = 0; 103 break; 104 } 105 106 return r; 107 } 108 109 static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) 110 { 111 switch (attr->attr) { 112 case KVM_LOONGARCH_VM_FEAT_LSX: 113 if (cpu_has_lsx) 114 return 0; 115 return -ENXIO; 116 case KVM_LOONGARCH_VM_FEAT_LASX: 117 if (cpu_has_lasx) 118 return 0; 119 return -ENXIO; 120 case KVM_LOONGARCH_VM_FEAT_X86BT: 121 if (cpu_has_lbt_x86) 122 return 0; 123 return -ENXIO; 124 case KVM_LOONGARCH_VM_FEAT_ARMBT: 125 if (cpu_has_lbt_arm) 126 return 0; 127 return -ENXIO; 128 case KVM_LOONGARCH_VM_FEAT_MIPSBT: 129 if (cpu_has_lbt_mips) 130 return 0; 131 return -ENXIO; 132 case KVM_LOONGARCH_VM_FEAT_PMU: 133 if (cpu_has_pmp) 134 return 0; 135 return -ENXIO; 136 case KVM_LOONGARCH_VM_FEAT_PV_IPI: 137 return 0; 138 case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME: 139 if (kvm_pvtime_supported()) 140 return 0; 141 return -ENXIO; 142 default: 143 return -ENXIO; 144 } 145 } 146 147 static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) 148 { 149 switch (attr->group) { 150 case KVM_LOONGARCH_VM_FEAT_CTRL: 151 return kvm_vm_feature_has_attr(kvm, attr); 152 default: 153 return -ENXIO; 154 } 155 } 156 157 int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) 158 { 159 void __user *argp = (void __user *)arg; 160 struct kvm *kvm = filp->private_data; 161 struct kvm_device_attr attr; 162 163 switch (ioctl) { 164 case KVM_HAS_DEVICE_ATTR: 165 if (copy_from_user(&attr, argp, sizeof(attr))) 166 return -EFAULT; 167 168 return kvm_vm_has_attr(kvm, &attr); 169 default: 170 return -ENOIOCTLCMD; 171 } 172 } 173