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.


enabled stopping a VM before the secondary cores have been initialized
[palacios.git] / palacios / src / palacios / vmm_cpuid.c
index 34040d8..ca7ef86 100644 (file)
@@ -7,11 +7,10 @@
  * 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> 
+ * Copyright (c) 2011, Jack Lange <jacklange@cs.pitt.edu> 
  * All rights reserved.
  *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ * Author: Jack Lange <jacklange@cs.pitt.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
 #include <palacios/vmm_lowlevel.h>
 #include <palacios/vm_guest.h>
 
+struct masked_cpuid {
+    uint32_t rax_mask;
+    uint32_t rbx_mask;
+    uint32_t rcx_mask;
+    uint32_t rdx_mask;
+
+    uint32_t rax;
+    uint32_t rbx;
+    uint32_t rcx;
+    uint32_t rdx;
+};
+
+
+void v3_init_cpuid_map(struct v3_vm_info * vm) {
+    vm->cpuid_map.map.rb_node = NULL;
+
+    // Setup default cpuid entries
+
+
+    // Disable XSAVE (cpuid 0x01, ECX bit 26)
+    v3_cpuid_add_fields(vm, 0x01, 0, 0, 0, 0, (1 << 26), 0, 0, 0);
 
-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);
+
+
+int v3_deinit_cpuid_map(struct v3_vm_info * vm) {
+    struct rb_node * node = v3_rb_first(&(vm->cpuid_map.map));
+    struct v3_cpuid_hook * hook = NULL;
+    struct rb_node * tmp_node = NULL;
+    
+
+    while (node) {
+       hook = rb_entry(node, struct v3_cpuid_hook, tree_node);
+       tmp_node = node;
+       node = v3_rb_next(node);
+
+       v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
+       V3_Free(hook);
+       
+    }
+
+    return 0;
+}
+
+
+static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
+  struct rb_node ** p = &(vm->cpuid_map.map.rb_node);
   struct rb_node * parent = NULL;
   struct v3_cpuid_hook * tmp_hook = NULL;
 
@@ -51,22 +91,22 @@ static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct guest_info * inf
 }
 
 
