Skip to content

Commit c983b3e

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/pkvm-features-6.20 into kvmarm-master/next
* kvm-arm64/pkvm-features-6.20: : . : pKVM guest feature trapping fixes, courtesy of Fuad Tabba. : . KVM: arm64: Prevent host from managing timer offsets for protected VMs KVM: arm64: Check whether a VM IOCTL is allowed in pKVM KVM: arm64: Track KVM IOCTLs and their associated KVM caps KVM: arm64: Do not allow KVM_CAP_ARM_MTE for any guest in pKVM KVM: arm64: Include VM type when checking VM capabilities in pKVM KVM: arm64: Introduce helper to calculate fault IPA offset KVM: arm64: Fix MTE flag initialization for protected VMs KVM: arm64: Fix Trace Buffer trap polarity for protected VMs KVM: arm64: Fix Trace Buffer trapping for protected VMs Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents cb6cd8a + f7d05ee commit c983b3e

9 files changed

Lines changed: 108 additions & 24 deletions

File tree

arch/arm64/include/asm/kvm_arm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@
316316
#define PAR_TO_HPFAR(par) \
317317
(((par) & GENMASK_ULL(52 - 1, 12)) >> 8)
318318

319+
#define FAR_TO_FIPA_OFFSET(far) ((far) & GENMASK_ULL(11, 0))
320+
319321
#define ECN(x) { ESR_ELx_EC_##x, #x }
320322

321323
#define kvm_arm_exception_class \

arch/arm64/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,4 +1656,6 @@ static __always_inline enum fgt_group_id __fgt_reg_to_group_id(enum vcpu_sysreg
16561656
p; \
16571657
})
16581658

1659+
long kvm_get_cap_for_kvm_ioctl(unsigned int ioctl, long *ext);
1660+
16591661
#endif /* __ARM64_KVM_HOST_H__ */

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/arm_ffa.h>
1010
#include <linux/memblock.h>
1111
#include <linux/scatterlist.h>
12+
#include <asm/kvm_host.h>
1213
#include <asm/kvm_pgtable.h>
1314

1415
/* Maximum number of VMs that can co-exist under pKVM. */
@@ -23,10 +24,12 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm);
2324
int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu);
2425

2526
/*
26-
* This functions as an allow-list of protected VM capabilities.
27-
* Features not explicitly allowed by this function are denied.
27+
* Check whether the specific capability is allowed in pKVM.
28+
*
29+
* Certain features are allowed only for non-protected VMs in pKVM, which is why
30+
* this takes the VM (kvm) as a parameter.
2831
*/
29-
static inline bool kvm_pvm_ext_allowed(long ext)
32+
static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
3033
{
3134
switch (ext) {
3235
case KVM_CAP_IRQCHIP:
@@ -42,11 +45,32 @@ static inline bool kvm_pvm_ext_allowed(long ext)
4245
case KVM_CAP_ARM_PTRAUTH_ADDRESS:
4346
case KVM_CAP_ARM_PTRAUTH_GENERIC:
4447
return true;
45-
default:
48+
case KVM_CAP_ARM_MTE:
4649
return false;
50+
default:
51+
return !kvm || !kvm_vm_is_protected(kvm);
4752
}
4853
}
4954

55+
/*
56+
* Check whether the KVM VM IOCTL is allowed in pKVM.
57+
*
58+
* Certain features are allowed only for non-protected VMs in pKVM, which is why
59+
* this takes the VM (kvm) as a parameter.
60+
*/
61+
static inline bool kvm_pkvm_ioctl_allowed(struct kvm *kvm, unsigned int ioctl)
62+
{
63+
long ext;
64+
int r;
65+
66+
r = kvm_get_cap_for_kvm_ioctl(ioctl, &ext);
67+
68+
if (WARN_ON_ONCE(r < 0))
69+
return false;
70+
71+
return kvm_pkvm_ext_allowed(kvm, ext);
72+
}
73+
5074
extern struct memblock_region kvm_nvhe_sym(hyp_memory)[];
5175
extern unsigned int kvm_nvhe_sym(hyp_memblock_nr);
5276

