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.


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