Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added cpuid hooking
Jack Lange [Fri, 18 Sep 2009 22:34:52 +0000 (17:34 -0500)]
palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm_cpuid.h [new file with mode: 0644]
palacios/include/palacios/vmm_lowlevel.h
palacios/src/palacios/Makefile
palacios/src/palacios/svm.c
palacios/src/palacios/svm_handler.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_cpuid.c [new file with mode: 0644]
palacios/src/palacios/vmx.c
palacios/src/palacios/vmx_handler.c

index 749925d..86a1cc4 100644 (file)
@@ -33,6 +33,7 @@
 #include <palacios/vmm_host_events.h>
 #include <palacios/vmm_msr.h>
 #include <palacios/vmm_hypercall.h>
+#include <palacios/vmm_cpuid.h>
 #include <palacios/vmm_sym_iface.h>
 
 #ifdef CONFIG_TELEMETRY
@@ -154,6 +155,8 @@ struct guest_info {
 
     struct v3_msr_map msr_map;
 
+    struct v3_cpuid_map cpuid_map;
+
     // Symbiotic state
     struct v3_sym_state sym_state;
 
diff --git a/palacios/include/palacios/vmm_cpuid.h b/palacios/include/palacios/vmm_cpuid.h
new file mode 100644 (file)
index 0000000..a5f45ee
--- /dev/null
@@ -0,0 +1,72 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#ifndef __VMM_CPUID_H__
+#define __VMM_CPUID_H__
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_types.h>
+#include <palacios/vmm_rbtree.h>
+
+
+
+struct guest_info;
+
+void v3_init_cpuid_map(struct guest_info * info);
+
+
+struct v3_cpuid_hook {
+    uint32_t cpuid;
+    
+    int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
+                  uint32_t * eax, uint32_t * ebx, \
+                  uint32_t * ecx, uint32_t * edx, \
+                  void * private_data);
+    void * private_data;
+
+    struct rb_node tree_node;
+};
+
+
+
+struct v3_cpuid_map {
+    struct rb_root map;
+};
+
+void v3_print_cpuid_map(struct guest_info * info);
+
+int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid, 
+                 int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
+                                uint32_t * eax, uint32_t * ebx, \
+                                uint32_t * ecx, uint32_t * edx, \
+                                void * private_data), 
+                 void * private_data);
+
+int v3_unhook_cpuid(struct guest_info * info, uint32_t cpuid);
+
+int v3_handle_cpuid(struct guest_info * info);
+
+
+
+#endif
+
+#endif
index 71af105..8e85162 100644 (file)
 #define CPUID_EXT_FEATURE_IDS 0x80000001
 
 
-#ifdef __V3_32BIT__
 
