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.


Avoid physical/virtual contiguity assumptions using new guest memory access functions
[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 init_custom(struct v3_vm_info *vm)
38 {
39   /*
40     CPUID 0
41       EAX = maxid supported  (1)
42       EBX = first 4 bytes of string
43       EDX = second 4 bytes of string
44       ECX = third 4 bytes of string
45
46     GenuineIntel
47     AuthenticAMD
48     VirtualV3VEE
49     EBX EDX ECX
50   */
51   uint32_t ebx, ecx, edx;
52
53   memcpy(&ebx,"Virt",4);
54   memcpy(&edx,"ualV",4);
55   memcpy(&ecx,"3VEE",4);
56
57
58   // In the Intel Space, we are a VirtualV3VEE 
59   // and our maximum cpuid is 0x1
60   v3_cpuid_add_fields(vm,0x0,             // ID 0 (Vendor)
61                       0xffffffff, 1,      // Max CPUID is one
62                       0xffffffff, ebx,
63                       0xffffffff, ecx,
64                       0xffffffff, edx);
65
66   // In the AMD Space, we are a Virtual V3VEE
67   // and our maximum cpuid is 0x80000001
68   // other than the maximum cpuid, this is identical to Intel 0x0
69   //
70   v3_cpuid_add_fields(vm,0x80000000,          // ID 8...0 (Vendor - AMD variant)
71                       0xffffffff, 0x80000001, // Max CPUID is one
72                       0xffffffff, ebx,
73                       0xffffffff, ecx,
74                       0xffffffff, edx);
75
76   /* CPUID 1, EAX - Family, Model, Stepping 
77      We are Family 16, Model 1, Stepping 1 (family 16 puts us in x86-64)
78      31:28 = reserved
79      27:20 = extended family (extfam)
80      19:16 = extended model (extmod)
81      15:12 = reserved
82      11:8  = base family (basfam)
83      7:4   = base model  (basmod)
84      3:0   = stepping
85
86      family = extfam+basefam, model=extmod:basmod
87      but we need to "top out" basefam first (0xf)
88
89      So we want: 0x00100f11
90
91      EBX is probably bogus here, since we need the apic ids
92      of the vcores, not the pcores
93   */
94
95   // in Intel Space, we are family 16, model 1, stepping 1
96   // and our other features are passthrough
97   v3_cpuid_add_fields(vm,0x1,
98                       0xffffffff, 0x00100f11,
99                       0x0, 0,
100                       0x0, 0,
101                       0x0, 0);
102
103   // In the AMD space, we are family 16, model 1, stepping 1
104   // with other features passthrough
105   // These other fields are *different* from Intel's 0x1, however
106   // in particular, long mode is here, even if it's an Intel...
107   v3_cpuid_add_fields(vm,0x80000001, // AMD variant
108                       0xffffffff, 0x00100f11,
109                       0x0, 0,
110                       0x0, 0,
111                       0x0, 0);
112       
113
114
115 void v3_init_cpuid_map(struct v3_vm_info * vm) {
116     vm->cpuid_map.map.rb_node = NULL;
117
118     // Setup default cpuid entries
119
120 #ifdef V3_CONFIG_CUSTOM_CPUID
121     init_custom(vm);
122 #endif
123
124     // Disable XSAVE (cpuid 0x01, ECX bit 26)
125     v3_cpuid_add_fields(vm, 0x01, 0, 0, 0, 0, (1 << 26), 0, 0, 0);
126
127     // Disable MONITOR/MWAIT (cpuid 0x01, ECX bit 3)
128     v3_cpuid_add_fields(vm, 0x01, 0, 0, 0, 0, (1 << 3), 0, 0, 0);
129
130
131     // disable MTRR
132     v3_cpuid_add_fields(vm, 0x00000001, 0, 0, 0, 0, 0, 0, (1 << 12), 0);
133     // disable PAT
134     v3_cpuid_add_fields(vm, 0x00000001, 0, 0, 0, 0, 0, 0, (1 << 16), 0);
135     // disable HTT
136     v3_cpuid_add_fields(vm, 0x00000001, 0, 0, 0, 0, 0, 0, (1 << 28), 0);
137
138     // disable X2APIC
139     v3_cpuid_add_fields(vm, 0x00000001, 0, 0, 0, 0, (1 << 21), 0, 0, 0);
140
141
142     // Demarcate machine as a VM
143     v3_cpuid_add_fields(vm, 0x00000001,
144                         0, 0,
145                         0, 0,
146                         0x80000000, 0x80000000,
147                         0, 0
148                         );
149
150
151     // disable ARAT
152     v3_cpuid_add_fields(vm, 0x00000006, (1 << 2), 0, 0, 0, 0, 0, 0, 0);
153
154 }
155
156
157
158
159 int v3_deinit_cpuid_map(struct v3_vm_info * vm) {
160     struct rb_node * node = v3_rb_first(&(vm->cpuid_map.map));
161     struct v3_cpuid_hook * hook = NULL;
162     struct rb_node * tmp_node = NULL;
163     
164
165     while (node) {
166         hook = rb_entry(node, struct v3_cpuid_hook, tree_node);
167         tmp_node = node;
168         node = v3_rb_next(node);
169
170         v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
171         V3_Free(hook);
172         
173     }
174
175     return 0;
176 }
177
178
179 static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
180   struct rb_node ** p = &(vm->cpuid_map.map.rb_node);
181   struct rb_node * parent = NULL;
182   struct v3_cpuid_hook * tmp_hook = NULL;
183
184   while (*p) {
185     parent = *p;
186     tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node);
187
188     if (hook->cpuid < tmp_hook->cpuid) {
189       p = &(*p)->rb_left;
190     } else if (hook->cpuid > tmp_hook->cpuid) {
191       p = &(*p)->rb_right;
192     } else {
193       return tmp_hook;
194     }
195   }
196   rb_link_node(&(hook->tree_node), parent, p);
197
198   return NULL;
199 }
200
201
202 static inline struct v3_cpuid_hook * insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
203   struct v3_cpuid_hook * ret;
204
205   if ((ret = __insert_cpuid_hook(vm, hook))) {
206     return ret;
207   }
208
209   v3_rb_insert_color(&(hook->tree_node), &(vm->cpuid_map.map));
210
211   return NULL;
212 }
213
214
215
216 static struct v3_cpuid_hook * get_cpuid_hook(struct v3_vm_info * vm, uint32_t cpuid) {
217   struct rb_node * n = vm->cpuid_map.map.rb_node;
218   struct v3_cpuid_hook * hook = NULL;
219
220   while (n) {
221     hook = rb_entry(n, struct v3_cpuid_hook, tree_node);
222     
223     if (cpuid < hook->cpuid) {
224       n = n->rb_left;
225     } else if (cpuid > hook->cpuid) {
226       n = n->rb_right;
227     } else {
228       return hook;
229     }
230   }
231
232   return NULL;
233 }
234
235
236
237 static int mask_hook(struct guest_info * core, uint32_t cpuid, 
238               uint32_t * eax, uint32_t * ebx, 
239               uint32_t * ecx, uint32_t * edx,
240               void * priv_data) {
241     struct masked_cpuid * mask = (struct masked_cpuid *)priv_data;
242
243     v3_cpuid(cpuid, eax, ebx, ecx, edx);
244
245     *eax &= ~(mask->rax_mask);
246     *eax |= (mask->rax & mask->rax_mask);
247
248     *ebx &= ~(mask->rbx_mask);
249     *ebx |= (mask->rbx & mask->rbx_mask);
250
251     *ecx &= ~(mask->rcx_mask);
252     *ecx |= (mask->rcx & mask->rcx_mask);
253
254     *edx &= ~(mask->rdx_mask);
255     *edx |= (mask->rdx & mask->rdx_mask);
256
257     return 0;
258 }
259
260
261
262 /* This function allows you to reserve a set of bits in a given cpuid value 
263  * For each cpuid return register you specify which bits you want to reserve in the mask.
264  * The value of those bits is set in the reg param.
265  * The values of the reserved bits are  returned to the guest, when it reads the cpuid
266  */ 
267 int v3_cpuid_add_fields(struct v3_vm_info * vm, uint32_t cpuid, 
268                         uint32_t rax_mask, uint32_t rax,
269                         uint32_t rbx_mask, uint32_t rbx, 
270                         uint32_t rcx_mask, uint32_t rcx, 
271                         uint32_t rdx_mask, uint32_t rdx) {
272     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
273
274
275     if ((~rax_mask & rax) || (~rbx_mask & rbx) ||
276         (~rcx_mask & rcx) || (~rdx_mask & rdx)) {
277         PrintError(vm, VCORE_NONE, "Invalid cpuid reg value (mask overrun)\n");
278         return -1;
279     }
280
281
282     if (hook == NULL) {
283         struct masked_cpuid * mask = V3_Malloc(sizeof(struct masked_cpuid));
284
285         if (!mask) {
286             PrintError(vm, VCORE_NONE, "Unable to alocate space for cpu id mask\n");
287             return -1;
288         }
289
290         memset(mask, 0, sizeof(struct masked_cpuid));
291         
292         mask->rax_mask = rax_mask;
293         mask->rax = rax;
294         mask->rbx_mask = rbx_mask;
295         mask->rbx = rbx;
296         mask->rcx_mask = rcx_mask;
297         mask->rcx = rcx;
298         mask->rdx_mask = rdx_mask;
299         mask->rdx = rdx;
300
301         if (v3_hook_cpuid(vm, cpuid, mask_hook, mask) == -1) {
302             PrintError(vm, VCORE_NONE, "Error hooking cpuid %d\n", cpuid);
303             V3_Free(mask);
304             return -1;
305         }
306     } else {
307         struct masked_cpuid * mask = NULL;
308         uint32_t tmp_val = 0;
309
310         if (hook->hook_fn != mask_hook) {
311             PrintError(vm, VCORE_NONE, "trying to add fields to a fully hooked cpuid (%d)\n", cpuid);
312             return -1;
313         }
314         
315         mask = (struct masked_cpuid *)(hook->private_data);
316
317         if ((mask->rax_mask & rax_mask) ||
318             (mask->rbx_mask & rbx_mask) || 
319             (mask->rcx_mask & rcx_mask) || 
320             (mask->rdx_mask & rdx_mask)) {
321             PrintError(vm, VCORE_NONE, "Trying to add fields that have already been masked\n");
322             return -1;
323         }
324
325         mask->rax_mask |= rax_mask;
326         mask->rbx_mask |= rbx_mask;
327         mask->rcx_mask |= rcx_mask;
328         mask->rdx_mask |= rdx_mask;
329         
330         mask->rax |= rax;
331         tmp_val = (~rax_mask | rax);
332         mask->rax &= tmp_val;
333
334         mask->rbx |= rbx;
335         tmp_val = (~rbx_mask | rbx);
336         mask->rbx &= tmp_val;
337
338         mask->rcx |= rcx;
339         tmp_val = (~rcx_mask | rcx);
340         mask->rcx &= tmp_val;
341
342         mask->rdx |= rdx;
343         tmp_val = (~rdx_mask | rdx);
344         mask->rdx &= tmp_val;
345
346     }
347
348     return 0;
349 }
350
351 int v3_unhook_cpuid(struct v3_vm_info * vm, uint32_t cpuid) {
352     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
353
354     if (hook == NULL) {
355         PrintError(vm, VCORE_NONE, "Could not find cpuid to unhook (0x%x)\n", cpuid);
356         return -1;
357     }
358
359     v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
360
361     V3_Free(hook);
362
363     return 0;
364 }
365
366 int v3_hook_cpuid(struct v3_vm_info * vm, uint32_t cpuid, 
367                   int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
368                                  uint32_t * eax, uint32_t * ebx, \
369                                  uint32_t * ecx, uint32_t * edx, \
370                                  void * private_data), 
371                   void * private_data) {
372     struct v3_cpuid_hook * hook = NULL;
373
374     if (hook_fn == NULL) {
375         PrintError(vm, VCORE_NONE, "CPUID hook requested with null handler\n");
376         return -1;
377     }
378
379     hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
380
381     if (!hook) {
382         PrintError(vm, VCORE_NONE, "Cannot allocate memory to hook cpu id\n");
383         return -1;
384     }
385
386     hook->cpuid = cpuid;
387     hook->private_data = private_data;
388     hook->hook_fn = hook_fn;
389
390     if (insert_cpuid_hook(vm, hook)) {
391         PrintError(vm, VCORE_NONE, "Could not hook cpuid 0x%x (already hooked)\n", cpuid);
392         V3_Free(hook);
393         return -1;
394     }
395
396     return 0;
397 }
398
399 int v3_handle_cpuid(struct guest_info * info) {
400     uint32_t cpuid = info->vm_regs.rax;
401     struct v3_cpuid_hook * hook = get_cpuid_hook(info->vm_info, cpuid);
402
403     //PrintDebug(info->vm_info, info, "CPUID called for 0x%x\n", cpuid);
404
405     if (hook == NULL) {
406         //PrintDebug(info->vm_info, info, "Calling passthrough handler\n");
407         // call the passthrough handler
408         v3_cpuid(cpuid, 
409                  (uint32_t *)&(info->vm_regs.rax), 
410                  (uint32_t *)&(info->vm_regs.rbx), 
411                  (uint32_t *)&(info->vm_regs.rcx), 
412                  (uint32_t *)&(info->vm_regs.rdx));
413     } else {
414         //      PrintDebug(info->vm_info, info, "Calling hook function\n");
415
416         if (hook->hook_fn(info, cpuid, 
417                           (uint32_t *)&(info->vm_regs.rax), 
418                           (uint32_t *)&(info->vm_regs.rbx), 
419                           (uint32_t *)&(info->vm_regs.rcx), 
420                           (uint32_t *)&(info->vm_regs.rdx), 
421                           hook->private_data) == -1) {
422             PrintError(info->vm_info, info, "Error in cpuid handler for 0x%x\n", cpuid);
423             return -1;
424         }
425     }
426
427     //    PrintDebug(info->vm_info, info, "Cleaning up register contents\n");
428
429     info->vm_regs.rax &= 0x00000000ffffffffLL;
430     info->vm_regs.rbx &= 0x00000000ffffffffLL;
431     info->vm_regs.rcx &= 0x00000000ffffffffLL;
432     info->vm_regs.rdx &= 0x00000000ffffffffLL;
433
434     info->rip += 2;
435
436     return 0;
437 }
438
439
440
441
442