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.


6dc29eb55d4683134200f6aa36152ed83022d3fd
[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) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_cpuid.h>
22 #include <palacios/vmm_lowlevel.h>
23
24
25
26 void v3_init_cpuid_map(struct guest_info * info) {
27     info->cpuid_map.map.rb_node = NULL;
28 }
29
30
31 static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) {
32   struct rb_node ** p = &(info->cpuid_map.map.rb_node);
33   struct rb_node * parent = NULL;
34   struct v3_cpuid_hook * tmp_hook = NULL;
35
36   while (*p) {
37     parent = *p;
38     tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node);
39
40     if (hook->cpuid < tmp_hook->cpuid) {
41       p = &(*p)->rb_left;
42     } else if (hook->cpuid > tmp_hook->cpuid) {
43       p = &(*p)->rb_right;
44     } else {
45       return tmp_hook;
46     }
47   }
48   rb_link_node(&(hook->tree_node), parent, p);
49
50   return NULL;
51 }
52
53
54 static inline struct v3_cpuid_hook * insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) {
55   struct v3_cpuid_hook * ret;
56
57   if ((ret = __insert_cpuid_hook(info, hook))) {
58     return ret;
59   }
60
61   v3_rb_insert_color(&(hook->tree_node), &(info->cpuid_map.map));
62
63   return NULL;
64 }
65
66
67
68 static struct v3_cpuid_hook * get_cpuid_hook(struct guest_info * info, uint32_t cpuid) {
69   struct rb_node * n = info->cpuid_map.map.rb_node;
70   struct v3_cpuid_hook * hook = NULL;
71
72   while (n) {
73     hook = rb_entry(n, struct v3_cpuid_hook, tree_node);
74     
75     if (cpuid < hook->cpuid) {
76       n = n->rb_left;
77     } else if (cpuid > hook->cpuid) {
78       n = n->rb_right;
79     } else {
80       return hook;
81     }
82   }
83
84   return NULL;
85 }
86
87
88 int v3_unhook_cpuid(struct guest_info * info, uint32_t cpuid) {
89     struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid);
90
91     if (hook == NULL) {
92         PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid);
93         return -1;
94     }
95
96     v3_rb_erase(&(hook->tree_node), &(info->cpuid_map.map));
97
98     V3_Free(hook);
99
100     return 0;
101 }
102
103 int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid, 
104                   int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
105                                  uint32_t * eax, uint32_t * ebx, \
106                                  uint32_t * ecx, uint32_t * edx, \
107                                  void * private_data), 
108                   void * private_data) {
109     struct v3_cpuid_hook * hook = NULL;
110
111     if (hook_fn == NULL) {
112         PrintError("CPUID hook requested with null handler\n");
113         return -1;
114     }
115
116     hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
117     hook->cpuid = cpuid;
118     hook->private_data = private_data;
119     hook->hook_fn = hook_fn;
120
121     if (insert_cpuid_hook(info, hook)) {
122         PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
123         V3_Free(hook);
124         return -1;
125     }
126
127     return 0;
128 }
129
130 int v3_handle_cpuid(struct guest_info * info) {
131     uint32_t cpuid = info->vm_regs.rax;
132     struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid);
133
134     if (hook == NULL) {
135         // call the passthrough handler
136         v3_cpuid(cpuid, 
137                  (uint32_t *)&(info->vm_regs.rax), 
138                  (uint32_t *)&(info->vm_regs.rbx), 
139                  (uint32_t *)&(info->vm_regs.rcx), 
140                  (uint32_t *)&(info->vm_regs.rdx));
141     } else {
142         if (hook->hook_fn(info, cpuid, 
143                           (uint32_t *)&(info->vm_regs.rax), 
144                           (uint32_t *)&(info->vm_regs.rbx), 
145                           (uint32_t *)&(info->vm_regs.rcx), 
146                           (uint32_t *)&(info->vm_regs.rdx), 
147                           hook->private_data) == -1) {
148             PrintError("Error in cpuid handler for 0x%x\n", cpuid);
149             return -1;
150         }
151     }
152
153     info->vm_regs.rax &= 0x00000000ffffffffLL;
154     info->vm_regs.rbx &= 0x00000000ffffffffLL;
155     info->vm_regs.rcx &= 0x00000000ffffffffLL;
156     info->vm_regs.rdx &= 0x00000000ffffffffLL;
157
158     info->rip += 2;
159
160     return 0;
161 }