-static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) {
+static void __inline__ v3_cpuid(uint32_t target, 
+                               uint32_t * eax, uint32_t * ebx, 
+                               uint32_t * ecx, uint32_t * edx) {
     __asm__ __volatile__ (
                          "cpuid\n\t"
                          : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
@@ -35,19 +36,6 @@ static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_
     return;
 }
 
-#elif __V3_64BIT__
-
-static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) {
-    __asm__ __volatile__ (
-                         "cpuid\n\t"
-                         : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
-                         : "0" (target), "2" (*ecx)
-                         );
-    return;
-}
-
-#endif
-
 
 static void __inline__ v3_set_msr(uint_t msr, uint_t high_byte, uint_t low_byte) {
     __asm__ __volatile__ (
index 0999c36..d01dd6a 100644 (file)
@@ -30,7 +30,8 @@ obj-y := \
        vmm_util.o \
        vmm_xed.o \
        vmm_binaries.o \
-       vmm_sym_iface.o
+       vmm_cpuid.o \
+       vmm_sym_iface.o \
 
 
 obj-$(CONFIG_SVM) +=    svm.o \
index 3c33292..7ba76eb 100644 (file)
@@ -90,6 +90,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
     ctrl_area->svm_instrs.CLGI = 1;
     ctrl_area->svm_instrs.SKINIT = 1;
     ctrl_area->svm_instrs.RDTSCP = 1;
+    ctrl_area->svm_instrs.CPUID = 1;
     ctrl_area->svm_instrs.ICEBP = 1;
     ctrl_area->svm_instrs.WBINVD = 1;
     ctrl_area->svm_instrs.MONITOR = 1;
@@ -176,13 +177,11 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
     ctrl_area->instrs.IOIO_PROT = 1;
 
 
-
     v3_init_svm_msr_map(vm_info);
     ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(vm_info->msr_map.arch_data);
     ctrl_area->instrs.MSR_PROT = 1;
 
 
-
     PrintDebug("Exiting on interrupts\n");
     ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
     ctrl_area->instrs.INTR = 1;
@@ -370,11 +369,11 @@ static int start_svm_guest(struct guest_info *info) {
 int v3_is_svm_capable() {
     // Dinda
     uint_t vm_cr_low = 0, vm_cr_high = 0;
-    addr_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
   
-    PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=%p\n", (void *)ecx);
+    PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
 
     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
       PrintDebug("SVM Not Available\n");
@@ -389,7 +388,7 @@ int v3_is_svm_capable() {
            
            v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
            
-           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=%p\n", (void *)edx);
+           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
            
            if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
                PrintDebug("SVM BIOS Disabled, not unlockable\n");
@@ -402,10 +401,10 @@ int v3_is_svm_capable() {
            PrintDebug("SVM is available and  enabled.\n");
 
            v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
-           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=%p\n", (void *)eax);
-           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=%p\n", (void *)ebx);
-           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=%p\n", (void *)ecx);
-           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=%p\n", (void *)edx);
+           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
+           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
+           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
+           PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
 
 
            if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
@@ -420,7 +419,7 @@ int v3_is_svm_capable() {
 }
 
 static int has_svm_nested_paging() {
-    addr_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
 
index 5736234..4c4aa2c 100644 (file)
@@ -31,6 +31,7 @@
 #include <palacios/vmm_emulator.h>
 #include <palacios/svm_msr.h>
 #include <palacios/vmm_hypercall.h>
+#include <palacios/vmm_cpuid.h>
 #include <palacios/vmm_direct_paging.h>
 
 #ifdef CONFIG_TELEMETRY
@@ -139,6 +140,7 @@ int v3_handle_svm_exit(struct guest_info * info) {
            break;
        }
        case VMEXIT_MSR:
+
            if (guest_ctrl->exit_info1 == 0) {
                if (v3_handle_msr_read(info) == -1) {
                    return -1;
@@ -153,6 +155,14 @@ int v3_handle_svm_exit(struct guest_info * info) {
            }
                
            break;
+
+       case VMEXIT_CPUID:
+           if (v3_handle_cpuid(info) == -1) {
+               PrintError("Error handling CPUID\n");
+               return -1;
+           }
+
+           break;
        case VMEXIT_CR0_WRITE: 
 #ifdef CONFIG_DEBUG_CTRL_REGS
            PrintDebug("CR0 Write\n");
index d4bd23a..72887c6 100644 (file)
@@ -27,6 +27,7 @@
 #include <palacios/vmm_hypercall.h>
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vmm_sym_iface.h>
+#include <palacios/vmm_cpuid.h>
 
 #ifdef CONFIG_SYMBIOTIC_SWAP
 #include <palacios/vmm_sym_swap.h>
@@ -94,6 +95,7 @@ int v3_pre_config_guest(struct guest_info * info, struct v3_vm_config * config_p
     v3_init_hypercall_map(info);
     v3_init_io_map(info);
     v3_init_msr_map(info);
+    v3_init_cpuid_map(info);
     v3_init_host_events(info);
 
     // Initialize the memory map
@@ -155,7 +157,7 @@ int v3_post_config_guest(struct guest_info * info, struct v3_vm_config * config_
        return -1;
     }
 
-    v3_print_io_map(info);
+    //    v3_print_io_map(info);
     v3_print_msr_map(info);
 
     info->run_state = VM_STOPPED;
diff --git a/palacios/src/palacios/vmm_cpuid.c b/palacios/src/palacios/vmm_cpuid.c
new file mode 100644 (file)
index 0000000..6dc29eb
--- /dev/null
@@ -0,0 +1,161 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_cpuid.h>
+#include <palacios/vmm_lowlevel.h>
+
+
+
+void v3_init_cpuid_map(struct guest_info * info) {
+    info->cpuid_map.map.rb_node = NULL;
+}
+
+
+static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) {
+  struct rb_node ** p = &(info->cpuid_map.map.rb_node);
+  struct rb_node * parent = NULL;
+  struct v3_cpuid_hook * tmp_hook = NULL;
+
+  while (*p) {
+    parent = *p;
+    tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node);
+
+    if (hook->cpuid < tmp_hook->cpuid) {
+      p = &(*p)->rb_left;
+    } else if (hook->cpuid > tmp_hook->cpuid) {
+      p = &(*p)->rb_right;
+    } else {
+      return tmp_hook;
+    }
+  }
+  rb_link_node(&(hook->tree_node), parent, p);
+
+  return NULL;
+}
+
+
+static inline struct v3_cpuid_hook * insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) {
+  struct v3_cpuid_hook * ret;
+
+  if ((ret = __insert_cpuid_hook(info, hook))) {
+    return ret;
+  }
+
+  v3_rb_insert_color(&(hook->tree_node), &(info->cpuid_map.map));
+
+  return NULL;
+}
+
+
+
+static struct v3_cpuid_hook * get_cpuid_hook(struct guest_info * info, uint32_t cpuid) {
+  struct rb_node * n = info->cpuid_map.map.rb_node;
+  struct v3_cpuid_hook * hook = NULL;
+
+  while (n) {
+    hook = rb_entry(n, struct v3_cpuid_hook, tree_node);
+    
+    if (cpuid < hook->cpuid) {
+      n = n->rb_left;
+    } else if (cpuid > hook->cpuid) {
+      n = n->rb_right;
+    } else {
+      return hook;
+    }
+  }
+
+  return NULL;
+}
+
+
+int v3_unhook_cpuid(struct guest_info * info, uint32_t cpuid) {
+    struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid);
+
+    if (hook == NULL) {
+       PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid);
+       return -1;
+    }
+
+    v3_rb_erase(&(hook->tree_node), &(info->cpuid_map.map));
+
+    V3_Free(hook);
+
+    return 0;
+}
+
+int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid, 
+                 int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
+                                uint32_t * eax, uint32_t * ebx, \
+                                uint32_t * ecx, uint32_t * edx, \
+                                void * private_data), 
+                 void * private_data) {
+    struct v3_cpuid_hook * hook = NULL;
+
+    if (hook_fn == NULL) {
+       PrintError("CPUID hook requested with null handler\n");
+       return -1;
+    }
+
+    hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
+    hook->cpuid = cpuid;
+    hook->private_data = private_data;
+    hook->hook_fn = hook_fn;
+
+    if (insert_cpuid_hook(info, hook)) {
+       PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
+       V3_Free(hook);
+       return -1;
+    }
+
+    return 0;
+}
+
+int v3_handle_cpuid(struct guest_info * info) {
+    uint32_t cpuid = info->vm_regs.rax;
+    struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid);
+
+    if (hook == NULL) {
+       // call the passthrough handler
+       v3_cpuid(cpuid, 
+                (uint32_t *)&(info->vm_regs.rax), 
+                (uint32_t *)&(info->vm_regs.rbx), 
+                (uint32_t *)&(info->vm_regs.rcx), 
+                (uint32_t *)&(info->vm_regs.rdx));
+    } else {
+       if (hook->hook_fn(info, cpuid, 
+                         (uint32_t *)&(info->vm_regs.rax), 
+                         (uint32_t *)&(info->vm_regs.rbx), 
+                         (uint32_t *)&(info->vm_regs.rcx), 
+                         (uint32_t *)&(info->vm_regs.rdx), 
+                         hook->private_data) == -1) {
+           PrintError("Error in cpuid handler for 0x%x\n", cpuid);
+           return -1;
+       }
+    }
+
+    info->vm_regs.rax &= 0x00000000ffffffffLL;
+    info->vm_regs.rbx &= 0x00000000ffffffffLL;
+    info->vm_regs.rcx &= 0x00000000ffffffffLL;
+    info->vm_regs.rdx &= 0x00000000ffffffffLL;
+
+    info->rip += 2;
+
+    return 0;
+}
index 7789b70..90ff060 100644 (file)
@@ -456,11 +456,11 @@ static int start_vmx_guest(struct guest_info* info) {
 
 int v3_is_vmx_capable() {
     v3_msr_t feature_msr;
-    addr_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
     v3_cpuid(0x1, &eax, &ebx, &ecx, &edx);
 
-    PrintDebug("ECX: %p\n", (void*)ecx);
+    PrintDebug("ECX: 0x%x\n", ecx);
 
     if (ecx & CPUID_1_ECX_VTXFLAG) {
         v3_get_msr(VMX_FEATURE_CONTROL_MSR, &(feature_msr.hi), &(feature_msr.lo));
index af76455..ee1824f 100644 (file)
@@ -23,6 +23,8 @@
 #include <palacios/vmcs.h>
 #include <palacios/vmx_lowlevel.h>
 #include <palacios/vmx_io.h>
+#include <palacios/vmm_cpuid.h>
+
 #include <palacios/vmx.h>
 #include <palacios/vmm_ctrl_regs.h>
 #include <palacios/vmm_lowlevel.h>
@@ -178,19 +180,13 @@ int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v
             }
 
             break;
-        case VMEXIT_CPUID: {
-           int instr_len;
-            uint32_t target = info->vm_regs.rax;
-
-            v3_cpuid(target, (addr_t *)&(info->vm_regs.rax), (addr_t *)&(info->vm_regs.rbx), 
-                    (addr_t *)&(info->vm_regs.rcx), (addr_t *)&(info->vm_regs.rdx));
-
-            check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
-
-            info->rip += instr_len;
+        case VMEXIT_CPUID:
+           if (v3_handle_cpuid(info) == -1) {
+               PrintError("Error Handling CPUID instruction\n");
+               return -1;
+           }
 
             break;
-        }
         case VMEXIT_RDMSR: 
             if (v3_handle_msr_read(info) == -1) {
                PrintError("Error handling MSR Read\n");