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.


Add lock to vmm_queue
[palacios.git] / palacios / src / palacios / vmm.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_intr.h>
22 #include <palacios/vmm_config.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_instrument.h>
25 #include <palacios/vmm_ctrl_regs.h>
26 #include <palacios/vmm_lowlevel.h>
27 #include <palacios/vmm_sprintf.h>
28 #include <palacios/vmm_vnet.h>
29
30 #ifdef CONFIG_SVM
31 #include <palacios/svm.h>
32 #endif
33 #ifdef CONFIG_VMX
34 #include <palacios/vmx.h>
35 #endif
36
37
38 v3_cpu_arch_t v3_cpu_types[CONFIG_MAX_CPUS];
39 struct v3_os_hooks * os_hooks = NULL;
40
41 int v3_dbg_enable = 0;
42
43
44 static struct guest_info * allocate_guest() {
45     void * info = V3_Malloc(sizeof(struct guest_info));
46     memset(info, 0, sizeof(struct guest_info));
47     return info;
48 }
49
50
51 static void init_cpu(void * arg) {
52     uint32_t cpu_id = (uint32_t)(addr_t)arg;
53
54 #ifdef CONFIG_SVM
55     if (v3_is_svm_capable()) {
56         PrintDebug("Machine is SVM Capable\n");
57         v3_init_svm_cpu(cpu_id);
58         
59     } else 
60 #endif
61 #ifdef CONFIG_VMX
62     if (v3_is_vmx_capable()) {
63         PrintDebug("Machine is VMX Capable\n");
64         v3_init_vmx_cpu(cpu_id);
65
66     } else 
67 #endif
68     {
69        PrintError("CPU has no virtualization Extensions\n");
70     }
71 }
72
73
74
75 void Init_V3(struct v3_os_hooks * hooks, int num_cpus) {
76     int i;
77
78     V3_Print("V3 Print statement to fix a Kitten page fault bug\n");
79
80     // Set global variables. 
81     os_hooks = hooks;
82
83     for (i = 0; i < CONFIG_MAX_CPUS; i++) {
84         v3_cpu_types[i] = V3_INVALID_CPU;
85     }
86
87     // Register all the possible device types
88     v3_init_devices();
89
90 #ifdef INSTRUMENT_VMM
91     v3_init_instrumentation();
92 #endif
93
94     if ((hooks) && (hooks->call_on_cpu)) {
95
96         for (i = 0; i < num_cpus; i++) {
97
98             V3_Print("Initializing VMM extensions on cpu %d\n", i);
99             hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
100         }
101     }
102
103 #ifdef CONFIG_VNET
104     v3_init_vnet();
105 #endif
106 }
107
108
109 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
110     return v3_cpu_types[cpu_id];
111 }
112
113
114 struct guest_info * v3_create_vm(void * cfg) {
115     struct guest_info * info = allocate_guest();
116     
117     if (!info) {
118         PrintError("Could not allocate Guest\n");
119         return NULL;
120     }
121
122     if (v3_config_guest(info, cfg) == -1) {
123         PrintError("Could not configure guest\n");
124         return NULL;
125     }
126
127     return info;
128 }
129
130
131 int v3_start_vm(struct guest_info * info, unsigned int cpu_mask) {
132     
133     info->cpu_id = v3_get_cpu_id();
134
135     V3_Print("V3 --  Starting VM\n");
136
137     switch (v3_cpu_types[info->cpu_id]) {
138 #ifdef CONFIG_SVM
139         case V3_SVM_CPU:
140         case V3_SVM_REV3_CPU:
141             return v3_start_svm_guest(info);
142             break;
143 #endif
144 #if CONFIG_VMX
145         case V3_VMX_CPU:
146         case V3_VMX_EPT_CPU:
147             return v3_start_vmx_guest(info);
148             break;
149 #endif
150         default:
151             PrintError("Attemping to enter a guest on an invalid CPU\n");
152             return -1;
153     }
154
155     return 0;
156 }
157
158
159 #ifdef __V3_32BIT__
160
161 v3_cpu_mode_t v3_get_host_cpu_mode() {
162     uint32_t cr4_val;
163     struct cr4_32 * cr4;
164
165     __asm__ (
166              "movl %%cr4, %0; "
167              : "=r"(cr4_val) 
168              );
169
170     
171     cr4 = (struct cr4_32 *)&(cr4_val);
172
173     if (cr4->pae == 1) {
174         return PROTECTED_PAE;
175     } else {
176         return PROTECTED;
177     }
178 }
179
180 #elif __V3_64BIT__
181
182 v3_cpu_mode_t v3_get_host_cpu_mode() {
183     return LONG;
184 }
185
186 #endif 
187
188
189 #define V3_Yield(addr)                                  \
190     do {                                                \
191         extern struct v3_os_hooks * os_hooks;           \
192         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
193             (os_hooks)->yield_cpu();                    \
194         }                                               \
195     } while (0)                                         \
196
197
198
199 void v3_yield_cond(struct guest_info * info) {
200     uint64_t cur_cycle;
201     rdtscll(cur_cycle);
202
203     if (cur_cycle > (info->yield_start_cycle + info->yield_cycle_period)) {
204
205         /*
206           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
207           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
208         */
209         V3_Yield();
210         rdtscll(info->yield_start_cycle);
211     }
212 }
213
214
215 /* 
216  * unconditional cpu yield 
217  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
218  * Non guest context threads should call this function with a NULL argument
219  */
220 void v3_yield(struct guest_info * info) {
221     V3_Yield();
222
223     if (info) {
224         rdtscll(info->yield_start_cycle);
225     }
226 }
227
228
229
230
231 void v3_print_cond(const char * fmt, ...) {
232     if (v3_dbg_enable == 1) {
233         char buf[2048];
234         va_list ap;
235
236         va_start(ap, fmt);
237         vsnprintf(buf, 2048, fmt, ap);
238         va_end(ap);
239
240         V3_Print("%s", buf);
241     }    
242 }
243
244
245
246
247 void v3_interrupt_cpu(struct guest_info * info, int logical_cpu) {
248     extern struct v3_os_hooks * os_hooks;
249
250     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
251         (os_hooks)->interrupt_cpu(info, logical_cpu);
252     }
253 }
254
255
256
257 unsigned int v3_get_cpu_id() {
258     extern struct v3_os_hooks * os_hooks;
259     unsigned int ret = (unsigned int)-1;
260
261     if ((os_hooks) && (os_hooks)->get_cpu) {
262         ret = os_hooks->get_cpu();
263     }
264
265     return ret;
266 }
267
268
269
270 int v3_vm_enter(struct guest_info * info) {
271     switch (v3_cpu_types[info->cpu_id]) {
272 #ifdef CONFIG_SVM
273         case V3_SVM_CPU:
274         case V3_SVM_REV3_CPU:
275             return v3_svm_enter(info);
276             break;
277 #endif
278 #if CONFIG_VMX
279         case V3_VMX_CPU:
280         case V3_VMX_EPT_CPU:
281             return v3_vmx_enter(info);
282             break;
283 #endif
284         default:
285             PrintError("Attemping to enter a guest on an invalid CPU\n");
286             return -1;
287     }
288 }