-static inline struct v3_cpuid_hook * insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) {
+static inline struct v3_cpuid_hook * insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
   struct v3_cpuid_hook * ret;
 
-  if ((ret = __insert_cpuid_hook(info, hook))) {
+  if ((ret = __insert_cpuid_hook(vm, hook))) {
     return ret;
   }
 
-  v3_rb_insert_color(&(hook->tree_node), &(info->cpuid_map.map));
+  v3_rb_insert_color(&(hook->tree_node), &(vm->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;
+static struct v3_cpuid_hook * get_cpuid_hook(struct v3_vm_info * vm, uint32_t cpuid) {
+  struct rb_node * n = vm->cpuid_map.map.rb_node;
   struct v3_cpuid_hook * hook = NULL;
 
   while (n) {
@@ -85,22 +125,130 @@ static struct v3_cpuid_hook * get_cpuid_hook(struct guest_info * info, uint32_t
 }
 
 
-int v3_unhook_cpuid(struct guest_info * info, uint32_t cpuid) {
-    struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid);
+
+static int mask_hook(struct guest_info * core, uint32_t cpuid, 
+             uint32_t * eax, uint32_t * ebx, 
+             uint32_t * ecx, uint32_t * edx,
+             void * priv_data) {
+    struct masked_cpuid * mask = (struct masked_cpuid *)priv_data;
+
+    v3_cpuid(cpuid, eax, ebx, ecx, edx);
+
+    *eax &= ~(mask->rax_mask);
+    *eax |= (mask->rax & mask->rax_mask);
+
+    *ebx &= ~(mask->rbx_mask);
+    *ebx |= (mask->rbx & mask->rbx_mask);
+
+    *ecx &= ~(mask->rcx_mask);
+    *ecx |= (mask->rcx & mask->rcx_mask);
+
+    *edx &= ~(mask->rdx_mask);
+    *edx |= (mask->rdx & mask->rdx_mask);
+
+    return 0;
+}
+
+
+
+/* This function allows you to reserve a set of bits in a given cpuid value 
+ * For each cpuid return register you specify which bits you want to reserve in the mask.
+ * The value of those bits is set in the reg param.
+ * The values of the reserved bits are  returned to the guest, when it reads the cpuid
+ */ 
+int v3_cpuid_add_fields(struct v3_vm_info * vm, uint32_t cpuid, 
+                       uint32_t rax_mask, uint32_t rax,
+                       uint32_t rbx_mask, uint32_t rbx, 
+                       uint32_t rcx_mask, uint32_t rcx, 
+                       uint32_t rdx_mask, uint32_t rdx) {
+    struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
+
+
+    if ((~rax_mask & rax) || (~rbx_mask & rbx) ||
+       (~rcx_mask & rcx) || (~rdx_mask & rdx)) {
+       PrintError("Invalid cpuid reg value (mask overrun)\n");
+       return -1;
+    }
+
+
+    if (hook == NULL) {
+       struct masked_cpuid * mask = V3_Malloc(sizeof(struct masked_cpuid));
+       memset(mask, 0, sizeof(struct masked_cpuid));
+       
+       mask->rax_mask = rax_mask;
+       mask->rax = rax;
+       mask->rbx_mask = rbx_mask;
+       mask->rbx = rbx;
+       mask->rcx_mask = rcx_mask;
+       mask->rcx = rcx;
+       mask->rdx_mask = rdx_mask;
+       mask->rdx = rdx;
+
+       if (v3_hook_cpuid(vm, cpuid, mask_hook, mask) == -1) {
+           PrintError("Error hooking cpuid %d\n", cpuid);
+           return -1;
+       }
+    } else {
+       struct masked_cpuid * mask = NULL;
+       uint32_t tmp_val = 0;
+
+       if (hook->hook_fn != mask_hook) {
+           PrintError("trying to add fields to a fully hooked cpuid (%d)\n", cpuid);
+           return -1;
+       }
+       
+       mask = (struct masked_cpuid *)(hook->private_data);
+
+       if ((mask->rax_mask & rax_mask) ||
+           (mask->rbx_mask & rbx_mask) || 
+           (mask->rcx_mask & rcx_mask) || 
+           (mask->rdx_mask & rdx_mask)) {
+           PrintError("Trying to add fields that have already been masked\n");
+           return -1;
+       }
+
+       mask->rax_mask |= rax_mask;
+       mask->rbx_mask |= rbx_mask;
+       mask->rcx_mask |= rcx_mask;
+       mask->rdx_mask |= rdx_mask;
+       
+       mask->rax |= rax;
+       tmp_val = (~rax_mask | rax);
+       mask->rax &= tmp_val;
+
+       mask->rbx |= rbx;
+       tmp_val = (~rbx_mask | rbx);
+       mask->rbx &= tmp_val;
+
+       mask->rcx |= rcx;
+       tmp_val = (~rcx_mask | rcx);
+       mask->rcx &= tmp_val;
+
+       mask->rdx |= rdx;
+       tmp_val = (~rdx_mask | rdx);
+       mask->rdx &= tmp_val;
+
+    }
+
+    return 0;
+}
+
+int v3_unhook_cpuid(struct v3_vm_info * vm, uint32_t cpuid) {
+    struct v3_cpuid_hook * hook = get_cpuid_hook(vm, 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_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
 
     V3_Free(hook);
 
     return 0;
 }
 
-int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid, 
+int v3_hook_cpuid(struct v3_vm_info * vm, 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, \
@@ -118,7 +266,7 @@ int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid,
     hook->private_data = private_data;
     hook->hook_fn = hook_fn;
 
-    if (insert_cpuid_hook(info, hook)) {
+    if (insert_cpuid_hook(vm, hook)) {
        PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
        V3_Free(hook);
        return -1;
@@ -129,7 +277,7 @@ int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid,
 
 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);
+    struct v3_cpuid_hook * hook = get_cpuid_hook(info->vm_info, cpuid);
 
     //PrintDebug("CPUID called for 0x%x\n", cpuid);
 
@@ -166,3 +314,8 @@ int v3_handle_cpuid(struct guest_info * info) {
 
     return 0;
 }
+
+
+
+
+