arch/arm64/kvm/arch_timer.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,10 +1056,14 @@ static void timer_context_init(struct kvm_vcpu *vcpu, int timerid)
10561056

10571057
ctxt->timer_id = timerid;
10581058

1059-
if (timerid == TIMER_VTIMER)
1060-
ctxt->offset.vm_offset = &kvm->arch.timer_data.voffset;
1061-
else
1062-
ctxt->offset.vm_offset = &kvm->arch.timer_data.poffset;
1059+
if (!kvm_vm_is_protected(vcpu->kvm)) {
1060+
if (timerid == TIMER_VTIMER)
1061+
ctxt->offset.vm_offset = &kvm->arch.timer_data.voffset;
1062+
else
1063+
ctxt->offset.vm_offset = &kvm->arch.timer_data.poffset;
1064+
} else {
1065+
ctxt->offset.vm_offset = NULL;
1066+
}
10631067

10641068
hrtimer_setup(&ctxt->hrtimer, kvm_hrtimer_expire, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
10651069

@@ -1083,7 +1087,8 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
10831087
timer_context_init(vcpu, i);
10841088

10851089
/* Synchronize offsets across timers of a VM if not already provided */
1086-
if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) {
1090+
if (!vcpu_is_protected(vcpu) &&
1091+
!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) {
10871092
timer_set_offset(vcpu_vtimer(vcpu), kvm_phys_timer_read());
10881093
timer_set_offset(vcpu_ptimer(vcpu), 0);
10891094
}
@@ -1687,6 +1692,9 @@ int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm,
16871692
if (offset->reserved)
16881693
return -EINVAL;
16891694

1695+
if (kvm_vm_is_protected(kvm))
1696+
return -EINVAL;
1697+
16901698
mutex_lock(&kvm->lock);
16911699

16921700
if (!kvm_trylock_all_vcpus(kvm)) {

arch/arm64/kvm/arm.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,51 @@ enum kvm_wfx_trap_policy {
5858
static enum kvm_wfx_trap_policy kvm_wfi_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
5959
static enum kvm_wfx_trap_policy kvm_wfe_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
6060

61+
/*
62+
* Tracks KVM IOCTLs and their associated KVM capabilities.
63+
*/
64+
struct kvm_ioctl_cap_map {
65+
unsigned int ioctl;
66+
long ext;
67+
};
68+
69+
/* Make KVM_CAP_NR_VCPUS the reference for features we always supported */
70+
#define KVM_CAP_ARM_BASIC KVM_CAP_NR_VCPUS
71+
72+
/*
73+
* Sorted by ioctl to allow for potential binary search,
74+
* though linear scan is sufficient for this size.
75+
*/
76+
static const struct kvm_ioctl_cap_map vm_ioctl_caps[] = {
77+
{ KVM_CREATE_IRQCHIP, KVM_CAP_IRQCHIP },
78+
{ KVM_ARM_SET_DEVICE_ADDR, KVM_CAP_ARM_SET_DEVICE_ADDR },
79+
{ KVM_ARM_MTE_COPY_TAGS, KVM_CAP_ARM_MTE },
80+
{ KVM_SET_DEVICE_ATTR, KVM_CAP_DEVICE_CTRL },
81+
{ KVM_GET_DEVICE_ATTR, KVM_CAP_DEVICE_CTRL },
82+
{ KVM_HAS_DEVICE_ATTR, KVM_CAP_DEVICE_CTRL },
83+
{ KVM_ARM_SET_COUNTER_OFFSET, KVM_CAP_COUNTER_OFFSET },
84+
{ KVM_ARM_GET_REG_WRITABLE_MASKS, KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES },
85+
{ KVM_ARM_PREFERRED_TARGET, KVM_CAP_ARM_BASIC },
86+
};
87+
88+
/*
89+
* Set *ext to the capability.
90+
* Return 0 if found, or -EINVAL if no IOCTL matches.
91+
*/
92+
long kvm_get_cap_for_kvm_ioctl(unsigned int ioctl, long *ext)
93+
{
94+
int i;
95+
96+
for (i = 0; i < ARRAY_SIZE(vm_ioctl_caps); i++) {
97+
if (vm_ioctl_caps[i].ioctl == ioctl) {
98+
*ext = vm_ioctl_caps[i].ext;
99+
return 0;
100+
}
101+
}
102+
103+
return -EINVAL;
104+
}
105+
61106
DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
62107

63108
DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_base);
@@ -87,7 +132,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
87132
if (cap->flags)
88133
return -EINVAL;
89134

90-
if (kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(cap->cap))
135+
if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, cap->cap))
91136
return -EINVAL;
92137

