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.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
[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
29 #ifdef CONFIG_SVM
30 #include <palacios/svm.h>
31 #endif
32 #ifdef CONFIG_VMX
33 #include <palacios/vmx.h>
34 #endif
35
36 #ifdef CONFIG_VNET
37 #include <palacios/vmm_vnet.h>
38 #endif
39
40
41 v3_cpu_arch_t v3_cpu_types[CONFIG_MAX_CPUS];
42 struct v3_os_hooks * os_hooks = NULL;
43
44 int v3_dbg_enable = 0;
45
46
47
48 static void init_cpu(void * arg) {
49     uint32_t cpu_id = (uint32_t)(addr_t)arg;
50
51 #ifdef CONFIG_SVM
52     if (v3_is_svm_capable()) {
53         PrintDebug("Machine is SVM Capable\n");
54         v3_init_svm_cpu(cpu_id);
55         
56     } else 
57 #endif
58 #ifdef CONFIG_VMX
59     if (v3_is_vmx_capable()) {
60         PrintDebug("Machine is VMX Capable\n");
61         v3_init_vmx_cpu(cpu_id);
62
63     } else 
64 #endif
65     {
66        PrintError("CPU has no virtualizationExtensions\n");
67     }
68 }
69
70
71
72 void Init_V3(struct v3_os_hooks * hooks, int num_cpus) {
73     int i;
74
75     V3_Print("V3 Print statement to fix a Kitten page fault bug\n");
76
77     // Set global variables. 
78     os_hooks = hooks;
79
80     for (i = 0; i < CONFIG_MAX_CPUS; i++) {
81         v3_cpu_types[i] = V3_INVALID_CPU;
82     }
83
84     // Register all the possible device types
85     v3_init_devices();
86
87     // Register all shadow paging handlers
88     V3_init_shdw_paging();
89
90
91 #ifdef CONFIG_SYMMOD
92     V3_init_symmod();
93 #endif
94
95 #ifdef CONFIG_INSTRUMENT_VMM
96     v3_init_instrumentation();
97 #endif
98
99
100 #ifdef CONFIG_VNET
101     v3_init_vnet();
102 #endif
103
104     if ((hooks) && (hooks->call_on_cpu)) {
105
106         for (i = 0; i < num_cpus; i++) {
107
108             V3_Print("Initializing VMM extensions on cpu %d\n", i);
109             hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
110         }
111     }
112 }
113
114
115 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
116     return v3_cpu_types[cpu_id];
117 }
118
119
120 struct v3_vm_info * v3_create_vm(void * cfg) {
121     struct v3_vm_info * vm = v3_config_guest(cfg);
122
123     if (vm == NULL) {
124         PrintError("Could not configure guest\n");
125         return NULL;
126     }
127
128     return vm;
129 }
130
131
132 static int start_core(void *p)
133 {
134     struct guest_info * info = (struct guest_info*)p;
135
136
137     PrintDebug("core %u: in start_core\n",info->cpu_id);
138     
139     // we assume here that the APs are in INIT mode
140     // and only the BSP is in REAL
141     // the per-architecture code will rely on this
142     // assumption
143
144
145     switch (v3_cpu_types[info->cpu_id]) {
146 #ifdef CONFIG_SVM
147         case V3_SVM_CPU:
148         case V3_SVM_REV3_CPU:
149             return v3_start_svm_guest(info);
150             break;
151 #endif
152 #if CONFIG_VMX
153         case V3_VMX_CPU:
154         case V3_VMX_EPT_CPU:
155             return v3_start_vmx_guest(info);
156             break;
157 #endif
158         default:
159             PrintError("Attempting to enter a guest on an invalid CPU\n");
160             return -1;
161     }
162     // should not happen
163     return 0;
164 }
165
166
167 static uint32_t get_next_core(unsigned int cpu_mask, uint32_t last_proc)
168 {
169     uint32_t proc_to_use;
170
171     PrintDebug("In get_next_core cpu_mask=0x%x last_proc=%u\n",cpu_mask,last_proc);
172
173     proc_to_use=(last_proc+1) % 32; // only 32 procs
174     // This will wrap around, and eventually we can use proc 0, 
175     // since that's clearly available
176     while (!((cpu_mask >> proc_to_use)&0x1)) {
177         proc_to_use=(proc_to_use+1)%32;
178     }
179     return proc_to_use;
180 }
181
182 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
183     uint32_t i;
184     uint32_t last_proc;
185     uint32_t proc_to_use;
186     char tname[16];
187
188     V3_Print("V3 --  Starting VM (%u cores)\n",vm->num_cores);
189
190     // We assume that we are running on CPU 0 of the underlying system
191     last_proc=0;
192
193     // We will fork off cores 1..n first, then boot core zero
194     
195     // for the AP, we need to create threads
196  
197     for (i = 1; i < vm->num_cores; i++) {
198         if (!os_hooks->start_thread_on_cpu) { 
199             PrintError("Host OS does not support start_thread_on_cpu - FAILING\n");
200             return -1;
201         }
202
203         proc_to_use=get_next_core(cpu_mask,last_proc);
204         last_proc=proc_to_use;
205
206         // vm->cores[i].cpu_id=i;
207         // vm->cores[i].physical_cpu_id=proc_to_use;
208
209         PrintDebug("Starting virtual core %u on logical core %u\n",i,proc_to_use);
210         
211         sprintf(tname,"core%u",i);
212
213         PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
214                    proc_to_use, start_core, &(vm->cores[i]), tname);
215
216         // TODO: actually manage these threads instead of just launching them
217         if (!(os_hooks->start_thread_on_cpu(proc_to_use,start_core,&(vm->cores[i]),tname))) { 
218             PrintError("Thread launch failed\n");
219             return -1;
220         }
221     }
222
223     // vm->cores[0].cpu_id=0;
224     // vm->cores[0].physical_cpu_id=0;
225
226     // Finally launch the BSP on core 0
227     sprintf(tname,"core%u",0);
228
229 #if CONFIG_LINUX
230     if (vm->num_cores==1) { 
231         start_core(&(vm->cores[0]));
232         return -1;
233     } else {
234         if (!os_hooks->start_thread_on_cpu(0,start_core,&(vm->cores[0]),tname)) { 
235             PrintError("Thread launch failed\n");
236             return -1;
237         }
238     }
239 #else
240     if (!os_hooks->start_thread_on_cpu(0,start_core,&(vm->cores[0]),tname)) { 
241         PrintError("Thread launch failed\n");
242         return -1;
243     }
244 #endif
245
246     return 0;
247
248 }
249
250
251 #ifdef __V3_32BIT__
252
253 v3_cpu_mode_t v3_get_host_cpu_mode() {
254     uint32_t cr4_val;
255     struct cr4_32 * cr4;
256
257     __asm__ (
258              "movl %%cr4, %0; "
259              : "=r"(cr4_val) 
260              );
261
262     
263     cr4 = (struct cr4_32 *)&(cr4_val);
264
265     if (cr4->pae == 1) {
266         return PROTECTED_PAE;
267     } else {
268         return PROTECTED;
269     }
270 }
271
272 #elif __V3_64BIT__
273
274 v3_cpu_mode_t v3_get_host_cpu_mode() {
275     return LONG;
276 }
277
278 #endif 
279
280
281 #define V3_Yield(addr)                                  \
282     do {                                                \
283         extern struct v3_os_hooks * os_hooks;           \
284         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
285             (os_hooks)->yield_cpu();                    \
286         }                                               \
287     } while (0)                                         \
288
289
290
291 void v3_yield_cond(struct guest_info * info) {
292     uint64_t cur_cycle;
293     rdtscll(cur_cycle);
294
295     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
296
297         /*
298           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
299           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
300         */
301         V3_Yield();
302         rdtscll(info->yield_start_cycle);
303     }
304 }
305
306
307 /* 
308  * unconditional cpu yield 
309  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
310  * Non guest context threads should call this function with a NULL argument
311  */
312 void v3_yield(struct guest_info * info) {
313     V3_Yield();
314
315     if (info) {
316         rdtscll(info->yield_start_cycle);
317     }
318 }
319
320
321
322
323 void v3_print_cond(const char * fmt, ...) {
324     if (v3_dbg_enable == 1) {
325         char buf[2048];
326         va_list ap;
327
328         va_start(ap, fmt);
329         vsnprintf(buf, 2048, fmt, ap);
330         va_end(ap);
331
332         V3_Print("%s", buf);
333     }    
334 }
335
336
337
338
339 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
340     extern struct v3_os_hooks * os_hooks;
341
342     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
343         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
344     }
345 }
346
347
348
349 unsigned int v3_get_cpu_id() {
350     extern struct v3_os_hooks * os_hooks;
351     unsigned int ret = (unsigned int)-1;
352
353     if ((os_hooks) && (os_hooks)->get_cpu) {
354         ret = os_hooks->get_cpu();
355     }
356
357     return ret;
358 }
359
360
361
362 int v3_vm_enter(struct guest_info * info) {
363     switch (v3_cpu_types[info->cpu_id]) {
364 #ifdef CONFIG_SVM
365         case V3_SVM_CPU:
366         case V3_SVM_REV3_CPU:
367             return v3_svm_enter(info);
368             break;
369 #endif
370 #if CONFIG_VMX
371         case V3_VMX_CPU:
372         case V3_VMX_EPT_CPU:
373             return v3_vmx_enter(info);
374             break;
375 #endif
376         default:
377             PrintError("Attemping to enter a guest on an invalid CPU\n");
378             return -1;
379     }
380 }