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 functionality for MONITOR and MWAIT instructions on SVM and VMX:
[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) 2011, Jack Lange <jacklange@cs.pitt.edu> 
11  * All rights reserved.
12  *
13  * Author: Jack Lange <jacklange@cs.pitt.edu>
14  *
15  * This is free software.  You are permitted to use,
16  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
17  */
18
19 #include <palacios/vmm.h>
20 #include <palacios/vmm_cpuid.h>
21 #include <palacios/vmm_lowlevel.h>
22 #include <palacios/vm_guest.h>
23
24 struct masked_cpuid {
25     uint32_t rax_mask;
26     uint32_t rbx_mask;
27     uint32_t rcx_mask;
28     uint32_t rdx_mask;
29
30     uint32_t rax;
31     uint32_t rbx;
32     uint32_t rcx;
33     uint32_t rdx;
34 };
35
36
37 void v3_init_cpuid_map(struct v3_vm_info * vm) {
38     vm->cpuid_map.map.rb_node = NULL;
39
40     // Setup default cpuid entries
41
42
43     // Disable XSAVE (cpuid 0x01, ECX bit 26)
44     v3_cpuid_add_fields(vm, 0x01, 0, 0, 0, 0, (1 << 26), 0, 0, 0);
45
46     // Disable MONITOR/MWAIT (cpuid 0x01, ECX bit 3)
47     v3_cpuid_add_fields(vm, 0x01, 0, 0, 0, 0, (1 << 3), 0, 0, 0);
48
49 }
50
51
52
53
54 int v3_deinit_cpuid_map(struct v3_vm_info * vm) {
55     struct rb_node * node = v3_rb_first(&(vm->cpuid_map.map));
56     struct v3_cpuid_hook * hook = NULL;
57     struct rb_node * tmp_node = NULL;
58     
59
60     while (node) {
61         hook = rb_entry(node, struct v3_cpuid_hook, tree_node);
62         tmp_node = node;
63         node = v3_rb_next(node);
64
65         v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
66         V3_Free(hook);
67         
68     }
69
70     return 0;
71 }
72
73
74 static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
75   struct rb_node ** p = &(vm->cpuid_map.map.rb_node);
76   struct rb_node * parent = NULL;
77   struct v3_cpuid_hook * tmp_hook = NULL;
78
79   while (*p) {
80     parent = *p;
81     tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node);
82
83     if (hook->cpuid < tmp_hook->cpuid) {
84       p = &(*p)->rb_left;
85     } else if (hook->cpuid > tmp_hook->cpuid) {
86       p = &(*p)->rb_right;
87     } else {
88       return tmp_hook;
89     }
90   }
91   rb_link_node(&(hook->tree_node), parent, p);
92
93   return NULL;
94 }
95
96
97 static inline struct v3_cpuid_hook * insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
98   struct v3_cpuid_hook * ret;
99
100   if ((ret = __insert_cpuid_hook(vm, hook))) {
101     return ret;
102   }
103
104   v3_rb_insert_color(&(hook->tree_node), &(vm->cpuid_map.map));
105
106   return NULL;
107 }
108
109
110
111 static struct v3_cpuid_hook * get_cpuid_hook(struct v3_vm_info * vm, uint32_t cpuid) {
112   struct rb_node * n = vm->cpuid_map.map.rb_node;
113   struct v3_cpuid_hook * hook = NULL;
114
115   while (n) {
116     hook = rb_entry(n, struct v3_cpuid_hook, tree_node);
117     
118     if (cpuid < hook->cpuid) {
119       n = n->rb_left;
120     } else if (cpuid > hook->cpuid) {
121       n = n->rb_right;
122     } else {
123       return hook;
124     }
125   }
126
127   return NULL;
128 }
129
130
131
132 static int mask_hook(struct guest_info * core, uint32_t cpuid, 
133               uint32_t * eax, uint32_t * ebx, 
134               uint32_t * ecx, uint32_t * edx,
135               void * priv_data) {
136     struct masked_cpuid * mask = (struct masked_cpuid *)priv_data;
137
138     v3_cpuid(cpuid, eax, ebx, ecx, edx);
139
140     *eax &= ~(mask->rax_mask);
141     *eax |= (mask->rax & mask->rax_mask);
142
143     *ebx &= ~(mask->rbx_mask);
144     *ebx |= (mask->rbx & mask->rbx_mask);
145
146     *ecx &= ~(mask->rcx_mask);
147     *ecx |= (mask->rcx & mask->rcx_mask);
148
149     *edx &= ~(mask->rdx_mask);
150     *edx |= (mask->rdx & mask->rdx_mask);
151
152     return 0;
153 }
154
155
156
157 /* This function allows you to reserve a set of bits in a given cpuid value 
158  * For each cpuid return register you specify which bits you want to reserve in the mask.
159  * The value of those bits is set in the reg param.
160  * The values of the reserved bits are  returned to the guest, when it reads the cpuid
161  */ 
162 int v3_cpuid_add_fields(struct v3_vm_info * vm, uint32_t cpuid, 
163                         uint32_t rax_mask, uint32_t rax,
164                         uint32_t rbx_mask, uint32_t rbx, 
165                         uint32_t rcx_mask, uint32_t rcx, 
166                         uint32_t rdx_mask, uint32_t rdx) {
167     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
168
169
170     if ((~rax_mask & rax) || (~rbx_mask & rbx) ||
171         (~rcx_mask & rcx) || (~rdx_mask & rdx)) {
172         PrintError("Invalid cpuid reg value (mask overrun)\n");
173         return -1;
174     }
175
176
177     if (hook == NULL) {
178         struct masked_cpuid * mask = V3_Malloc(sizeof(struct masked_cpuid));
179
180         if (!mask) {
181             PrintError("Unable to alocate space for cpu id mask\n");
182             return -1;
183         }
184
185         memset(mask, 0, sizeof(struct masked_cpuid));
186         
187         mask->rax_mask = rax_mask;
188         mask->rax = rax;
189         mask->rbx_mask = rbx_mask;
190         mask->rbx = rbx;
191         mask->rcx_mask = rcx_mask;
192         mask->rcx = rcx;
193         mask->rdx_mask = rdx_mask;
194         mask->rdx = rdx;
195
196         if (v3_hook_cpuid(vm, cpuid, mask_hook, mask) == -1) {
197             PrintError("Error hooking cpuid %d\n", cpuid);
198             V3_Free(mask);
199             return -1;
200         }
201     } else {
202         struct masked_cpuid * mask = NULL;
203         uint32_t tmp_val = 0;
204
205         if (hook->hook_fn != mask_hook) {
206             PrintError("trying to add fields to a fully hooked cpuid (%d)\n", cpuid);
207             return -1;
208         }
209         
210         mask = (struct masked_cpuid *)(hook->private_data);
211
212         if ((mask->rax_mask & rax_mask) ||
213             (mask->rbx_mask & rbx_mask) || 
214             (mask->rcx_mask & rcx_mask) || 
215             (mask->rdx_mask & rdx_mask)) {
216             PrintError("Trying to add fields that have already been masked\n");
217             return -1;
218         }
219
220         mask->rax_mask |= rax_mask;
221         mask->rbx_mask |= rbx_mask;
222         mask->rcx_mask |= rcx_mask;
223         mask->rdx_mask |= rdx_mask;
224         
225         mask->rax |= rax;
226         tmp_val = (~rax_mask | rax);
227         mask->rax &= tmp_val;
228
229         mask->rbx |= rbx;
230         tmp_val = (~rbx_mask | rbx);
231         mask->rbx &= tmp_val;
232
233         mask->rcx |= rcx;
234         tmp_val = (~rcx_mask | rcx);
235         mask->rcx &= tmp_val;
236
237         mask->rdx |= rdx;
238         tmp_val = (~rdx_mask | rdx);
239         mask->rdx &= tmp_val;
240
241     }
242
243     return 0;
244 }
245
246 int v3_unhook_cpuid(struct v3_vm_info * vm, uint32_t cpuid) {
247     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
248
249     if (hook == NULL) {
250         PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid);
251         return -1;
252     }
253
254     v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
255
256     V3_Free(hook);
257
258     return 0;
259 }
260
261 int v3_hook_cpuid(struct v3_vm_info * vm, uint32_t cpuid, 
262                   int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
263                                  uint32_t * eax, uint32_t * ebx, \
264                                  uint32_t * ecx, uint32_t * edx, \
265                                  void * private_data), 
266                   void * private_data) {
267     struct v3_cpuid_hook * hook = NULL;
268
269     if (hook_fn == NULL) {
270         PrintError("CPUID hook requested with null handler\n");
271         return -1;
272     }
273
274     hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
275
276     if (!hook) {
277         PrintError("Cannot allocate memory to hook cpu id\n");
278         return -1;
279     }
280
281     hook->cpuid = cpuid;
282     hook->private_data = private_data;
283     hook->hook_fn = hook_fn;
284
285     if (insert_cpuid_hook(vm, hook)) {
286         PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
287         V3_Free(hook);
288         return -1;
289     }
290
291     return 0;
292 }
293
294 int v3_handle_cpuid(struct guest_info * info) {
295     uint32_t cpuid = info->vm_regs.rax;
296     struct v3_cpuid_hook * hook = get_cpuid_hook(info->vm_info, cpuid);
297
298     //PrintDebug("CPUID called for 0x%x\n", cpuid);
299
300     if (hook == NULL) {
301         //PrintDebug("Calling passthrough handler\n");
302         // call the passthrough handler
303         v3_cpuid(cpuid, 
304                  (uint32_t *)&(info->vm_regs.rax), 
305                  (uint32_t *)&(info->vm_regs.rbx), 
306                  (uint32_t *)&(info->vm_regs.rcx), 
307                  (uint32_t *)&(info->vm_regs.rdx));
308     } else {
309         //      PrintDebug("Calling hook function\n");
310
311         if (hook->hook_fn(info, cpuid, 
312                           (uint32_t *)&(info->vm_regs.rax), 
313                           (uint32_t *)&(info->vm_regs.rbx), 
314                           (uint32_t *)&(info->vm_regs.rcx), 
315                           (uint32_t *)&(info->vm_regs.rdx), 
316                           hook->private_data) == -1) {
317             PrintError("Error in cpuid handler for 0x%x\n", cpuid);
318             return -1;
319         }
320     }
321
322     //    PrintDebug("Cleaning up register contents\n");
323
324     info->vm_regs.rax &= 0x00000000ffffffffLL;
325     info->vm_regs.rbx &= 0x00000000ffffffffLL;
326     info->vm_regs.rcx &= 0x00000000ffffffffLL;
327     info->vm_regs.rdx &= 0x00000000ffffffffLL;
328
329     info->rip += 2;
330
331     return 0;
332 }
333
334
335
336
337