// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2026 Qualcomm Technologies, Inc. */ #include #include #include #include #include #include #include #define KVM_ISA_EXT_ARR(ext) \ [KVM_RISCV_ISA_EXT_##ext] = RISCV_ISA_EXT_##ext /* Mapping between KVM ISA Extension ID & guest ISA extension ID */ static const unsigned long kvm_isa_ext_arr[] = { /* Single letter extensions (alphabetically sorted) */ [KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a, [KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c, [KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d, [KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f, [KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h, [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i, [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v, /* Multi letter extensions (alphabetically sorted) */ KVM_ISA_EXT_ARR(SMNPM), KVM_ISA_EXT_ARR(SMSTATEEN), KVM_ISA_EXT_ARR(SSAIA), KVM_ISA_EXT_ARR(SSCOFPMF), KVM_ISA_EXT_ARR(SSNPM), KVM_ISA_EXT_ARR(SSTC), KVM_ISA_EXT_ARR(SVADE), KVM_ISA_EXT_ARR(SVADU), KVM_ISA_EXT_ARR(SVINVAL), KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), KVM_ISA_EXT_ARR(SVVPTC), KVM_ISA_EXT_ARR(ZAAMO), KVM_ISA_EXT_ARR(ZABHA), KVM_ISA_EXT_ARR(ZACAS), KVM_ISA_EXT_ARR(ZALASR), KVM_ISA_EXT_ARR(ZALRSC), KVM_ISA_EXT_ARR(ZAWRS), KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBC), KVM_ISA_EXT_ARR(ZBKB), KVM_ISA_EXT_ARR(ZBKC), KVM_ISA_EXT_ARR(ZBKX), KVM_ISA_EXT_ARR(ZBS), KVM_ISA_EXT_ARR(ZCA), KVM_ISA_EXT_ARR(ZCB), KVM_ISA_EXT_ARR(ZCD), KVM_ISA_EXT_ARR(ZCF), KVM_ISA_EXT_ARR(ZCLSD), KVM_ISA_EXT_ARR(ZCMOP), KVM_ISA_EXT_ARR(ZFA), KVM_ISA_EXT_ARR(ZFBFMIN), KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), KVM_ISA_EXT_ARR(ZICBOM), KVM_ISA_EXT_ARR(ZICBOP), KVM_ISA_EXT_ARR(ZICBOZ), KVM_ISA_EXT_ARR(ZICCRSE), KVM_ISA_EXT_ARR(ZICNTR), KVM_ISA_EXT_ARR(ZICOND), KVM_ISA_EXT_ARR(ZICSR), KVM_ISA_EXT_ARR(ZIFENCEI), KVM_ISA_EXT_ARR(ZIHINTNTL), KVM_ISA_EXT_ARR(ZIHINTPAUSE), KVM_ISA_EXT_ARR(ZIHPM), KVM_ISA_EXT_ARR(ZILSD), KVM_ISA_EXT_ARR(ZIMOP), KVM_ISA_EXT_ARR(ZKND), KVM_ISA_EXT_ARR(ZKNE), KVM_ISA_EXT_ARR(ZKNH), KVM_ISA_EXT_ARR(ZKR), KVM_ISA_EXT_ARR(ZKSED), KVM_ISA_EXT_ARR(ZKSH), KVM_ISA_EXT_ARR(ZKT), KVM_ISA_EXT_ARR(ZTSO), KVM_ISA_EXT_ARR(ZVBB), KVM_ISA_EXT_ARR(ZVBC), KVM_ISA_EXT_ARR(ZVFBFMIN), KVM_ISA_EXT_ARR(ZVFBFWMA), KVM_ISA_EXT_ARR(ZVFH), KVM_ISA_EXT_ARR(ZVFHMIN), KVM_ISA_EXT_ARR(ZVKB), KVM_ISA_EXT_ARR(ZVKG), KVM_ISA_EXT_ARR(ZVKNED), KVM_ISA_EXT_ARR(ZVKNHA), KVM_ISA_EXT_ARR(ZVKNHB), KVM_ISA_EXT_ARR(ZVKSED), KVM_ISA_EXT_ARR(ZVKSH), KVM_ISA_EXT_ARR(ZVKT), }; unsigned long kvm_riscv_base2isa_ext(unsigned long base_ext) { unsigned long i; for (i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) { if (kvm_isa_ext_arr[i] == base_ext) return i; } return KVM_RISCV_ISA_EXT_MAX; } int __kvm_riscv_isa_check_host(unsigned long kvm_ext, unsigned long *base_ext) { unsigned long host_ext; if (kvm_ext >= KVM_RISCV_ISA_EXT_MAX || kvm_ext >= ARRAY_SIZE(kvm_isa_ext_arr)) return -ENOENT; kvm_ext = array_index_nospec(kvm_ext, ARRAY_SIZE(kvm_isa_ext_arr)); switch (kvm_isa_ext_arr[kvm_ext]) { case RISCV_ISA_EXT_SMNPM: /* * Pointer masking effective in (H)S-mode is provided by the * Smnpm extension, so that extension is reported to the guest, * even though the CSR bits for configuring VS-mode pointer * masking on the host side are part of the Ssnpm extension. */ host_ext = RISCV_ISA_EXT_SSNPM; break; default: host_ext = kvm_isa_ext_arr[kvm_ext]; break; } if (!__riscv_isa_extension_available(NULL, host_ext)) return -ENOENT; if (base_ext) *base_ext = kvm_isa_ext_arr[kvm_ext]; return 0; } bool kvm_riscv_isa_enable_allowed(unsigned long ext) { switch (ext) { case KVM_RISCV_ISA_EXT_H: return false; case KVM_RISCV_ISA_EXT_SSCOFPMF: /* Sscofpmf depends on interrupt filtering defined in ssaia */ return !kvm_riscv_isa_check_host(SSAIA); case KVM_RISCV_ISA_EXT_SVADU: /* * The henvcfg.ADUE is read-only zero if menvcfg.ADUE is zero. * Guest OS can use Svadu only when host OS enable Svadu. */ return arch_has_hw_pte_young(); case KVM_RISCV_ISA_EXT_V: return riscv_v_vstate_ctrl_user_allowed(); default: break; } return true; } bool kvm_riscv_isa_disable_allowed(unsigned long ext) { switch (ext) { /* Extensions which don't have any mechanism to disable */ case KVM_RISCV_ISA_EXT_A: case KVM_RISCV_ISA_EXT_C: case KVM_RISCV_ISA_EXT_I: case KVM_RISCV_ISA_EXT_M: /* There is not architectural config bit to disable sscofpmf completely */ case KVM_RISCV_ISA_EXT_SSCOFPMF: case KVM_RISCV_ISA_EXT_SSNPM: case KVM_RISCV_ISA_EXT_SSTC: case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_RISCV_ISA_EXT_SVVPTC: case KVM_RISCV_ISA_EXT_ZAAMO: case KVM_RISCV_ISA_EXT_ZABHA: case KVM_RISCV_ISA_EXT_ZACAS: case KVM_RISCV_ISA_EXT_ZALASR: case KVM_RISCV_ISA_EXT_ZALRSC: case KVM_RISCV_ISA_EXT_ZAWRS: case KVM_RISCV_ISA_EXT_ZBA: case KVM_RISCV_ISA_EXT_ZBB: case KVM_RISCV_ISA_EXT_ZBC: case KVM_RISCV_ISA_EXT_ZBKB: case KVM_RISCV_ISA_EXT_ZBKC: case KVM_RISCV_ISA_EXT_ZBKX: case KVM_RISCV_ISA_EXT_ZBS: case KVM_RISCV_ISA_EXT_ZCA: case KVM_RISCV_ISA_EXT_ZCB: case KVM_RISCV_ISA_EXT_ZCD: case KVM_RISCV_ISA_EXT_ZCF: case KVM_RISCV_ISA_EXT_ZCMOP: case KVM_RISCV_ISA_EXT_ZFA: case KVM_RISCV_ISA_EXT_ZFBFMIN: case KVM_RISCV_ISA_EXT_ZFH: case KVM_RISCV_ISA_EXT_ZFHMIN: case KVM_RISCV_ISA_EXT_ZICBOP: case KVM_RISCV_ISA_EXT_ZICCRSE: case KVM_RISCV_ISA_EXT_ZICNTR: case KVM_RISCV_ISA_EXT_ZICOND: case KVM_RISCV_ISA_EXT_ZICSR: case KVM_RISCV_ISA_EXT_ZIFENCEI: case KVM_RISCV_ISA_EXT_ZIHINTNTL: case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: case KVM_RISCV_ISA_EXT_ZIHPM: case KVM_RISCV_ISA_EXT_ZIMOP: case KVM_RISCV_ISA_EXT_ZKND: case KVM_RISCV_ISA_EXT_ZKNE: case KVM_RISCV_ISA_EXT_ZKNH: case KVM_RISCV_ISA_EXT_ZKR: case KVM_RISCV_ISA_EXT_ZKSED: case KVM_RISCV_ISA_EXT_ZKSH: case KVM_RISCV_ISA_EXT_ZKT: case KVM_RISCV_ISA_EXT_ZTSO: case KVM_RISCV_ISA_EXT_ZVBB: case KVM_RISCV_ISA_EXT_ZVBC: case KVM_RISCV_ISA_EXT_ZVFBFMIN: case KVM_RISCV_ISA_EXT_ZVFBFWMA: case KVM_RISCV_ISA_EXT_ZVFH: case KVM_RISCV_ISA_EXT_ZVFHMIN: case KVM_RISCV_ISA_EXT_ZVKB: case KVM_RISCV_ISA_EXT_ZVKG: case KVM_RISCV_ISA_EXT_ZVKNED: case KVM_RISCV_ISA_EXT_ZVKNHA: case KVM_RISCV_ISA_EXT_ZVKNHB: case KVM_RISCV_ISA_EXT_ZVKSED: case KVM_RISCV_ISA_EXT_ZVKSH: case KVM_RISCV_ISA_EXT_ZVKT: return false; /* Extensions which can be disabled using Smstateen */ case KVM_RISCV_ISA_EXT_SSAIA: return riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN); case KVM_RISCV_ISA_EXT_SVADE: /* * The henvcfg.ADUE is read-only zero if menvcfg.ADUE is zero. * Svade can't be disabled unless we support Svadu. */ return arch_has_hw_pte_young(); default: break; } return true; }