VMM: SMP guest (XCC)
authorGan Shun <ganshun@gmail.com>
Fri, 3 Feb 2017 18:44:36 +0000 (10:44 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 7 Feb 2017 18:01:42 +0000 (13:01 -0500)
This commit allows us to boot SMP guest kernels. It requires that the
guest VM to start up AP cores using vmcall instead of the usual method.

Reinstall your kernel headers

Signed-off-by: Gan Shun <ganshun@gmail.com>
Change-Id: Ie37a77eb1fb553893fa4cf89e20fe4b2e4a18516
[made retval a bool]
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/trap.c
kern/include/ros/vmm.h
kern/kfs/vmimage_cmdline
tests/vmm/vmrunkernel.c
user/vmm/include/vmm/vmm.h
user/vmm/vmexit.c

index 78b165d..3e7e5b7 100644 (file)
@@ -1056,7 +1056,8 @@ static void vmexit_dispatch(struct vm_trapframe *tf)
         * do it for external IRQs - the irq_dispatch code will handle it. */
        switch (tf->tf_exit_reason) {
        case EXIT_REASON_VMCALL:
-               if (current->vmm.flags & VMM_VMCALL_PRINTF) {
+               if (current->vmm.flags & VMM_VMCALL_PRINTF &&
+                   tf->tf_rax == VMCALL_PRINTC) {
                        printk("%c", tf->tf_rdi);
                        tf->tf_rip += 3;
                        handled = TRUE;
index 9c74762..bf7bb8c 100644 (file)
@@ -10,4 +10,8 @@
 
 #define        VMM_VMCALL_PRINTF       0x1     /* Enable VMCALL output console hack */
 
+/* VMCALL FUNCTION NUMBERS */
+#define VMCALL_PRINTC          0x1
+#define VMCALL_SMPBOOT         0x2
+
 #define VMM_ALL_FLAGS  (VMM_VMCALL_PRINTF)
index 3b4c72b..1703786 100644 (file)
@@ -1,11 +1,11 @@
 earlyprintk=vmcall,keep
  console=hvc0
- maxcpus=1
  acpi.debug_layer=0x2
  acpi.debug_level=0xffffffff
  apic=debug
  noexec=off
  nohlt
+ noht
  lapic=notscdeadline
  lapictimerfreq=1000000
  clocksource=tsc
index d2fd4e7..c944099 100644 (file)
@@ -1101,6 +1101,7 @@ int main(int argc, char **argv)
        vm_tf->tf_rip = entry;
        vm_tf->tf_rsp = stack;
        vm_tf->tf_rsi = (uint64_t) bp;
+       vm->up_gpcs = 1;
        start_guest_thread(vm->gths[0]);
 
        uthread_sleep_forever();
index 65ddd4a..4f9e4ee 100644 (file)
@@ -26,6 +26,12 @@ enum {
 struct virtual_machine {
        struct guest_thread                     **gths;
        unsigned int                            nr_gpcs;
+       /* up_gpcs should not need synchronization. only the BSP should be making
+        * startup vmcalls. For security's sake we might still want to lock in the
+        * future. TODO(ganshun)
+        * up_gpcs refers to the number of guest pcores that have
+        * been started so far. */
+       unsigned int                            up_gpcs;
        struct vmm_gpcore_init          *gpcis;
        bool                                            vminit;
 
index 3e8700b..798e8b4 100644 (file)
@@ -121,22 +121,84 @@ static bool handle_ept_fault(struct guest_thread *gth)
        return TRUE;
 }
 
-static bool handle_vmcall(struct guest_thread *gth)
+static bool handle_vmcall_printc(struct guest_thread *gth)
 {
        struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
        uint8_t byte;
 
-       if (gth->vmcall)
-               return gth->vmcall(gth, vm_tf);
        byte = vm_tf->tf_rdi;
        printf("%c", byte);
        if (byte == '\n')
                printf("%c", '%');
        fflush(stdout);
-       vm_tf->tf_rip += 3;
        return TRUE;
 }
 
+static bool handle_vmcall_smpboot(struct guest_thread *gth)
+{
+       struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
+       struct vm_trapframe *vm_tf_ap;
+       struct virtual_machine *vm = gth_to_vm(gth);
+       int cur_pcores = vm->up_gpcs;
+
+       /* Check if we're guest pcore 0. Only the BSP is allowed to start APs. */
+       if (vm_tf->tf_guest_pcoreid != 0) {
+               fprintf(stderr,
+                       "Only guest pcore 0 is allowed to start APs. core was %ld\n",
+                       vm_tf->tf_guest_pcoreid);
+               return FALSE;
+       }
+
+       /* Check if we've reached the maximum, if yes, blow out. */
+       if (vm->nr_gpcs == cur_pcores) {
+               fprintf(stderr,
+                       "guest tried to start up too many cores. max was %ld, current up %ld\n",
+                       vm->nr_gpcs, cur_pcores);
+               return FALSE;
+       }
+
+       /* Start up secondary core. */
+       vm_tf_ap = gth_to_vmtf(vm->gths[cur_pcores]);
+       /* We use the BSP's CR3 for now. This should be fine because they
+        * change it later anyway. */
+       vm_tf_ap->tf_cr3 = vm_tf->tf_cr3;
+
+       /* Starting RIP is passed in via rdi. */
+       vm_tf_ap->tf_rip = vm_tf->tf_rdi;
+
+       /* Starting RSP is passed in via rsi. */
+       vm_tf_ap->tf_rsp = vm_tf->tf_rsi;
+
+       vm->up_gpcs++;
+
+       start_guest_thread(vm->gths[cur_pcores]);
+
+       return TRUE;
+}
+
+static bool handle_vmcall(struct guest_thread *gth)
+{
+       struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
+       bool retval = FALSE;
+
+       if (gth->vmcall)
+               return gth->vmcall(gth, vm_tf);
+
+       switch (vm_tf->tf_rax) {
+               case VMCALL_PRINTC:
+                       retval = handle_vmcall_printc(gth);
+                       break;
+               case VMCALL_SMPBOOT:
+                       retval = handle_vmcall_smpboot(gth);
+                       break;
+       }
+
+       if (retval)
+               vm_tf->tf_rip += 3;
+
+       return retval;
+}
+
 static bool handle_io(struct guest_thread *gth)
 {
        struct vm_trapframe *vm_tf = gth_to_vmtf(gth);