vmm: CPUID level 0x0B handling
authorDan Cross <crossd@gmail.com>
Wed, 12 Apr 2017 19:40:16 +0000 (15:40 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 17 Apr 2017 19:59:17 +0000 (15:59 -0400)
TODO: Figure out EAX (really, RAX in our world) values at SMT level.

When we get CPUID level 0x0b, reflect to userspace.  We
fake some information about the SMP topology of the machine:
basically, no hyperthreading and $n$ cores in a single
package.

We'll probably have to hook this into the ACPI tables somehow
to get the full effect; in the meantime, this seems to work.

Change-Id: I9543066e74e592d381c11bcd76e7f9e0476c7cab
Signed-off-by: Dan Cross <crossd@gmail.com>
[removed WIP tag]
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/trap.c
user/vmm/vmexit.c

index aa73e6e..1958b29 100644 (file)
@@ -883,6 +883,9 @@ static bool handle_vmexit_cpuid(struct vm_trapframe *tf)
 {
        uint32_t eax, ebx, ecx, edx;
 
+       if (tf->tf_rax == 0x0B)
+               return FALSE;   // Handle in userspace.
+
        cpuid(tf->tf_rax, tf->tf_rcx, &eax, &ebx, &ecx, &edx);
        switch (tf->tf_rax) {
                case 0x01:
index ebb4e01..bf7a05b 100644 (file)
@@ -64,6 +64,43 @@ static void sleep_til_irq(struct guest_thread *gth)
        uth_mutex_unlock(gth->halt_mtx);
 }
 
+enum {
+               CPUID_0B_LEVEL_SMT = 0,
+               CPUID_0B_LEVEL_CORE
+};
+
+static bool handle_cpuid(struct guest_thread *gth)
+{
+       struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
+       struct virtual_machine *vm = gth_to_vm(gth);
+       uint32_t level = vm_tf->tf_rcx & 0x0F;
+
+       if (vm_tf->tf_rax != 0x0B)
+               return FALSE;
+
+       vm_tf->tf_rip += 2;
+       vm_tf->tf_rax = 0;
+       vm_tf->tf_rbx = 0;
+       vm_tf->tf_rcx = level;
+       vm_tf->tf_rdx = gth->gpc_id;
+       if (level == CPUID_0B_LEVEL_SMT) {
+               vm_tf->tf_rax = 0;
+               vm_tf->tf_rbx = 1;
+               vm_tf->tf_rcx |= ((level + 1) << 8);
+       }
+       if (level == CPUID_0B_LEVEL_CORE) {
+               uint32_t shift = LOG2_UP(vm->nr_gpcs);
+
+               if (shift > 0x1F)
+                       shift = 0x1F;
+               vm_tf->tf_rax = shift;
+               vm_tf->tf_rbx = vm->nr_gpcs;
+               vm_tf->tf_rcx |= ((level + 1) << 8);
+       }
+
+       return TRUE;
+}
+
 static bool handle_ept_fault(struct guest_thread *gth)
 {
        struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
@@ -283,6 +320,8 @@ bool handle_vmexit(struct guest_thread *gth)
        struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
 
        switch (vm_tf->tf_exit_reason) {
+       case EXIT_REASON_CPUID:
+               return handle_cpuid(gth);
        case EXIT_REASON_EPT_VIOLATION:
                return handle_ept_fault(gth);
        case EXIT_REASON_VMCALL: