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.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
[palacios.git] / palacios / src / palacios / vmm_cpuid.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_cpuid.h>
22 #include <palacios/vmm_lowlevel.h>
23 #include <palacios/vm_guest.h>
24
25
26 void v3_init_cpuid_map(struct v3_vm_info * vm) {
27     vm->cpuid_map.map.rb_node = NULL;
28 }
29
30
31 static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
32   struct rb_node ** p = &(vm->cpuid_map.map.rb_node);
33   struct rb_node * parent = NULL;
34   struct v3_cpuid_hook * tmp_hook = NULL;
35
36   while (*p) {
37     parent = *p;
38     tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node);
39
40     if (hook->cpuid < tmp_hook->cpuid) {
41       p = &(*p)->rb_left;
42     } else if (hook->cpuid > tmp_hook->cpuid) {
43       p = &(*p)->rb_right;
44     } else {
45       return tmp_hook;
46     }
47   }
48   rb_link_node(&(hook->tree_node), parent, p);
49
50   return NULL;
51 }
52
53
54 static inline struct v3_cpuid_hook * insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
55   struct v3_cpuid_hook * ret;
56
57   if ((ret = __insert_cpuid_hook(vm, hook))) {
58     return ret;
59   }
60
61   v3_rb_insert_color(&(hook->tree_node), &(vm->cpuid_map.map));
62
63   return NULL;
64 }
65
66
67
68 static struct v3_cpuid_hook * get_cpuid_hook(struct v3_vm_info * vm, uint32_t cpuid) {
69   struct rb_node * n = vm->cpuid_map.map.rb_node;
70   struct v3_cpuid_hook * hook = NULL;
71
72   while (n) {
73     hook = rb_entry(n, struct v3_cpuid_hook, tree_node);
74     
75     if (cpuid < hook->cpuid) {
76       n = n->rb_left;
77     } else if (cpuid > hook->cpuid) {
78       n = n->rb_right;
79     } else {
80       return hook;
81     }
82   }
83
84   return NULL;
85 }
86
87
88 int v3_unhook_cpuid(struct v3_vm_info * vm, uint32_t cpuid) {
89     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
90
91     if (hook == NULL) {
92         PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid);
93         return -1;
94     }
95
96     v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
97
98     V3_Free(hook);
99
100     return 0;
101 }
102
103 int v3_hook_cpuid(struct v3_vm_info * vm, uint32_t cpuid, 
104                   int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
105                                  uint32_t * eax, uint32_t * ebx, \
106                                  uint32_t * ecx, uint32_t * edx, \
107                                  void * private_data), 
108                   void * private_data) {
109     struct v3_cpuid_hook * hook = NULL;
110
111     if (hook_fn == NULL) {
112         PrintError("CPUID hook requested with null handler\n");
113         return -1;
114     }
115
116     hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
117     hook->cpuid = cpuid;
118     hook->private_data = private_data;
119     hook->hook_fn = hook_fn;
120
121     if (insert_cpuid_hook(vm, hook)) {
122         PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
123         V3_Free(hook);
124         return -1;
125     }
126
127     return 0;
128 }
129
130 int v3_handle_cpuid(struct guest_info * info) {
131     uint32_t cpuid = info->vm_regs.rax;
132     struct v3_cpuid_hook * hook = get_cpuid_hook(info->vm_info, cpuid);
133
134     //PrintDebug("CPUID called for 0x%x\n", cpuid);
135
136     if (hook == NULL) {
137         //PrintDebug("Calling passthrough handler\n");
138         // call the passthrough handler
139         v3_cpuid(cpuid, 
140                  (uint32_t *)&(info->vm_regs.rax), 
141                  (uint32_t *)&(info->vm_regs.rbx), 
142                  (uint32_t *)&(info->vm_regs.rcx), 
143                  (uint32_t *)&(info->vm_regs.rdx));
144     } else {
145         //      PrintDebug("Calling hook function\n");
146
147         if (hook->hook_fn(info, cpuid, 
148                           (uint32_t *)&(info->vm_regs.rax), 
149                           (uint32_t *)&(info->vm_regs.rbx), 
150                           (uint32_t *)&(info->vm_regs.rcx), 
151                           (uint32_t *)&(info->vm_regs.rdx), 
152                           hook->private_data) == -1) {
153             PrintError("Error in cpuid handler for 0x%x\n", cpuid);
154             return -1;
155         }
156     }
157
158     //    PrintDebug("Cleaning up register contents\n");
159
160     info->vm_regs.rax &= 0x00000000ffffffffLL;
161     info->vm_regs.rbx &= 0x00000000ffffffffLL;
162     info->vm_regs.rcx &= 0x00000000ffffffffLL;
163     info->vm_regs.rdx &= 0x00000000ffffffffLL;
164
165     info->rip += 2;
166
167     return 0;
168 }