From: Christoffer Dall <cd...@cs.columbia.edu>

When the guest executes a WFI instruction the operation is trapped to
KVM, which emulates the instruction in software. There is no correlation
between a guest executing a WFI instruction and actually putting the
hardware into a low-power mode, since a KVM guest is essentially a
process and the WFI instruction can be seen as 'sleep' call from this
process. Therefore, we flag the VCPU to be in wait_for_interrupts mode
and call the main KVM function kvm_vcpu_block() function. This function
will put the thread on a wait-queue and call schedule.

When an interrupt comes in through KVM_IRQ_LINE (see previous patch) we
signal the VCPU thread and unflag the VCPU to no longer wait for
interrupts. All calls to kvm_arch_vcpu_ioctl_run() result in a call to
kvm_vcpu_block() as long as the VCPU is in wfi-mode.

Signed-off-by: Christoffer Dall <c.d...@virtualopensystems.com>
---
 arch/arm/kvm/arm.c     |   15 ++++++++++++++-
 arch/arm/kvm/emulate.c |   12 ++++++++++++
 arch/arm/kvm/trace.h   |   16 ++++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index eedf171..e4b659b 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -291,9 +291,17 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
        return -EINVAL;
 }
 
+/**
+ * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled
+ * @v:         The VCPU pointer
+ *
+ * If the guest CPU is not waiting for interrupts (or waiting and
+ * an interrupt is pending) then it is by definition runnable.
+ */
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-       return 0;
+       return !!v->arch.irq_lines ||
+               !v->arch.wait_for_interrupts;
 }
 
 int kvm_arch_vcpu_in_guest_mode(struct kvm_vcpu *v)
@@ -479,6 +487,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
                        break;
                }
 
+               if (vcpu->arch.wait_for_interrupts)
+                       kvm_vcpu_block(vcpu);
+
                /*
                 * Enter the guest
                 */
@@ -551,6 +562,8 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm,
         * trigger a world-switch round on the running physical CPU to set the
         * virtual IRQ/FIQ fields in the HCR appropriately.
         */
+       if (irq_level->level)
+               vcpu->arch.wait_for_interrupts = 0;
        kvm_vcpu_kick(vcpu);
 
        return 0;
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 47aa04c..914b17f 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -433,8 +433,20 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
        return emulate_cp15(vcpu, &params);
 }
 
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a 
guest
+ * @vcpu:      the vcpu pointer
+ * @run:       the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+       trace_kvm_wfi(vcpu->arch.regs.pc);
+       if (!vcpu->arch.irq_lines)
+               vcpu->arch.wait_for_interrupts = 1;
        return 0;
 }
 
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
index bd3a6cc..fc68394 100644
--- a/arch/arm/kvm/trace.h
+++ b/arch/arm/kvm/trace.h
@@ -90,6 +90,22 @@ TRACE_EVENT(kvm_emulate_cp15_imp,
                        __entry->CRm, __entry->Op2)
 );
 
+TRACE_EVENT(kvm_wfi,
+       TP_PROTO(unsigned long vcpu_pc),
+       TP_ARGS(vcpu_pc),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  vcpu_pc         )
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_pc                = vcpu_pc;
+       ),
+
+       TP_printk("guest executed wfi at: 0x%08lx", __entry->vcpu_pc)
+);
+
+
 #endif /* _TRACE_KVM_H */
 
 #undef TRACE_INCLUDE_PATH

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to