ANDROID: KVM: arm64: Restrict protected VM capabilities

Restrict protected VM capabilities based on the
fixed-configuration for protected VMs.

No functional change intended in current KVM-supported modes
(nVHE, VHE).

Signed-off-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Will Deacon <willdeacon@google.com>
Bug: 233587962
Change-Id: I1df873d512754207decf9eedb50135ee2ae76b29
This commit is contained in:
Fuad Tabba
2022-04-25 13:33:24 +00:00
committed by Will Deacon
parent 93c5d05944
commit b042ff6f1c
2 changed files with 95 additions and 1 deletions

View File

@@ -208,6 +208,33 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm);
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) \
)
/*
* Returns the maximum number of breakpoints supported for protected VMs.
*/
static inline int pkvm_get_max_brps(void)
{
int num = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_BRPs),
PVM_ID_AA64DFR0_ALLOW);
/*
* If breakpoints are supported, the maximum number is 1 + the field.
* Otherwise, return 0, which is not compliant with the architecture,
* but is reserved and is used here to indicate no debug support.
*/
return num ? num + 1 : 0;
}
/*
* Returns the maximum number of watchpoints supported for protected VMs.
*/
static inline int pkvm_get_max_wrps(void)
{
int num = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_WRPs),
PVM_ID_AA64DFR0_ALLOW);
return num ? num + 1 : 0;
}
extern struct memblock_region kvm_nvhe_sym(hyp_memory)[];
extern unsigned int kvm_nvhe_sym(hyp_memblock_nr);

View File

@@ -199,9 +199,10 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_unshare_hyp(kvm, kvm + 1);
}
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
static int kvm_check_extension(struct kvm *kvm, long ext)
{
int r;
switch (ext) {
case KVM_CAP_IRQCHIP:
r = vgic_present;
@@ -300,6 +301,72 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
return r;
}
/*
* Checks whether the extension specified in ext is supported in protected
* mode for the specified vm.
* The capabilities supported by kvm in general are passed in kvm_cap.
*/
static int pkvm_check_extension(struct kvm *kvm, long ext, int kvm_cap)
{
int r;
switch (ext) {
case KVM_CAP_IRQCHIP:
case KVM_CAP_ARM_PSCI:
case KVM_CAP_ARM_PSCI_0_2:
case KVM_CAP_NR_VCPUS:
case KVM_CAP_MAX_VCPUS:
case KVM_CAP_MAX_VCPU_ID:
case KVM_CAP_MSI_DEVID:
case KVM_CAP_ARM_VM_IPA_SIZE:
r = kvm_cap;
break;
case KVM_CAP_GUEST_DEBUG_HW_BPS:
r = min(kvm_cap, pkvm_get_max_brps());
break;
case KVM_CAP_GUEST_DEBUG_HW_WPS:
r = min(kvm_cap, pkvm_get_max_wrps());
break;
case KVM_CAP_ARM_PMU_V3:
r = kvm_cap && FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer),
PVM_ID_AA64DFR0_ALLOW);
break;
case KVM_CAP_ARM_SVE:
r = kvm_cap && FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE),
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED);
break;
case KVM_CAP_ARM_PTRAUTH_ADDRESS:
r = kvm_cap &&
FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API),
PVM_ID_AA64ISAR1_ALLOW) &&
FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA),
PVM_ID_AA64ISAR1_ALLOW);
break;
case KVM_CAP_ARM_PTRAUTH_GENERIC:
r = kvm_cap &&
FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI),
PVM_ID_AA64ISAR1_ALLOW) &&
FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA),
PVM_ID_AA64ISAR1_ALLOW);
break;
default:
r = 0;
break;
}
return r;
}
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
int r = kvm_check_extension(kvm, ext);
if (kvm && kvm_vm_is_protected(kvm))
r = pkvm_check_extension(kvm, ext, r);
return r;
}
long kvm_arch_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{