mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-27 14:29:59 -04:00
The KVM ISA extension related checks are not VCPU specific and should be factored out of vcpu_onereg.c into separate sources. Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com> Reviewed-by: Radim Krčmář <radim.krcmar@oss.qualcomm.com> Link: https://lore.kernel.org/r/20260120080013.2153519-6-anup.patel@oss.qualcomm.com Signed-off-by: Anup Patel <anup@brainfault.org>
254 lines
6.8 KiB
C
254 lines
6.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2026 Qualcomm Technologies, Inc.
|
|
*/
|
|
|
|
#include <linux/cpufeature.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/kvm_host.h>
|
|
#include <linux/nospec.h>
|
|
#include <linux/pgtable.h>
|
|
#include <asm/kvm_isa.h>
|
|
#include <asm/vector.h>
|
|
|
|
#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;
|
|
}
|