93138
switch (cap->cap) {
@@ -303,7 +348,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
303348
{
304349
int r;
305350

306-
if (kvm && kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(ext))
351+
if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, ext))
307352
return 0;
308353

309354
switch (ext) {
@@ -1894,6 +1939,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
18941939
void __user *argp = (void __user *)arg;
18951940
struct kvm_device_attr attr;
18961941

1942+
if (is_protected_kvm_enabled() && !kvm_pkvm_ioctl_allowed(kvm, ioctl))
1943+
return -EINVAL;
1944+
18971945
switch (ioctl) {
18981946
case KVM_CREATE_IRQCHIP: {
18991947
int ret;

arch/arm64/kvm/hyp/nvhe/pkvm.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ static void pvm_init_traps_mdcr(struct kvm_vcpu *vcpu)
117117
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceFilt, IMP))
118118
val |= MDCR_EL2_TTRF;
119119

120-
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, ExtTrcBuff, IMP))
121-
val |= MDCR_EL2_E2TB_MASK;
120+
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceBuffer, IMP))
121+
val &= ~MDCR_EL2_E2TB_MASK;
122122

123123
/* Trap Debug Communications Channel registers */
124124
if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, FGT, IMP))
@@ -339,9 +339,6 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
339339
/* Preserve the vgic model so that GICv3 emulation works */
340340
hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
341341

342-
if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
343-
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
344-
345342
/* No restrictions for non-protected VMs. */
346343
if (!kvm_vm_is_protected(kvm)) {
347344
hyp_vm->kvm.arch.flags = host_arch_flags;
@@ -356,20 +353,23 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
356353
return;
357354
}
358355

356+
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE))
357+
kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_MTE_ENABLED);
358+
359359
bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES);
360360

361361
set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features);
362362

363-
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PMU_V3))
363+
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PMU_V3))
364364
set_bit(KVM_ARM_VCPU_PMU_V3, allowed_features);
365365

366-
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_ADDRESS))
366+
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_ADDRESS))
367367
set_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, allowed_features);
368368

369-
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_GENERIC))
369+
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC))
370370
set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
371371

372-
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_SVE)) {
372+
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE)) {
373373
set_bit(KVM_ARM_VCPU_SVE, allowed_features);
374374
kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
375375
}

arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
4444

4545
/* Build the full address */
4646
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
47-
fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
47+
fault_ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
4848

4949
/* If not for GICV, move on */
5050
if (fault_ipa < vgic->vgic_cpu_base ||

arch/arm64/kvm/inject_fault.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
296296
unsigned long addr, esr;
297297

298298
addr = kvm_vcpu_get_fault_ipa(vcpu);
299-
addr |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
299+
addr |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
300300

301301
__kvm_inject_sea(vcpu, kvm_vcpu_trap_is_iabt(vcpu), addr);
302302

arch/arm64/kvm/mmu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,7 +2079,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
20792079

20802080
/* Falls between the IPA range and the PARange? */
20812081
if (fault_ipa >= BIT_ULL(VTCR_EL2_IPA(vcpu->arch.hw_mmu->vtcr))) {
2082-
fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
2082+
fault_ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
20832083

20842084
return kvm_inject_sea(vcpu, is_iabt, fault_ipa);
20852085
}
@@ -2185,7 +2185,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
21852185
* faulting VA. This is always 12 bits, irrespective
21862186
* of the page size.
21872187
*/
2188-
ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
2188+
ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
21892189
ret = io_mem_abort(vcpu, ipa);
21902190
goto out_unlock;
21912191
}

0 commit comments

Comments
 (0)