1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 * 5 * Authors: 6 * Anup Patel <anup.patel@wdc.com> 7 */ 8 9 #include <linux/errno.h> 10 #include <linux/err.h> 11 #include <linux/module.h> 12 #include <linux/kvm_host.h> 13 #include <asm/cpufeature.h> 14 #include <asm/kvm_mmu.h> 15 #include <asm/kvm_nacl.h> 16 #include <asm/sbi.h> 17 18 DEFINE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa); 19 20 static void kvm_riscv_setup_vendor_features(void) 21 { 22 /* Andes AX66: split two-stage TLBs */ 23 if (riscv_cached_mvendorid(0) == ANDES_VENDOR_ID && 24 (riscv_cached_marchid(0) & 0xFFFF) == 0x8A66) { 25 static_branch_enable(&kvm_riscv_vsstage_tlb_no_gpa); 26 kvm_info("VS-stage TLB does not cache guest physical address and VMID\n"); 27 } 28 } 29 30 long kvm_arch_dev_ioctl(struct file *filp, 31 unsigned int ioctl, unsigned long arg) 32 { 33 return -EINVAL; 34 } 35 36 int kvm_arch_enable_virtualization_cpu(void) 37 { 38 int rc; 39 40 rc = kvm_riscv_nacl_enable(); 41 if (rc) 42 return rc; 43 44 csr_write(CSR_HEDELEG, KVM_HEDELEG_DEFAULT); 45 csr_write(CSR_HIDELEG, KVM_HIDELEG_DEFAULT); 46 47 /* VS should access only the time counter directly. Everything else should trap */ 48 csr_write(CSR_HCOUNTEREN, 0x02); 49 50 csr_write(CSR_HVIP, 0); 51 52 kvm_riscv_aia_enable(); 53 54 return 0; 55 } 56 57 void kvm_arch_disable_virtualization_cpu(void) 58 { 59 kvm_riscv_aia_disable(); 60 61 /* 62 * After clearing the hideleg CSR, the host kernel will receive 63 * spurious interrupts if hvip CSR has pending interrupts and the 64 * corresponding enable bits in vsie CSR are asserted. To avoid it, 65 * hvip CSR and vsie CSR must be cleared before clearing hideleg CSR. 66 */ 67 csr_write(CSR_VSIE, 0); 68 csr_write(CSR_HVIP, 0); 69 csr_write(CSR_HEDELEG, 0); 70 csr_write(CSR_HIDELEG, 0); 71 72 kvm_riscv_nacl_disable(); 73 } 74 75 static void kvm_riscv_teardown(void) 76 { 77 kvm_riscv_aia_exit(); 78 kvm_riscv_nacl_exit(); 79 kvm_unregister_perf_callbacks(); 80 } 81 82 static int __init riscv_kvm_init(void) 83 { 84 int rc; 85 char slist[64]; 86 const char *str; 87 88 if (!riscv_isa_extension_available(NULL, h)) { 89 kvm_info("hypervisor extension not available\n"); 90 return -ENODEV; 91 } 92 93 if (sbi_spec_is_0_1()) { 94 kvm_info("require SBI v0.2 or higher\n"); 95 return -ENODEV; 96 } 97 98 if (!sbi_probe_extension(SBI_EXT_RFENCE)) { 99 kvm_info("require SBI RFENCE extension\n"); 100 return -ENODEV; 101 } 102 103 rc = kvm_riscv_nacl_init(); 104 if (rc && rc != -ENODEV) 105 return rc; 106 107 kvm_riscv_gstage_mode_detect(); 108 switch (kvm_riscv_gstage_mode) { 109 case HGATP_MODE_SV32X4: 110 str = "Sv32x4"; 111 break; 112 case HGATP_MODE_SV39X4: 113 str = "Sv39x4"; 114 break; 115 case HGATP_MODE_SV48X4: 116 str = "Sv48x4"; 117 break; 118 case HGATP_MODE_SV57X4: 119 str = "Sv57x4"; 120 break; 121 default: 122 kvm_riscv_nacl_exit(); 123 return -ENODEV; 124 } 125 126 kvm_riscv_gstage_vmid_detect(); 127 128 rc = kvm_riscv_aia_init(); 129 if (rc && rc != -ENODEV) { 130 kvm_riscv_nacl_exit(); 131 return rc; 132 } 133 134 kvm_info("hypervisor extension available\n"); 135 136 if (kvm_riscv_nacl_available()) { 137 rc = 0; 138 slist[0] = '\0'; 139 if (kvm_riscv_nacl_sync_csr_available()) { 140 if (rc) 141 strcat(slist, ", "); 142 strcat(slist, "sync_csr"); 143 rc++; 144 } 145 if (kvm_riscv_nacl_sync_hfence_available()) { 146 if (rc) 147 strcat(slist, ", "); 148 strcat(slist, "sync_hfence"); 149 rc++; 150 } 151 if (kvm_riscv_nacl_sync_sret_available()) { 152 if (rc) 153 strcat(slist, ", "); 154 strcat(slist, "sync_sret"); 155 rc++; 156 } 157 if (kvm_riscv_nacl_autoswap_csr_available()) { 158 if (rc) 159 strcat(slist, ", "); 160 strcat(slist, "autoswap_csr"); 161 rc++; 162 } 163 kvm_info("using SBI nested acceleration with %s\n", 164 (rc) ? slist : "no features"); 165 } 166 167 kvm_info("using %s G-stage page table format\n", str); 168 169 kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits()); 170 171 if (kvm_riscv_aia_available()) 172 kvm_info("AIA available with %d guest external interrupts\n", 173 kvm_riscv_aia_nr_hgei); 174 175 kvm_riscv_setup_vendor_features(); 176 177 kvm_register_perf_callbacks(NULL); 178 179 rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); 180 if (rc) { 181 kvm_riscv_teardown(); 182 return rc; 183 } 184 185 return 0; 186 } 187 module_init(riscv_kvm_init); 188 189 static void __exit riscv_kvm_exit(void) 190 { 191 kvm_exit(); 192 193 kvm_riscv_teardown(); 194 } 195 module_exit(riscv_kvm_exit); 196