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.


free up telemetry state and free backend state for the virtio devices
[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 #include <palacios/vm_guest.h>
24
25
26 void v3_init_cpuid_map(struct v3_vm_info * vm) {
27     vm->cpuid_map.map.rb_node = NULL;
28 }
29
30 int v3_deinit_cpuid_map(struct v3_vm_info * vm) {
31     struct rb_node * node = v3_rb_first(&(vm->cpuid_map.map));
32     struct v3_cpuid_hook * hook = NULL;
33     struct rb_node * tmp_node = NULL;
34     
35
36     while (node) {
37         hook = rb_entry(node, struct v3_cpuid_hook, tree_node);
38         tmp_node = node;
39         node = v3_rb_next(node);
40
41         v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
42         V3_Free(hook);
43         
44     }
45
46     return 0;
47 }
48
49
50 static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
51   struct rb_node ** p = &(vm->cpuid_map.map.rb_node);
52   struct rb_node * parent = NULL;
53   struct v3_cpuid_hook * tmp_hook = NULL;
54
55   while (*p) {
56     parent = *p;
57     tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node);
58
59     if (hook->cpuid < tmp_hook->cpuid) {
60       p = &(*p)->rb_left;
61     } else if (hook->cpuid > tmp_hook->cpuid) {
62       p = &(*p)->rb_right;
63     } else {
64       return tmp_hook;
65     }
66   }
67   rb_link_node(&(hook->tree_node), parent, p);
68
69   return NULL;
70 }
71
72
73 static inline struct v3_cpuid_hook * insert_cpuid_hook(struct v3_vm_info * vm, struct v3_cpuid_hook * hook) {
74   struct v3_cpuid_hook * ret;
75
76   if ((ret = __insert_cpuid_hook(vm, hook))) {
77     return ret;
78   }
79
80   v3_rb_insert_color(&(hook->tree_node), &(vm->cpuid_map.map));
81
82   return NULL;
83 }
84
85
86
87 static struct v3_cpuid_hook * get_cpuid_hook(struct v3_vm_info * vm, uint32_t cpuid) {
88   struct rb_node * n = vm->cpuid_map.map.rb_node;
89   struct v3_cpuid_hook * hook = NULL;
90
91   while (n) {
92     hook = rb_entry(n, struct v3_cpuid_hook, tree_node);
93     
94     if (cpuid < hook->cpuid) {
95       n = n->rb_left;
96     } else if (cpuid > hook->cpuid) {
97       n = n->rb_right;
98     } else {
99       return hook;
100     }
101   }
102
103   return NULL;
104 }
105
106
107 int v3_unhook_cpuid(struct v3_vm_info * vm, uint32_t cpuid) {
108     struct v3_cpuid_hook * hook = get_cpuid_hook(vm, cpuid);
109
110     if (hook == NULL) {
111         PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid);
112         return -1;
113     }
114
115     v3_rb_erase(&(hook->tree_node), &(vm->cpuid_map.map));
116
117     V3_Free(hook);
118
119     return 0;
120 }
121
122 int v3_hook_cpuid(struct v3_vm_info * vm, uint32_t cpuid, 
123                   int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \
124                                  uint32_t * eax, uint32_t * ebx, \
125                                  uint32_t * ecx, uint32_t * edx, \
126                                  void * private_data), 
127                   void * private_data) {
128     struct v3_cpuid_hook * hook = NULL;
129
130     if (hook_fn == NULL) {
131         PrintError("CPUID hook requested with null handler\n");
132         return -1;
133     }
134
135     hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook));
136     hook->cpuid = cpuid;
137     hook->private_data = private_data;
138     hook->hook_fn = hook_fn;
139
140     if (insert_cpuid_hook(vm, hook)) {
141         PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid);
142         V3_Free(hook);
143         return -1;
144     }
145
146     return 0;
147 }
148
149 int v3_handle_cpuid(struct guest_info * info) {
150     uint32_t cpuid = info->vm_regs.rax;
151     struct v3_cpuid_hook * hook = get_cpuid_hook(info->vm_info, cpuid);
152
153     //PrintDebug("CPUID called for 0x%x\n", cpuid);
154
155     if (hook == NULL) {
156         //PrintDebug("Calling passthrough handler\n");
157         // call the passthrough handler
158         v3_cpuid(cpuid, 
159                  (uint32_t *)&(info->vm_regs.rax), 
160                  (uint32_t *)&(info->vm_regs.rbx), 
161                  (uint32_t *)&(info->vm_regs.rcx), 
162                  (uint32_t *)&(info->vm_regs.rdx));
163     } else {
164         //      PrintDebug("Calling hook function\n");
165
166         if (hook->hook_fn(info, cpuid, 
167                           (uint32_t *)&(info->vm_regs.rax), 
168                           (uint32_t *)&(info->vm_regs.rbx), 
169                           (uint32_t *)&(info->vm_regs.rcx), 
170                           (uint32_t *)&(info->vm_regs.rdx), 
171                           hook->private_data) == -1) {
172             PrintError("Error in cpuid handler for 0x%x\n", cpuid);
173             return -1;
174         }
175     }
176
177     //    PrintDebug("Cleaning up register contents\n");
178
179     info->vm_regs.rax &= 0x00000000ffffffffLL;
180     info->vm_regs.rbx &= 0x00000000ffffffffLL;
181     info->vm_regs.rcx &= 0x00000000ffffffffLL;
182     info->vm_regs.rdx &= 0x00000000ffffffffLL;
183
184     info->rip += 2;
185
186     return 0;
187 }