@@ -1174,10 +1174,20 @@ program_interrupt:
* again due to a host external interrupt.
*/
s = kvmppc_prepare_to_enter(vcpu);
- if (s <= 0)
+ switch (s) {
+ case -EINTR:
r = s;
- else {
- /* interrupts now hard-disabled */
+ break;
+ case 0:
+ /* Exit_reason is set, go to host */
+ r = RESUME_HOST;
+ break;
+ case 2:
+ /* Registers modified, reload then enter */
+ r = RESUME_GUEST_NV;
+ /* fall through */
+ case 1:
+ /* Interrupts now hard-disabled, enter guest */
kvmppc_fix_ee_before_entry();
}
@@ -1216,6 +1216,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (s <= 0)
r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
else {
+ if (s == 2)
+ r = RESUME_GUEST_NV;
+
/* interrupts now hard-disabled */
kvmppc_fix_ee_before_entry();
}
@@ -103,12 +103,14 @@ static bool kvmppc_needs_emulation(struct kvm_vcpu *vcpu)
*
* returns:
*
+ * == 2 if we're ready to go into guest state with NV registers restored
* == 1 if we're ready to go into guest state
* <= 0 if we need to go back to the host with return value
*/
int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
{
int r;
+ int enter_level = 1;
WARN_ON(irqs_disabled());
hard_irq_disable();
@@ -163,13 +165,15 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
r = kvmppc_emulate_any_instruction(vcpu);
if (r == EMULATE_DO_MMIO)
return 0;
+ if (r == EMULATE_DONE)
+ enter_level = 2;
hard_irq_disable();
continue;
}
kvm_guest_enter();
- return 1;
+ return enter_level;
}
/* return to host */
When we emulate instructions during our critical section emulation we may overwrite non-volatile registers that the looping code would need to load back in. Notify the callers of prepare_to_enter() when we emulated code, so that they can set enable NV restoration on their exit path. Signed-off-by: Alexander Graf <agraf@suse.de> --- arch/powerpc/kvm/book3s_pr.c | 16 +++++++++++++--- arch/powerpc/kvm/booke.c | 3 +++ arch/powerpc/kvm/powerpc.c | 6 +++++- 3 files changed, 21 insertions(+), 4 deletions(-)