Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: Setup a framework for hypercall bitmap firmware registers

KVM regularly introduces new hypercall services to the guests without
any consent from the userspace. This means, the guests can observe
hypercall services in and out as they migrate across various host
kernel versions. This could be a major problem if the guest
discovered a hypercall, started using it, and after getting migrated
to an older kernel realizes that it's no longer available. Depending
on how the guest handles the change, there's a potential chance that
the guest would just panic.

As a result, there's a need for the userspace to elect the services
that it wishes the guest to discover. It can elect these services
based on the kernels spread across its (migration) fleet. To remedy
this, extend the existing firmware pseudo-registers, such as
KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
for all the hypercall services available.

These firmware registers are categorized based on the service call
owners, but unlike the existing firmware pseudo-registers, they hold
the features supported in the form of a bitmap.

During the VM initialization, the registers are set to upper-limit of
the features supported by the corresponding registers. It's expected
that the VMMs discover the features provided by each register via
GET_ONE_REG, and write back the desired values using SET_ONE_REG.
KVM allows this modification only until the VM has started.

Some of the standard features are not mapped to any bits of the
registers. But since they can recreate the original problem of
making it available without userspace's consent, they need to
be explicitly added to the case-list in
kvm_hvc_call_default_allowed(). Any function-id that's not enabled
via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
be returned as SMCCC_RET_NOT_SUPPORTED to the guest.

Older userspace code can simply ignore the feature and the
hypercall services will be exposed unconditionally to the guests,
thus ensuring backward compatibility.

In this patch, the framework adds the register only for ARM's standard
secure services (owner value 4). Currently, this includes support only
for ARM True Random Number Generator (TRNG) service, with bit-0 of the
register representing mandatory features of v1.0. Other services are
momentarily added in the upcoming patches.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
[maz: reduced the scope of some helpers, tidy-up bitmap max values,
dropped error-only fast path]
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220502233853.1233742-3-rananta@google.com

authored by

Raghavendra Rao Ananta and committed by
Marc Zyngier
05714cab 85fbe08e

