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