It looks like we have tolerated creating mixed-width VMs since... forever. However, that was never the intention, and we'd rather not have to support that pointless complexity. Forbid such a setup by making sure all the vcpus have the same register width.
Unified · Split
| @@ -463,4 +463,9 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu) · 462 unmodified lines | ||
| 463 | 463 | vcpu->arch.flags |= KVM_ARM64_INCREMENT_PC; |
| 464 | 464 | } |
| 465 | 465 | |
| 466 | +static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature) | |
| 467 | +{ | |
| 468 | + return test_bit(feature, vcpu->arch.features); | |
| 469 | +} | |
| 470 | + | |
| 466 | 471 | #endif /* __ARM64_KVM_EMULATE_H__ */ |
| @@ -166,6 +166,25 @@ static int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) · 165 unmodified lines | ||
| 166 | 166 | return 0; |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | +static bool vcpu_allowed_register_width(struct kvm_vcpu *vcpu) | |
| 170 | +{ | |
| 171 | + struct kvm_vcpu *tmp; | |
| 172 | + bool is32bit; | |
| 173 | + int i; | |
| 174 | + | |
| 175 | + is32bit = vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT); | |
| 176 | + if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1) && is32bit) | |
| 177 | + return false; | |
| 178 | + | |
| 179 | + /* Check that the vcpus are either all 32bit or all 64bit */ | |
| 180 | + kvm_for_each_vcpu(i, tmp, vcpu->kvm) { | |
| 181 | + if (vcpu_has_feature(tmp, KVM_ARM_VCPU_EL1_32BIT) != is32bit) | |
| 182 | + return false; | |
| 183 | + } | |
| 184 | + | |
| 185 | + return true; | |
| 186 | +} | |
| 187 | + | |
| 169 | 188 | /** |
| 170 | 189 | * kvm_reset_vcpu - sets core registers and sys_regs to reset value |
| 171 | 190 | * @vcpu: The VCPU pointer |
| @@ -217,13 +236,14 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) · 45 unmodified lines | ||
| 217 | 236 | } |
| 218 | 237 | } |
| 219 | 238 | |
| 239 | + if (!vcpu_allowed_register_width(vcpu)) { | |
| 240 | + ret = -EINVAL; | |
| 241 | + goto out; | |
| 242 | + } | |
| 243 | + | |
| 220 | 244 | switch (vcpu->arch.target) { |
| 221 | 245 | default: |
| 222 | 246 | if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { |
| 223 | − if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1)) { | |
| 224 | − ret = -EINVAL; | |
| 225 | − goto out; | |
| 226 | − } | |
| 227 | 247 | pstate = VCPU_RESET_PSTATE_SVC; |
| 228 | 248 | } else { |
| 229 | 249 | pstate = VCPU_RESET_PSTATE_EL1; |