+137 -2
+12
arch/arm64/include/asm/kvm_host.h
··· 101 101 struct kvm_arch_memory_slot { 102 102 }; 103 103 104 + /** 105 + * struct kvm_smccc_features: Descriptor of the hypercall services exposed to the guests 106 + * 107 + * @std_bmap: Bitmap of standard secure service calls 108 + */ 109 + struct kvm_smccc_features { 110 + unsigned long std_bmap; 111 + }; 112 + 104 113 struct kvm_arch { 105 114 struct kvm_s2_mmu mmu; 106 115 ··· 159 150 160 151 u8 pfr0_csv2; 161 152 u8 pfr0_csv3; 153 + 154 + /* Hypercall features firmware registers' descriptor */ 155 + struct kvm_smccc_features smccc_feat; 162 156 }; 163 157 164 158 struct kvm_vcpu_fault_info {
+13
arch/arm64/include/uapi/asm/kvm.h
··· 332 332 #define KVM_ARM64_SVE_VLS_WORDS \ 333 333 ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1) 334 334 335 + /* Bitmap feature firmware registers */ 336 + #define KVM_REG_ARM_FW_FEAT_BMAP (0x0016 << KVM_REG_ARM_COPROC_SHIFT) 337 + #define KVM_REG_ARM_FW_FEAT_BMAP_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ 338 + KVM_REG_ARM_FW_FEAT_BMAP | \ 339 + ((r) & 0xffff)) 340 + 341 + #define KVM_REG_ARM_STD_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(0) 342 + 343 + enum { 344 + KVM_REG_ARM_STD_BIT_TRNG_V1_0 = 0, 345 + KVM_REG_ARM_STD_BMAP_BIT_COUNT, 346 + }; 347 + 335 348 /* Device Control API: ARM VGIC */ 336 349 #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 337 350 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
+1
arch/arm64/kvm/arm.c
··· 156 156 kvm->arch.max_vcpus = kvm_arm_default_max_vcpus(); 157 157 158 158 set_default_spectre(kvm); 159 + kvm_arm_init_hypercalls(kvm); 159 160 160 161 return ret; 161 162 out_free_stage2_pgd:
+6 -2
arch/arm64/kvm/guest.c
··· 756 756 757 757 switch (reg->id & KVM_REG_ARM_COPROC_MASK) { 758 758 case KVM_REG_ARM_CORE: return get_core_reg(vcpu, reg); 759 - case KVM_REG_ARM_FW: return kvm_arm_get_fw_reg(vcpu, reg); 759 + case KVM_REG_ARM_FW: 760 + case KVM_REG_ARM_FW_FEAT_BMAP: 761 + return kvm_arm_get_fw_reg(vcpu, reg); 760 762 case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg); 761 763 } 762 764 ··· 776 774 777 775 switch (reg->id & KVM_REG_ARM_COPROC_MASK) { 778 776 case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); 779 - case KVM_REG_ARM_FW: return kvm_arm_set_fw_reg(vcpu, reg); 777 + case KVM_REG_ARM_FW: 778 + case KVM_REG_ARM_FW_FEAT_BMAP: 779 + return kvm_arm_set_fw_reg(vcpu, reg); 780 780 case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg); 781 781 } 782 782
+104
arch/arm64/kvm/hypercalls.c
··· 9 9 #include <kvm/arm_hypercalls.h> 10 10 #include <kvm/arm_psci.h> 11 11 12 + #define KVM_ARM_SMCCC_STD_FEATURES \ 13 + GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0) 14 + 12 15 static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) 13 16 { 14 17 struct system_time_snapshot systime_snapshot; ··· 61 58 val[3] = lower_32_bits(cycles); 62 59 } 63 60 61 + static bool kvm_hvc_call_default_allowed(u32 func_id) 62 + { 63 + switch (func_id) { 64 + /* 65 + * List of function-ids that are not gated with the bitmapped 66 + * feature firmware registers, and are to be allowed for 67 + * servicing the call by default. 68 + */ 69 + case ARM_SMCCC_VERSION_FUNC_ID: 70 + case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 71 + case ARM_SMCCC_HV_PV_TIME_FEATURES: 72 + case ARM_SMCCC_HV_PV_TIME_ST: 73 + case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 74 + case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 75 + case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 76 + return true; 77 + default: 78 + /* PSCI 0.2 and up is in the 0:0x1f range */ 79 + if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD && 80 + ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f) 81 + return true; 82 + 83 + /* 84 + * KVM's PSCI 0.1 doesn't comply with SMCCC, and has 85 + * its own function-id base and range 86 + */ 87 + if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3)) 88 + return true; 89 + 90 + return false; 91 + } 92 + } 93 + 94 + static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) 95 + { 96 + struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 97 + 98 + switch (func_id) { 99 + case ARM_SMCCC_TRNG_VERSION: 100 + case ARM_SMCCC_TRNG_FEATURES: 101 + case ARM_SMCCC_TRNG_GET_UUID: 102 + case ARM_SMCCC_TRNG_RND32: 103 + case ARM_SMCCC_TRNG_RND64: 104 + return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0, 105 + &smccc_feat->std_bmap); 106 + default: 107 + return kvm_hvc_call_default_allowed(func_id); 108 + } 109 + } 110 + 64 111 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) 65 112 { 66 113 u32 func_id = smccc_get_function(vcpu); 67 114 u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 68 115 u32 feature; 69 116 gpa_t gpa; 117 + 118 + if (!kvm_hvc_call_allowed(vcpu, func_id)) 119 + goto out; 70 120 71 121 switch (func_id) { 72 122 case ARM_SMCCC_VERSION_FUNC_ID: ··· 211 155 return kvm_psci_call(vcpu); 212 156 } 213 157 158 + out: 214 159 smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 215 160 return 1; 216 161 } ··· 221 164 KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 222 165 KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 223 166 KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 167 + KVM_REG_ARM_STD_BMAP, 224 168 }; 169 + 170 + void kvm_arm_init_hypercalls(struct kvm *kvm) 171 + { 172 + struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 173 + 174 + smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 175 + } 225 176 226 177 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 227 178 { ··· 301 236 302 237 int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 303 238 { 239 + struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 304 240 void __user *uaddr = (void __user *)(long)reg->addr; 305 241 u64 val; 306 242 ··· 314 248 case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 315 249 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 316 250 break; 251 + case KVM_REG_ARM_STD_BMAP: 252 + val = READ_ONCE(smccc_feat->std_bmap); 253 + break; 317 254 default: 318 255 return -ENOENT; 319 256 } ··· 325 256 return -EFAULT; 326 257 327 258 return 0; 259 + } 260 + 261 + static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 262 + { 263 + int ret = 0; 264 + struct kvm *kvm = vcpu->kvm; 265 + struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 266 + unsigned long *fw_reg_bmap, fw_reg_features; 267 + 268 + switch (reg_id) { 269 + case KVM_REG_ARM_STD_BMAP: 270 + fw_reg_bmap = &smccc_feat->std_bmap; 271 + fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 272 + break; 273 + default: 274 + return -ENOENT; 275 + } 276 + 277 + /* Check for unsupported bit */ 278 + if (val & ~fw_reg_features) 279 + return -EINVAL; 280 + 281 + mutex_lock(&kvm->lock); 282 + 283 + if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) { 284 + ret = -EBUSY; 285 + goto out; 286 + } 287 + 288 + WRITE_ONCE(*fw_reg_bmap, val); 289 + out: 290 + mutex_unlock(&kvm->lock); 291 + return ret; 328 292 } 329 293 330 294 int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) ··· 438 336 return -EINVAL; 439 337 440 338 return 0; 339 + case KVM_REG_ARM_STD_BMAP: 340 + return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 441 341 default: 442 342 return -ENOENT; 443 343 }
+1
include/kvm/arm_hypercalls.h
··· 42 42 43 43 struct kvm_one_reg; 44 44 45 + void kvm_arm_init_hypercalls(struct kvm *kvm); 45 46 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); 46 47 int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); 47 48 int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);