diff options
author | Paul Mackerras <paulus@ozlabs.org> | 2018-01-29 18:51:32 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@ozlabs.org> | 2018-01-31 21:35:33 -0500 |
commit | 36ee41d161c67a6fcf696d4817a0da31f778938c (patch) | |
tree | 790868f34e9c7ec17b6d53d17c61aa27d112586a | |
parent | 9b9b13a6d1537ddc4caccd6f1c41b78edbc08437 (diff) |
KVM: PPC: Book3S HV: Drop locks before reading guest memory
Running with CONFIG_DEBUG_ATOMIC_SLEEP reveals that HV KVM tries to
read guest memory, in order to emulate guest instructions, while
preempt is disabled and a vcore lock is held. This occurs in
kvmppc_handle_exit_hv(), called from post_guest_process(), when
emulating guest doorbell instructions on POWER9 systems, and also
when checking whether we have hit a hypervisor breakpoint.
Reading guest memory can cause a page fault and thus cause the
task to sleep, so we need to avoid reading guest memory while
holding a spinlock or when preempt is disabled.
To fix this, we move the preempt_enable() in kvmppc_run_core() to
before the loop that calls post_guest_process() for each vcore that
has just run, and we drop and re-take the vcore lock around the calls
to kvmppc_emulate_debug_inst() and kvmppc_emulate_doorbell_instr().
Dropping the lock is safe with respect to the iteration over the
runnable vcpus in post_guest_process(); for_each_runnable_thread
is actually safe to use locklessly. It is possible for a vcpu
to become runnable and add itself to the runnable_threads array
(code near the beginning of kvmppc_run_vcpu()) and then get included
in the iteration in post_guest_process despite the fact that it
has not just run. This is benign because vcpu->arch.trap and
vcpu->arch.ceded will be zero.
Cc: stable@vger.kernel.org # v4.13+
Fixes: 579006944e0d ("KVM: PPC: Book3S HV: Virtualize doorbell facility on POWER9")
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
-rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index e5f81fc108e0..aa6130b56b5e 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c | |||
@@ -1008,8 +1008,6 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu) | |||
1008 | struct kvm *kvm = vcpu->kvm; | 1008 | struct kvm *kvm = vcpu->kvm; |
1009 | struct kvm_vcpu *tvcpu; | 1009 | struct kvm_vcpu *tvcpu; |
1010 | 1010 | ||
1011 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | ||
1012 | return EMULATE_FAIL; | ||
1013 | if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst) != EMULATE_DONE) | 1011 | if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst) != EMULATE_DONE) |
1014 | return RESUME_GUEST; | 1012 | return RESUME_GUEST; |
1015 | if (get_op(inst) != 31) | 1013 | if (get_op(inst) != 31) |
@@ -1059,6 +1057,7 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu) | |||
1059 | return RESUME_GUEST; | 1057 | return RESUME_GUEST; |
1060 | } | 1058 | } |
1061 | 1059 | ||
1060 | /* Called with vcpu->arch.vcore->lock held */ | ||
1062 | static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, | 1061 | static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, |
1063 | struct task_struct *tsk) | 1062 | struct task_struct *tsk) |
1064 | { | 1063 | { |
@@ -1179,7 +1178,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
1179 | swab32(vcpu->arch.emul_inst) : | 1178 | swab32(vcpu->arch.emul_inst) : |
1180 | vcpu->arch.emul_inst; | 1179 | vcpu->arch.emul_inst; |
1181 | if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { | 1180 | if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { |
1181 | /* Need vcore unlocked to call kvmppc_get_last_inst */ | ||
1182 | spin_unlock(&vcpu->arch.vcore->lock); | ||
1182 | r = kvmppc_emulate_debug_inst(run, vcpu); | 1183 | r = kvmppc_emulate_debug_inst(run, vcpu); |
1184 | spin_lock(&vcpu->arch.vcore->lock); | ||
1183 | } else { | 1185 | } else { |
1184 | kvmppc_core_queue_program(vcpu, SRR1_PROGILL); | 1186 | kvmppc_core_queue_program(vcpu, SRR1_PROGILL); |
1185 | r = RESUME_GUEST; | 1187 | r = RESUME_GUEST; |
@@ -1194,8 +1196,13 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
1194 | */ | 1196 | */ |
1195 | case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: | 1197 | case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: |
1196 | r = EMULATE_FAIL; | 1198 | r = EMULATE_FAIL; |
1197 | if ((vcpu->arch.hfscr >> 56) == FSCR_MSGP_LG) | 1199 | if (((vcpu->arch.hfscr >> 56) == FSCR_MSGP_LG) && |
1200 | cpu_has_feature(CPU_FTR_ARCH_300)) { | ||
1201 | /* Need vcore unlocked to call kvmppc_get_last_inst */ | ||
1202 | spin_unlock(&vcpu->arch.vcore->lock); | ||
1198 | r = kvmppc_emulate_doorbell_instr(vcpu); | 1203 | r = kvmppc_emulate_doorbell_instr(vcpu); |
1204 | spin_lock(&vcpu->arch.vcore->lock); | ||
1205 | } | ||
1199 | if (r == EMULATE_FAIL) { | 1206 | if (r == EMULATE_FAIL) { |
1200 | kvmppc_core_queue_program(vcpu, SRR1_PROGILL); | 1207 | kvmppc_core_queue_program(vcpu, SRR1_PROGILL); |
1201 | r = RESUME_GUEST; | 1208 | r = RESUME_GUEST; |
@@ -2946,13 +2953,14 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) | |||
2946 | /* make sure updates to secondary vcpu structs are visible now */ | 2953 | /* make sure updates to secondary vcpu structs are visible now */ |
2947 | smp_mb(); | 2954 | smp_mb(); |
2948 | 2955 | ||
2956 | preempt_enable(); | ||
2957 | |||
2949 | for (sub = 0; sub < core_info.n_subcores; ++sub) { | 2958 | for (sub = 0; sub < core_info.n_subcores; ++sub) { |
2950 | pvc = core_info.vc[sub]; | 2959 | pvc = core_info.vc[sub]; |
2951 | post_guest_process(pvc, pvc == vc); | 2960 | post_guest_process(pvc, pvc == vc); |
2952 | } | 2961 | } |
2953 | 2962 | ||
2954 | spin_lock(&vc->lock); | 2963 | spin_lock(&vc->lock); |
2955 | preempt_enable(); | ||
2956 | 2964 | ||
2957 | out: | 2965 | out: |
2958 | vc->vcore_state = VCORE_INACTIVE; | 2966 | vc->vcore_state = VCORE_INACTIVE; |