x86: vmm: Use a separate vector for posted IRQs
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 23 Aug 2017 14:27:18 +0000 (10:27 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 25 Aug 2017 18:41:49 +0000 (14:41 -0400)
We were using I_POKE_CORE, but we actually need two separate IRQs.
Sometimes we actually want to kick the core into the kernel, but if we use
the posted IRQ vector and the core was running a guest, we wouldn't kick
the core.

I looked into this because of mpstat.  It'll send IPIs to force a cpu state
change / reevaluation.  But if the guest was spinning or halted, the POKE
would have no effect.

This also is just a little clearer in the code where we are trying to do a
posted IRQ and where we are just trying to kick the core.

Note that mpstat is a little racy.  We could make it better, but I'd like
to keep the ability to not interfere with the CG cores.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/riscv/trap.h
kern/arch/x86/process64.c
kern/arch/x86/trap.c
kern/arch/x86/trap.h
kern/arch/x86/trapentry64.S
kern/arch/x86/vmm/intel/vmx.c
kern/arch/x86/vmm/vmm.c
kern/src/schedule.c

index 5034b86..8a4102e 100644 (file)
@@ -20,6 +20,7 @@
 #warning "make sure this poke vector is okay"
 /* this is for an ipi that just wakes a core, but has no handler (for now) */
 #define I_POKE_CORE 254
+#define I_POKE_GUEST 253
 
 static inline bool in_kernel(struct hw_trapframe *hw_tf)
 {
index f065dc1..8cbe2e4 100644 (file)
@@ -134,7 +134,7 @@ static void __attribute__((noreturn)) proc_pop_vmtf(struct vm_trapframe *tf)
         * notification' bit should still be set, and we can resend the IPI.  This
         * will arrive after we vmenter, since IRQs are currently disabled. */
        if (test_bit(VMX_POSTED_OUTSTANDING_NOTIF, gpc->posted_irq_desc))
-               send_self_ipi(I_POKE_CORE);
+               send_self_ipi(I_POKE_GUEST);
        /* The first time a VMCS is started after being loaded, it must be launched.
         * Subsequent starts must be resumes.  Once the VMCS is cleared, we start
         * with a launch again.  Note this is the VMCS, not the GPC unload. */
index 9f168fa..acd5ce2 100644 (file)
@@ -985,10 +985,17 @@ bool handle_vmexit_msr(struct vm_trapframe *tf)
 bool handle_vmexit_extirq(struct vm_trapframe *tf)
 {
        struct hw_trapframe hw_tf;
+       uint32_t trap_nr;
 
        /* For now, we just handle external IRQs.  I think guest traps should go to
         * the guest, based on our vmctls */
        assert((tf->tf_intrinfo2 & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_EXT_INTR);
+       /* The POKE_HANDLER doesn't run for an ExtINT that triggers a vmexit */
+       trap_nr = tf->tf_intrinfo2 & INTR_INFO_VECTOR_MASK;
+       if (trap_nr == I_POKE_CORE) {
+               lapic_send_eoi(trap_nr);
+               return TRUE;
+       }
        /* TODO: Our IRQ handlers all expect TFs.  Let's fake one.  A bunch of
         * handlers (e.g. backtrace/perf) will probably be unhappy about a user TF
         * that is really a VM, so this all needs work. */
@@ -1009,7 +1016,7 @@ bool handle_vmexit_extirq(struct vm_trapframe *tf)
        hw_tf.tf_r13 = tf->tf_r13;
        hw_tf.tf_r14 = tf->tf_r14;
        hw_tf.tf_r15 = tf->tf_r15;
-       hw_tf.tf_trapno = tf->tf_intrinfo2 & INTR_INFO_VECTOR_MASK;
+       hw_tf.tf_trapno = trap_nr;
        hw_tf.tf_err = 0;
        hw_tf.tf_rip = tf->tf_rip;
        hw_tf.tf_cs = GD_UT;    /* faking a user TF, even though it's a VM */
index ab28349..e8820b6 100644 (file)
@@ -63,7 +63,8 @@
 #define I_SMP_CALL3                            (I_SMP_CALL0 + 3)
 #define I_SMP_CALL4                            (I_SMP_CALL0 + 4)
 #define I_SMP_CALL_LAST                        I_SMP_CALL4
-#define I_TESTING                              237     /* Testing IPI (used in testing.c) */
+#define I_TESTING                              236             /* Testing IPI (used in testing.c) */
+#define I_POKE_GUEST                   237
 #define I_POKE_CORE                            238
 #define I_KERNEL_MSG                   239
 
index e7aa859..c9a6d5b 100644 (file)
@@ -86,7 +86,7 @@
        .quad name;                                                     \
        .long num
 
-/* Only used in the kernel during SMP boot.  Send a LAPIC_EOI and iret. */
+/* Bare minimum IRQ handler: send a LAPIC_EOI and immediately iret. */
 #define POKE_HANDLER(name, num)                        \
        .text;                                                          \
        .globl name;                                            \
@@ -354,8 +354,8 @@ IRQ_HANDLER(IRQ200, 232)
 IRQ_HANDLER(IRQ201, 233)
 IRQ_HANDLER(IRQ202, 234)
 IRQ_HANDLER(IRQ203, 235)
-IRQ_HANDLER(IRQ204, 236)
-IRQ_HANDLER(IRQ205, I_TESTING)
+IRQ_HANDLER(IRQ204, I_TESTING)
+POKE_HANDLER(IRQ205, I_POKE_GUEST)
 POKE_HANDLER(IRQ206, I_POKE_CORE)
 IRQ_HANDLER(IRQ207, I_KERNEL_MSG)
 /* 240-255 are LAPIC vectors (0xf0-0xff), hightest priority class */
index 771dbb0..f656aeb 100644 (file)
@@ -916,7 +916,7 @@ static void vmx_setup_initial_guest_state(struct proc *p,
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);      /* 22.2.1 */
 
        /* Initialize posted interrupt notification vector */
-       vmcs_write16(POSTED_NOTIFICATION_VEC, I_POKE_CORE);
+       vmcs_write16(POSTED_NOTIFICATION_VEC, I_POKE_GUEST);
 
        /* Clear the EOI exit bitmap */
        vmcs_writel(EOI_EXIT_BITMAP0, 0);
index 2694800..a7b4d95 100644 (file)
@@ -148,7 +148,7 @@ int vmm_poke_guest(struct proc *p, int guest_pcoreid)
                 * mess up; we tried." */
                return 0;
        }
-       send_ipi(pcoreid, I_POKE_CORE);
+       send_ipi(pcoreid, I_POKE_GUEST);
        return 0;
 }
 
index 70102a1..7f4087d 100644 (file)
@@ -249,10 +249,6 @@ void __sched_scp_wakeup(struct proc *p)
        if (!management_core()) {
                /* TODO: pick a better core and only send if halted.
                 *
-                * FYI, a POKE on x86 might lose a rare race with halt code, since the
-                * poke handler does not abort halts.  if this happens, the next timer
-                * IRQ would wake up the core.
-                *
                 * ideally, we'd know if a specific mgmt core is sleeping and wake it
                 * up.  o/w, we could interrupt an already-running mgmt core that won't
                 * get to our new proc anytime soon.  also, by poking core 0, a