VMM: Add a syscall to poke a guest pcore (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 8 Feb 2016 17:29:27 +0000 (12:29 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 11 Feb 2016 15:39:30 +0000 (10:39 -0500)
Posted IRQs in VMX are a lot like poking the guest pcore, so we'll just use
a syscall for it.

There's a bit of nastiness with error handling.  So far, it's a real pain
to find out if a posted IRQ landed on the VM and handling if it didn't.
(When the POKE IRQ lands and the core wasn't a VM, how do we know for
certain which VM we were supposed to interrupt, without doing something
painful?).

The general Akaros philosophy here is to post a bit in memory and poke
spuriously.  When it comes to notifying vcores, we set notif_pending, send
a (possibly spurious) __notify, and if we missed it, we'll see the
notif_pending the next time we __startcore.  Hopefully we can do something
similar with posted IRQs.

This also cleans up all of the vmctl hacks, none of which are needed
anymore.

Reinstall your kernel headers.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/vmm/intel/vmx.c
kern/arch/x86/vmm/vmm.c
kern/arch/x86/vmm/vmm.h
kern/drivers/dev/cons.c
kern/include/ros/bits/syscall.h
kern/src/syscall.c
tests/vmm/vmrunkernel.c

index 132bb16..7b3e00f 100644 (file)
@@ -1155,15 +1155,6 @@ static void vmx_step_instruction(void) {
                    vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
 }
 
-int vmx_interrupt_notify(struct vmctl *v)
-{
-       /* Assume we want to IPI guest pcore 0 (which vmctl controlled). */
-       int vm_core = current->vmm.guest_pcores[0]->cpu;
-
-       send_ipi(vm_core, I_POKE_CORE);
-       return 0;
-}
-
 /**
  * __vmx_enable - low-level enable of VMX mode on the current CPU
  * @vmxon_buf: an opaque buffer for use as the VMXON region
index 6d183aa..708d729 100644 (file)
@@ -61,17 +61,6 @@ void vmm_pcpu_init(void)
        printk("vmm_pcpu_init failed\n");
 }
 
-int vm_post_interrupt(struct vmctl *v)
-{
-       int vmx_interrupt_notify(struct vmctl *v);
-       if (current->vmm.amd) {
-               return -1;
-       } else {
-               return vmx_interrupt_notify(v);
-       }
-       return -1;
-}
-
 /* Initializes a process to run virtual machine contexts, returning the number
  * initialized, optionally setting errno */
 int vmm_struct_init(struct proc *p, unsigned int nr_guest_pcores,
@@ -140,6 +129,31 @@ void __vmm_struct_cleanup(struct proc *p)
        vmm->vmmcp = FALSE;
 }
 
+int vmm_poke_guest(struct proc *p, int guest_pcoreid)
+{
+       struct guest_pcore *gpc;
+       int pcoreid;
+
+       gpc = lookup_guest_pcore(p, guest_pcoreid);
+       if (!gpc) {
+               set_error(ENOENT, "Bad guest_pcoreid %d", guest_pcoreid);
+               return -1;
+       }
+       /* We're doing an unlocked peek; it could change immediately.  This is a
+        * best effort service. */
+       pcoreid = ACCESS_ONCE(gpc->cpu);
+       if (pcoreid == -1) {
+               /* So we know that we'll miss the poke for the posted IRQ.  We could
+                * return an error.  However, error handling for this case isn't
+                * particularly helpful (yet).  The absence of the error does not mean
+                * the IRQ was posted.  We'll still return 0, meaning "the user didn't
+                * mess up; we tried." */
+               return 0;
+       }
+       send_ipi(pcoreid, I_POKE_CORE);
+       return 0;
+}
+
 struct guest_pcore *lookup_guest_pcore(struct proc *p, int guest_pcoreid)
 {
        /* nr_guest_pcores is written once at setup and never changed */
index b4430dc..5a5a0fe 100644 (file)
@@ -61,8 +61,8 @@ void vmm_pcpu_init(void);
 int vmm_struct_init(struct proc *p, unsigned int nr_guest_pcores,
                     struct vmm_gpcore_init *gpcis, int flags);
 void __vmm_struct_cleanup(struct proc *p);
+int vmm_poke_guest(struct proc *p, int guest_pcoreid);
 
-int vm_post_interrupt(struct vmctl *v);
 int intel_vmx_start(int id);
 int intel_vmx_setup(int nvmcs);
 
index f1dc09d..72dc5e2 100644 (file)
@@ -605,7 +605,6 @@ enum {
        Qsysstat,
        Qtime,
        Quser,
-       Qvmctl,
        Qzero,
 };
 
@@ -639,7 +638,6 @@ static struct dirtab consdir[] = {
        {"sysstat", {Qsysstat}, 0, 0666},
        {"time", {Qtime}, NUMSIZE + 3 * VLNUMSIZE, 0664},
        {"user", {Quser}, 0, 0666},
-       {"vmctl", {Qvmctl}, 0, 0666},
        {"zero", {Qzero}, 0, 0444},
 };
 
@@ -1095,16 +1093,6 @@ static long conswrite(struct chan *c, void *va, long n, int64_t off)
                        error(EPERM, "Cannot write to config QID");
                        break;
 
-               case Qvmctl:
-                       memmove(&vmctl, a, sizeof(vmctl));
-                       if ((offset >> 12) ==1) {
-                               ret = vm_post_interrupt(&vmctl);
-                               n = ret;
-                               //printk("vm_interrupt_notify returns %d\n", ret);
-                       } else {
-                               error(EINVAL, "Bad vmctl command");
-                       }
-                       break;
                case Qsysctl:
                        //if (!iseve()) error(EPERM, ERROR_FIXME);
                        cb = parsecmd(a, n);
index 4612885..509041c 100644 (file)
@@ -46,6 +46,7 @@
 #define SYS_vc_entry                           35
 #define SYS_nanosleep                          36
 #define SYS_pop_ctx                                    37
+#define SYS_vmm_poke_guest                     38
 
 /* FS Syscalls */
 #define SYS_read                               100
index b5cd624..b9e99dc 100644 (file)
@@ -1438,6 +1438,11 @@ static int sys_vmm_setup(struct proc *p, unsigned int nr_guest_pcores,
        return vmm_struct_init(p, nr_guest_pcores, gpcis, flags);
 }
 
+static int sys_vmm_poke_guest(struct proc *p, int guest_pcoreid)
+{
+       return vmm_poke_guest(p, guest_pcoreid);
+}
+
 /* Pokes the ksched for the given resource for target_pid.  If the target pid
  * == 0, we just poke for the calling process.  The common case is poking for
  * self, so we avoid the lookup. 
@@ -2581,6 +2586,7 @@ const struct sys_table_entry syscall_table[] = {
 #endif
        [SYS_change_to_m] = {(syscall_t)sys_change_to_m, "change_to_m"},
        [SYS_vmm_setup] = {(syscall_t)sys_vmm_setup, "vmm_setup"},
+       [SYS_vmm_poke_guest] = {(syscall_t)sys_vmm_poke_guest, "vmm_poke_guest"},
        [SYS_poke_ksched] = {(syscall_t)sys_poke_ksched, "poke_ksched"},
        [SYS_abort_sysc] = {(syscall_t)sys_abort_sysc, "abort_sysc"},
        [SYS_abort_sysc_fd] = {(syscall_t)sys_abort_sysc_fd, "abort_sysc_fd"},
index f995605..f910568 100644 (file)
@@ -326,11 +326,9 @@ static inline int test_and_set_bit(int nr, volatile unsigned long *addr);
 
 void *timer_thread(void *arg)
 {
-       int fd = open("#cons/vmctl", O_RDWR), ret;
-
        while (1) {
                set_posted_interrupt(0xef);
-               pwrite(fd, &vmctl, sizeof(vmctl), 1<<12);
+               ros_syscall(SYS_vmm_poke_guest, 0, 0, 0, 0, 0, 0);
                uthread_usleep(1);
        }
 }
@@ -413,8 +411,6 @@ void *consin(void *arg)
        int timer_started = 0;
        pthread_t timerthread_struct;
 
-       int fd = open("#cons/vmctl", O_RDWR), ret;
-       
        if (debug) fprintf(stderr, "Spin on console being read, print num queues, halt\n");
 
        for(num = 0;! quit;num++) {
@@ -455,7 +451,7 @@ void *consin(void *arg)
                set_posted_interrupt(0xE5);
                virtio_mmio_set_vring_irq();
 
-               pwrite(fd, &vmctl, sizeof(vmctl), 1<<12);
+               ros_syscall(SYS_vmm_poke_guest, 0, 0, 0, 0, 0, 0);
                /*if (!timer_started && mcp) {
                        // Start up timer thread
                        if (pthread_create(&timerthread_struct, NULL, timer_thread, NULL)) {
@@ -574,7 +570,7 @@ int main(int argc, char **argv)
        int vmmflags = 0; // Disabled probably forever. VMM_VMCALL_PRINTF;
        uint64_t entry = 0x1200000, kerneladdress = 0x1200000;
        int nr_gpcs = 1;
-       int fd = open("#cons/vmctl", O_RDWR), ret;
+       int ret;
        void * xp;
        int kfd = -1;
        static char cmd[512];
@@ -620,10 +616,6 @@ int main(int argc, char **argv)
        ((uint32_t *)a_page)[0x30/4] = 0xDEADBEEF;
 
 
-       if (fd < 0) {
-               perror("#cons/sysctl");
-               exit(1);
-       }
        argc--,argv++;
        // switches ...
        // Sorry, I don't much like the gnu opt parsing code.