Skip to content

Commit e761a92

Browse files
christofferdall-armMarc Zyngier
authored andcommitted
KVM: arm/arm64: Reset the VCPU without preemption and vcpu state loaded
We have two ways to reset a vcpu: - either through VCPU_INIT - or through a PSCI_ON call The first one is easy to reason about. The second one is implemented in a more bizarre way, as it is the vcpu that handles PSCI_ON that resets the vcpu that is being powered-on. As we need to turn the logic around and have the target vcpu to reset itself, we must take some preliminary steps. Resetting the VCPU state modifies the system register state in memory, but this may interact with vcpu_load/vcpu_put if running with preemption disabled, which in turn may lead to corrupted system register state. Address this by disabling preemption and doing put/load if required around the reset logic. Reviewed-by: Andrew Jones <drjones@redhat.com> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 2292552 commit e761a92

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

arch/arm64/kvm/reset.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,33 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
105105
* This function finds the right table above and sets the registers on
106106
* the virtual CPU struct to their architecturally defined reset
107107
* values.
108+
*
109+
* Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT
110+
* ioctl or as part of handling a request issued by another VCPU in the PSCI
111+
* handling code. In the first case, the VCPU will not be loaded, and in the
112+
* second case the VCPU will be loaded. Because this function operates purely
113+
* on the memory-backed valus of system registers, we want to do a full put if
114+
* we were loaded (handling a request) and load the values back at the end of
115+
* the function. Otherwise we leave the state alone. In both cases, we
116+
* disable preemption around the vcpu reset as we would otherwise race with
117+
* preempt notifiers which also call put/load.
108118
*/
109119
int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
110120
{
111121
const struct kvm_regs *cpu_reset;
122+
int ret = -EINVAL;
123+
bool loaded;
124+
125+
preempt_disable();
126+
loaded = (vcpu->cpu != -1);
127+
if (loaded)
128+
kvm_arch_vcpu_put(vcpu);
112129

113130
switch (vcpu->arch.target) {
114131
default:
115132
if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
116133
if (!cpu_has_32bit_el1())
117-
return -EINVAL;
134+
goto out;
118135
cpu_reset = &default_regs_reset32;
119136
} else {
120137
cpu_reset = &default_regs_reset;
@@ -137,7 +154,12 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
137154
vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG;
138155

139156
/* Reset timer */
140-
return kvm_timer_vcpu_reset(vcpu);
157+
ret = kvm_timer_vcpu_reset(vcpu);
158+
out:
159+
if (loaded)
160+
kvm_arch_vcpu_load(vcpu, smp_processor_id());
161+
preempt_enable();
162+
return ret;
141163
}
142164

143165
void kvm_set_ipa_limit(void)

0 commit comments

Comments
 (0)