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