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 device checkpoint hooks
[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         memset(mask, 0, sizeof(struct masked_cpuid));
177         
178         mask->rax_mask = rax_mask;
179         mask->rax = rax;
180         mask->rbx_mask = rbx_mask;
181         mask->rbx = rbx;
182         mask->rcx_mask = rcx_mask;
183         mask->rcx = rcx;
184         mask->rdx_mask = rdx_mask;
185         mask->rdx = rdx;
186
187         if (v3_hook_cpuid(vm, cpuid, mask_hook, mask) == -1) {
188             PrintError("Error hooking cpuid %d\n", cpuid);
189             return -1;
190         }
191     } else {
192         struct masked_cpuid * mask = NULL;
193         uint32_t tmp_val = 0;
194
195         if (hook->hook_fn != mask_hook) {
196             PrintError("trying to add fields to a fully hooked cpuid (%d)\n", cpuid);
197             return -1;
198         }
199         
200         mask = (struct masked_cpuid *)(hook->private_data);
201
202         if ((mask->rax_mask & rax_mask) ||
203             (mask->rbx_mask & rbx_mask) || 
204             (mask->rcx_mask & rcx_mask) || 
205             (mask->rdx_mask & rdx_mask)) {
206             PrintError("Trying to add fields that have already been masked\n");
207             return -1;
208         }
209
210         mask->rax_mask |= rax_mask;
211         mask->rbx_mask |= rbx_mask;
212         mask->rcx_mask |= rcx_mask;
213         mask->rdx_mask |= rdx_mask;
214         
215         mask->rax |= rax;
216         tmp_val = (~rax_mask | rax);
217         mask->rax &= tmp_val;
218
219         mask->rbx |= rbx;
220         tmp_val = (~rbx_mask | rbx);
221         mask->rbx &= tmp_val;
222
223         mask->rcx |= rcx;
224         tmp_val = (~rcx_mask | rcx);
225         mask->rcx &= tmp_val;
226
227         mask->rdx |= rdx;
228         tmp_val = (~rdx_mask | rdx);
229         mask->rdx &= tmp_val;
230
231     }
232
233     return 0;
234 }
235
236 int v3_unhook_cpuid(struct v3_vm_info * vm, uint32_t cpuid) {
237     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
238
239     if (hook == NULL) {
240         PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid);
241         return -1;
242     }
243
244     v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
245
246     V3_Free(hook);
247
248     return 0;
249 }
250
251 int v3_hook_cpuid(struct v3_vm_info * vm, uint32_t cpuid, 
252                   int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
253                                  uint32_t * eax, uint32_t * ebx, \
254                                  uint32_t * ecx, uint32_t * edx, \
255                                  void * private_data), 
256                   void * private_data) {
257     struct v3_cpuid_hook * hook = NULL;
258
259     if (hook_fn == NULL) {
260         PrintError("CPUID hook requested with null handler\n");
261         return -1;
262     }
263
264     hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
265     hook->cpuid = cpuid;
266     hook->private_data = private_data;
267     hook->hook_fn = hook_fn;
268
269     if (insert_cpuid_hook(vm, hook)) {
270         PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
271         V3_Free(hook);
272         return -1;
273     }
274
275     return 0;
276 }
277
278 int v3_handle_cpuid(struct guest_info * info) {
279     uint32_t cpuid = info->vm_regs.rax;
280     struct v3_cpuid_hook * hook = get_cpuid_hook(info->vm_info, cpuid);
281
282     //PrintDebug("CPUID called for 0x%x\n", cpuid);
283
284     if (hook == NULL) {
285         //PrintDebug("Calling passthrough handler\n");
286         // call the passthrough handler
287         v3_cpuid(cpuid, 
288                  (uint32_t *)&(info->vm_regs.rax), 
289                  (uint32_t *)&(info->vm_regs.rbx), 
290                  (uint32_t *)&(info->vm_regs.rcx), 
291                  (uint32_t *)&(info->vm_regs.rdx));
292     } else {
293         //      PrintDebug("Calling hook function\n");
294
295         if (hook->hook_fn(info, cpuid, 
296                           (uint32_t *)&(info->vm_regs.rax), 
297                           (uint32_t *)&(info->vm_regs.rbx), 
298                           (uint32_t *)&(info->vm_regs.rcx), 
299                           (uint32_t *)&(info->vm_regs.rdx), 
300                           hook->private_data) == -1) {
301             PrintError("Error in cpuid handler for 0x%x\n", cpuid);
302             return -1;
303         }
304     }
305
306     //    PrintDebug("Cleaning up register contents\n");
307
308     info->vm_regs.rax &= 0x00000000ffffffffLL;
309     info->vm_regs.rbx &= 0x00000000ffffffffLL;
310     info->vm_regs.rcx &= 0x00000000ffffffffLL;
311     info->vm_regs.rdx &= 0x00000000ffffffffLL;
312
313     info->rip += 2;
314
315     return 0;
316 }
317
318
319
320
321