1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2023 Loongson Technology Corporation Limited 4 */ 5 6 #include <linux/err.h> 7 #include <linux/module.h> 8 #include <linux/mod_devicetable.h> 9 #include <linux/kvm_host.h> 10 #include <asm/cacheflush.h> 11 #include <asm/cpufeature.h> 12 #include <asm/kvm_csr.h> 13 #include <asm/kvm_eiointc.h> 14 #include <asm/kvm_pch_pic.h> 15 #include "trace.h" 16 17 unsigned long vpid_mask; 18 struct kvm_world_switch *kvm_loongarch_ops; 19 static int gcsr_flag[CSR_MAX_NUMS]; 20 static struct kvm_context __percpu *vmcs; 21 22 int get_gcsr_flag(int csr) 23 { 24 if (csr < CSR_MAX_NUMS) 25 return gcsr_flag[csr]; 26 27 return INVALID_GCSR; 28 } 29 30 static inline void set_gcsr_sw_flag(int csr) 31 { 32 if (csr < CSR_MAX_NUMS) 33 gcsr_flag[csr] |= SW_GCSR; 34 } 35 36 static inline void set_gcsr_hw_flag(int csr) 37 { 38 if (csr < CSR_MAX_NUMS) 39 gcsr_flag[csr] |= HW_GCSR; 40 } 41 42 /* 43 * The default value of gcsr_flag[CSR] is 0, and we use this 44 * function to set the flag to 1 (SW_GCSR) or 2 (HW_GCSR) if the 45 * gcsr is software or hardware. It will be used by get/set_gcsr, 46 * if gcsr_flag is HW we should use gcsrrd/gcsrwr to access it, 47 * else use software csr to emulate it. 48 */ 49 static void kvm_init_gcsr_flag(void) 50 { 51 set_gcsr_hw_flag(LOONGARCH_CSR_CRMD); 52 set_gcsr_hw_flag(LOONGARCH_CSR_PRMD); 53 set_gcsr_hw_flag(LOONGARCH_CSR_EUEN); 54 set_gcsr_hw_flag(LOONGARCH_CSR_MISC); 55 set_gcsr_hw_flag(LOONGARCH_CSR_ECFG); 56 set_gcsr_hw_flag(LOONGARCH_CSR_ESTAT); 57 set_gcsr_hw_flag(LOONGARCH_CSR_ERA); 58 set_gcsr_hw_flag(LOONGARCH_CSR_BADV); 59 set_gcsr_hw_flag(LOONGARCH_CSR_BADI); 60 set_gcsr_hw_flag(LOONGARCH_CSR_EENTRY); 61 set_gcsr_hw_flag(LOONGARCH_CSR_TLBIDX); 62 set_gcsr_hw_flag(LOONGARCH_CSR_TLBEHI); 63 set_gcsr_hw_flag(LOONGARCH_CSR_TLBELO0); 64 set_gcsr_hw_flag(LOONGARCH_CSR_TLBELO1); 65 set_gcsr_hw_flag(LOONGARCH_CSR_ASID); 66 set_gcsr_hw_flag(LOONGARCH_CSR_PGDL); 67 set_gcsr_hw_flag(LOONGARCH_CSR_PGDH); 68 set_gcsr_hw_flag(LOONGARCH_CSR_PGD); 69 set_gcsr_hw_flag(LOONGARCH_CSR_PWCTL0); 70 set_gcsr_hw_flag(LOONGARCH_CSR_PWCTL1); 71 set_gcsr_hw_flag(LOONGARCH_CSR_STLBPGSIZE); 72 set_gcsr_hw_flag(LOONGARCH_CSR_RVACFG); 73 set_gcsr_hw_flag(LOONGARCH_CSR_CPUID); 74 set_gcsr_hw_flag(LOONGARCH_CSR_PRCFG1); 75 set_gcsr_hw_flag(LOONGARCH_CSR_PRCFG2); 76 set_gcsr_hw_flag(LOONGARCH_CSR_PRCFG3); 77 set_gcsr_hw_flag(LOONGARCH_CSR_KS0); 78 set_gcsr_hw_flag(LOONGARCH_CSR_KS1); 79 set_gcsr_hw_flag(LOONGARCH_CSR_KS2); 80 set_gcsr_hw_flag(LOONGARCH_CSR_KS3); 81 set_gcsr_hw_flag(LOONGARCH_CSR_KS4); 82 set_gcsr_hw_flag(LOONGARCH_CSR_KS5); 83 set_gcsr_hw_flag(LOONGARCH_CSR_KS6); 84 set_gcsr_hw_flag(LOONGARCH_CSR_KS7); 85 set_gcsr_hw_flag(LOONGARCH_CSR_TMID); 86 set_gcsr_hw_flag(LOONGARCH_CSR_TCFG); 87 set_gcsr_hw_flag(LOONGARCH_CSR_TVAL); 88 set_gcsr_hw_flag(LOONGARCH_CSR_TINTCLR); 89 set_gcsr_hw_flag(LOONGARCH_CSR_CNTC); 90 set_gcsr_hw_flag(LOONGARCH_CSR_LLBCTL); 91 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRENTRY); 92 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRBADV); 93 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRERA); 94 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRSAVE); 95 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRELO0); 96 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRELO1); 97 set_gcsr_hw_flag(LOONGARCH_CSR_TLBREHI); 98 set_gcsr_hw_flag(LOONGARCH_CSR_TLBRPRMD); 99 set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN0); 100 set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN1); 101 set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN2); 102 set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN3); 103 104 set_gcsr_sw_flag(LOONGARCH_CSR_IMPCTL1); 105 set_gcsr_sw_flag(LOONGARCH_CSR_IMPCTL2); 106 set_gcsr_sw_flag(LOONGARCH_CSR_MERRCTL); 107 set_gcsr_sw_flag(LOONGARCH_CSR_MERRINFO1); 108 set_gcsr_sw_flag(LOONGARCH_CSR_MERRINFO2); 109 set_gcsr_sw_flag(LOONGARCH_CSR_MERRENTRY); 110 set_gcsr_sw_flag(LOONGARCH_CSR_MERRERA); 111 set_gcsr_sw_flag(LOONGARCH_CSR_MERRSAVE); 112 set_gcsr_sw_flag(LOONGARCH_CSR_CTAG); 113 set_gcsr_sw_flag(LOONGARCH_CSR_DEBUG); 114 set_gcsr_sw_flag(LOONGARCH_CSR_DERA); 115 set_gcsr_sw_flag(LOONGARCH_CSR_DESAVE); 116 117 set_gcsr_sw_flag(LOONGARCH_CSR_FWPC); 118 set_gcsr_sw_flag(LOONGARCH_CSR_FWPS); 119 set_gcsr_sw_flag(LOONGARCH_CSR_MWPC); 120 set_gcsr_sw_flag(LOONGARCH_CSR_MWPS); 121 122 set_gcsr_sw_flag(LOONGARCH_CSR_DB0ADDR); 123 set_gcsr_sw_flag(LOONGARCH_CSR_DB0MASK); 124 set_gcsr_sw_flag(LOONGARCH_CSR_DB0CTRL); 125 set_gcsr_sw_flag(LOONGARCH_CSR_DB0ASID); 126 set_gcsr_sw_flag(LOONGARCH_CSR_DB1ADDR); 127 set_gcsr_sw_flag(LOONGARCH_CSR_DB1MASK); 128 set_gcsr_sw_flag(LOONGARCH_CSR_DB1CTRL); 129 set_gcsr_sw_flag(LOONGARCH_CSR_DB1ASID); 130 set_gcsr_sw_flag(LOONGARCH_CSR_DB2ADDR); 131 set_gcsr_sw_flag(LOONGARCH_CSR_DB2MASK); 132 set_gcsr_sw_flag(LOONGARCH_CSR_DB2CTRL); 133 set_gcsr_sw_flag(LOONGARCH_CSR_DB2ASID); 134 set_gcsr_sw_flag(LOONGARCH_CSR_DB3ADDR); 135 set_gcsr_sw_flag(LOONGARCH_CSR_DB3MASK); 136 set_gcsr_sw_flag(LOONGARCH_CSR_DB3CTRL); 137 set_gcsr_sw_flag(LOONGARCH_CSR_DB3ASID); 138 set_gcsr_sw_flag(LOONGARCH_CSR_DB4ADDR); 139 set_gcsr_sw_flag(LOONGARCH_CSR_DB4MASK); 140 set_gcsr_sw_flag(LOONGARCH_CSR_DB4CTRL); 141 set_gcsr_sw_flag(LOONGARCH_CSR_DB4ASID); 142 set_gcsr_sw_flag(LOONGARCH_CSR_DB5ADDR); 143 set_gcsr_sw_flag(LOONGARCH_CSR_DB5MASK); 144 set_gcsr_sw_flag(LOONGARCH_CSR_DB5CTRL); 145 set_gcsr_sw_flag(LOONGARCH_CSR_DB5ASID); 146 set_gcsr_sw_flag(LOONGARCH_CSR_DB6ADDR); 147 set_gcsr_sw_flag(LOONGARCH_CSR_DB6MASK); 148 set_gcsr_sw_flag(LOONGARCH_CSR_DB6CTRL); 149 set_gcsr_sw_flag(LOONGARCH_CSR_DB6ASID); 150 set_gcsr_sw_flag(LOONGARCH_CSR_DB7ADDR); 151 set_gcsr_sw_flag(LOONGARCH_CSR_DB7MASK); 152 set_gcsr_sw_flag(LOONGARCH_CSR_DB7CTRL); 153 set_gcsr_sw_flag(LOONGARCH_CSR_DB7ASID); 154 155 set_gcsr_sw_flag(LOONGARCH_CSR_IB0ADDR); 156 set_gcsr_sw_flag(LOONGARCH_CSR_IB0MASK); 157 set_gcsr_sw_flag(LOONGARCH_CSR_IB0CTRL); 158 set_gcsr_sw_flag(LOONGARCH_CSR_IB0ASID); 159 set_gcsr_sw_flag(LOONGARCH_CSR_IB1ADDR); 160 set_gcsr_sw_flag(LOONGARCH_CSR_IB1MASK); 161 set_gcsr_sw_flag(LOONGARCH_CSR_IB1CTRL); 162 set_gcsr_sw_flag(LOONGARCH_CSR_IB1ASID); 163 set_gcsr_sw_flag(LOONGARCH_CSR_IB2ADDR); 164 set_gcsr_sw_flag(LOONGARCH_CSR_IB2MASK); 165 set_gcsr_sw_flag(LOONGARCH_CSR_IB2CTRL); 166 set_gcsr_sw_flag(LOONGARCH_CSR_IB2ASID); 167 set_gcsr_sw_flag(LOONGARCH_CSR_IB3ADDR); 168 set_gcsr_sw_flag(LOONGARCH_CSR_IB3MASK); 169 set_gcsr_sw_flag(LOONGARCH_CSR_IB3CTRL); 170 set_gcsr_sw_flag(LOONGARCH_CSR_IB3ASID); 171 set_gcsr_sw_flag(LOONGARCH_CSR_IB4ADDR); 172 set_gcsr_sw_flag(LOONGARCH_CSR_IB4MASK); 173 set_gcsr_sw_flag(LOONGARCH_CSR_IB4CTRL); 174 set_gcsr_sw_flag(LOONGARCH_CSR_IB4ASID); 175 set_gcsr_sw_flag(LOONGARCH_CSR_IB5ADDR); 176 set_gcsr_sw_flag(LOONGARCH_CSR_IB5MASK); 177 set_gcsr_sw_flag(LOONGARCH_CSR_IB5CTRL); 178 set_gcsr_sw_flag(LOONGARCH_CSR_IB5ASID); 179 set_gcsr_sw_flag(LOONGARCH_CSR_IB6ADDR); 180 set_gcsr_sw_flag(LOONGARCH_CSR_IB6MASK); 181 set_gcsr_sw_flag(LOONGARCH_CSR_IB6CTRL); 182 set_gcsr_sw_flag(LOONGARCH_CSR_IB6ASID); 183 set_gcsr_sw_flag(LOONGARCH_CSR_IB7ADDR); 184 set_gcsr_sw_flag(LOONGARCH_CSR_IB7MASK); 185 set_gcsr_sw_flag(LOONGARCH_CSR_IB7CTRL); 186 set_gcsr_sw_flag(LOONGARCH_CSR_IB7ASID); 187 188 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL0); 189 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR0); 190 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL1); 191 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR1); 192 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL2); 193 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR2); 194 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL3); 195 set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR3); 196 197 if (cpu_has_msgint) { 198 set_gcsr_hw_flag(LOONGARCH_CSR_IPR); 199 set_gcsr_hw_flag(LOONGARCH_CSR_ISR0); 200 set_gcsr_hw_flag(LOONGARCH_CSR_ISR1); 201 set_gcsr_hw_flag(LOONGARCH_CSR_ISR2); 202 set_gcsr_hw_flag(LOONGARCH_CSR_ISR3); 203 } 204 } 205 206 static void kvm_update_vpid(struct kvm_vcpu *vcpu, int cpu) 207 { 208 unsigned long vpid; 209 struct kvm_context *context; 210 211 context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu); 212 vpid = context->vpid_cache + 1; 213 if (!(vpid & vpid_mask)) { 214 /* finish round of vpid loop */ 215 if (unlikely(!vpid)) 216 vpid = vpid_mask + 1; 217 218 ++vpid; /* vpid 0 reserved for root */ 219 220 /* start new vpid cycle */ 221 if (!cpu_has_guestid) 222 kvm_flush_tlb_all(); 223 else 224 kvm_flush_tlb_all_stage1(); 225 } 226 227 context->vpid_cache = vpid; 228 vcpu->arch.vpid = vpid; 229 } 230 231 static void __kvm_check_vpid(struct kvm_vcpu *vcpu) 232 { 233 int cpu; 234 bool migrated; 235 unsigned long ver, old, vpid; 236 struct kvm_context *context; 237 238 cpu = smp_processor_id(); 239 /* 240 * Are we entering guest context on a different CPU to last time? 241 * If so, the vCPU's guest TLB state on this CPU may be stale. 242 */ 243 context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu); 244 migrated = (vcpu->cpu != cpu); 245 246 /* 247 * Check if our vpid is of an older version 248 * 249 * We also discard the stored vpid if we've executed on 250 * another CPU, as the guest mappings may have changed without 251 * hypervisor knowledge. 252 */ 253 ver = vcpu->arch.vpid & ~vpid_mask; 254 old = context->vpid_cache & ~vpid_mask; 255 if (migrated || (ver != old)) { 256 kvm_update_vpid(vcpu, cpu); 257 trace_kvm_vpid_change(vcpu, vcpu->arch.vpid); 258 vcpu->cpu = cpu; 259 260 /* 261 * LLBCTL is a separated guest CSR register from host, a general 262 * exception ERET instruction clears the host LLBCTL register in 263 * host mode, and clears the guest LLBCTL register in guest mode. 264 * ERET in tlb refill exception does not clear LLBCTL register. 265 * 266 * When secondary mmu mapping is changed, guest OS does not know 267 * even if the content is changed after mapping is changed. 268 * 269 * Here clear WCLLB of the guest LLBCTL register when mapping is 270 * changed. Otherwise, if mmu mapping is changed while guest is 271 * executing LL/SC pair, LL loads with the old address and set 272 * the LLBCTL flag, SC checks the LLBCTL flag and will store the 273 * new address successfully since LLBCTL_WCLLB is on, even if 274 * memory with new address is changed on other VCPUs. 275 */ 276 set_gcsr_llbctl(CSR_LLBCTL_WCLLB); 277 278 /* Restore GSTAT(0x50).vpid */ 279 vpid = (vcpu->arch.vpid & vpid_mask) << CSR_GSTAT_GID_SHIFT; 280 change_csr_gstat(vpid_mask << CSR_GSTAT_GID_SHIFT, vpid); 281 } 282 } 283 284 static void kvm_update_vmid(struct kvm_vcpu *vcpu, int cpu) 285 { 286 unsigned long vmid; 287 struct kvm_context *context; 288 289 context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu); 290 vmid = context->vmid_cache + 1; 291 if (!(vmid & vpid_mask)) { 292 /* finish round of vmid loop */ 293 if (unlikely(!vmid)) 294 vmid = vpid_mask + 1; 295 296 ++vmid; /* vmid 0 reserved for root */ 297 298 /* start new vmid cycle */ 299 kvm_flush_tlb_all_stage2(); 300 } 301 302 context->vmid_cache = vmid; 303 vcpu->kvm->arch.vmid[cpu] = vmid; 304 } 305 306 static void __kvm_check_vmid(struct kvm_vcpu *vcpu) 307 { 308 int cpu; 309 unsigned long ver, old, vmid; 310 311 /* On CPUs like Loongson-3A5000, vmid must be the same as vpid */ 312 if (!cpu_has_guestid) { 313 vmid = vcpu->arch.vpid & vpid_mask; 314 if (vcpu->arch.tgid != vmid) { 315 vcpu->arch.tgid = vcpu->arch.vpid & vpid_mask; 316 kvm_clear_request(KVM_REQ_TLB_FLUSH_GPA, vcpu); 317 } 318 return; 319 } 320 321 cpu = smp_processor_id(); 322 if (cpumask_test_and_clear_cpu(cpu, &vcpu->kvm->arch.tlb_flush_pending)) 323 vcpu->kvm->arch.vmid[cpu] = 0; 324 325 /* Check if our vmid is of an older version */ 326 ver = vcpu->kvm->arch.vmid[cpu] & ~vpid_mask; 327 old = this_cpu_ptr(vcpu->kvm->arch.vmcs)->vmid_cache & ~vpid_mask; 328 if (ver != old) 329 kvm_update_vmid(vcpu, cpu); 330 331 vcpu->arch.tgid = vcpu->kvm->arch.vmid[cpu] & vpid_mask; 332 } 333 334 void kvm_check_vpid(struct kvm_vcpu *vcpu) 335 { 336 __kvm_check_vpid(vcpu); 337 __kvm_check_vmid(vcpu); 338 } 339 340 void kvm_init_vmcs(struct kvm *kvm) 341 { 342 kvm->arch.vmcs = vmcs; 343 } 344 345 long kvm_arch_dev_ioctl(struct file *filp, 346 unsigned int ioctl, unsigned long arg) 347 { 348 return -ENOIOCTLCMD; 349 } 350 351 int kvm_arch_enable_virtualization_cpu(void) 352 { 353 unsigned long env, gcfg = 0; 354 355 env = read_csr_gcfg(); 356 357 /* First init gcfg, gstat, gintc, gtlbc. All guest use the same config */ 358 write_csr_gcfg(0); 359 write_csr_gstat(0); 360 write_csr_gintc(0); 361 clear_csr_gtlbc(CSR_GTLBC_TOTI | CSR_GTLBC_USETGID | CSR_GTLBC_USES2TGID); 362 363 /* 364 * Enable virtualization features granting guest direct control of 365 * certain features: 366 * GCI=2: Trap on init or unimplemented cache instruction. 367 * TORU=0: Trap on Root Unimplement. 368 * CACTRL=1: Root control cache. 369 * TOP=0: Trap on Privilege. 370 * TOE=0: Trap on Exception. 371 * TIT=0: Trap on Timer. 372 */ 373 if (env & CSR_GCFG_GCIP_SECURE) 374 gcfg |= CSR_GCFG_GCI_SECURE; 375 if (env & CSR_GCFG_MATP_ROOT) 376 gcfg |= CSR_GCFG_MATC_ROOT; 377 378 write_csr_gcfg(gcfg); 379 380 kvm_flush_tlb_all(); 381 382 /* Enable using TGID */ 383 set_csr_gtlbc(CSR_GTLBC_USETGID); 384 if (cpu_has_guestid) 385 set_csr_gtlbc(CSR_GTLBC_USES2TGID); 386 kvm_debug("GCFG:%lx GSTAT:%lx GINTC:%lx GTLBC:%lx", 387 read_csr_gcfg(), read_csr_gstat(), read_csr_gintc(), read_csr_gtlbc()); 388 389 /* 390 * HW Guest CSR registers are lost after CPU suspend and resume. 391 * Clear last_vcpu so that Guest CSR registers forced to reload 392 * from vCPU SW state. 393 */ 394 this_cpu_ptr(vmcs)->last_vcpu = NULL; 395 396 return 0; 397 } 398 399 void kvm_arch_disable_virtualization_cpu(void) 400 { 401 write_csr_gcfg(0); 402 write_csr_gstat(0); 403 write_csr_gintc(0); 404 clear_csr_gtlbc(CSR_GTLBC_TOTI | CSR_GTLBC_USETGID | CSR_GTLBC_USES2TGID); 405 406 /* Flush any remaining guest TLB entries */ 407 kvm_flush_tlb_all(); 408 } 409 410 static int kvm_loongarch_env_init(void) 411 { 412 int cpu, ret; 413 struct kvm_context *context; 414 415 vmcs = alloc_percpu(struct kvm_context); 416 if (!vmcs) { 417 pr_err("kvm: failed to allocate percpu kvm_context\n"); 418 return -ENOMEM; 419 } 420 421 kvm_loongarch_ops = kzalloc_obj(*kvm_loongarch_ops); 422 if (!kvm_loongarch_ops) { 423 free_percpu(vmcs); 424 vmcs = NULL; 425 return -ENOMEM; 426 } 427 428 kvm_loongarch_ops->exc_entry = (void *)kvm_exc_entry; 429 kvm_loongarch_ops->enter_guest = (void *)kvm_enter_guest; 430 431 vpid_mask = read_csr_gstat(); 432 vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> CSR_GSTAT_GIDBIT_SHIFT; 433 if (vpid_mask) 434 vpid_mask = GENMASK(vpid_mask - 1, 0); 435 436 for_each_possible_cpu(cpu) { 437 context = per_cpu_ptr(vmcs, cpu); 438 context->vpid_cache = vpid_mask + 1; 439 context->vmid_cache = vpid_mask + 1; 440 context->last_vcpu = NULL; 441 } 442 443 kvm_init_gcsr_flag(); 444 kvm_register_perf_callbacks(); 445 446 /* Register LoongArch IPI interrupt controller interface. */ 447 ret = kvm_loongarch_register_ipi_device(); 448 if (ret) 449 goto err_env; 450 451 /* Register LoongArch EIOINTC interrupt controller interface. */ 452 ret = kvm_loongarch_register_eiointc_device(); 453 if (ret) 454 goto err_ipi; 455 456 /* Register LoongArch PCH-PIC interrupt controller interface. */ 457 ret = kvm_loongarch_register_pch_pic_device(); 458 if (ret) 459 goto err_eiointc; 460 461 /* Register LoongArch DMSINTC interrupt contrroller interface */ 462 if (cpu_has_msgint) { 463 ret = kvm_loongarch_register_dmsintc_device(); 464 if (ret) 465 goto err_pch_pic; 466 } 467 468 return 0; 469 470 err_pch_pic: 471 kvm_loongarch_unregister_pch_pic_device(); 472 err_eiointc: 473 kvm_loongarch_unregister_eiointc_device(); 474 err_ipi: 475 kvm_loongarch_unregister_ipi_device(); 476 err_env: 477 kvm_unregister_perf_callbacks(); 478 kfree(kvm_loongarch_ops); 479 kvm_loongarch_ops = NULL; 480 free_percpu(vmcs); 481 vmcs = NULL; 482 483 return ret; 484 } 485 486 static void kvm_loongarch_env_exit(void) 487 { 488 if (cpu_has_msgint) 489 kvm_loongarch_unregister_dmsintc_device(); 490 491 kvm_loongarch_unregister_pch_pic_device(); 492 kvm_loongarch_unregister_eiointc_device(); 493 kvm_loongarch_unregister_ipi_device(); 494 495 if (vmcs) 496 free_percpu(vmcs); 497 498 if (kvm_loongarch_ops) { 499 kfree(kvm_loongarch_ops); 500 } 501 502 kvm_unregister_perf_callbacks(); 503 } 504 505 static int kvm_loongarch_init(void) 506 { 507 int r; 508 509 if (!cpu_has_lvz) { 510 kvm_info("Hardware virtualization not available\n"); 511 return -ENODEV; 512 } 513 r = kvm_loongarch_env_init(); 514 if (r) 515 return r; 516 517 r = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); 518 if (r) 519 kvm_loongarch_env_exit(); 520 521 return r; 522 } 523 524 static void kvm_loongarch_exit(void) 525 { 526 kvm_exit(); 527 kvm_loongarch_env_exit(); 528 } 529 530 module_init(kvm_loongarch_init); 531 module_exit(kvm_loongarch_exit); 532 533 #ifdef MODULE 534 static const struct cpu_feature kvm_feature[] = { 535 { .feature = cpu_feature(LOONGARCH_LVZ) }, 536 {}, 537 }; 538 MODULE_DEVICE_TABLE(cpu, kvm_feature); 539 #endif 540