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 ssh://palacios@newskysaw/home/palacios/palacios into devel
[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, void * priv_data) {
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     vm->host_priv_data = priv_data;
129
130     return vm;
131 }
132
133
134 static int start_core(void *p)
135 {
136     struct guest_info * info = (struct guest_info *)p;
137
138
139     PrintDebug("core %u: in start_core\n",info->cpu_id);
140     
141     // we assume here that the APs are in INIT mode
142     // and only the BSP is in REAL
143     // the per-architecture code will rely on this
144     // assumption
145
146
147     switch (v3_cpu_types[info->cpu_id]) {
148 #ifdef CONFIG_SVM
149         case V3_SVM_CPU:
150         case V3_SVM_REV3_CPU:
151             return v3_start_svm_guest(info);
152             break;
153 #endif
154 #if CONFIG_VMX
155         case V3_VMX_CPU:
156         case V3_VMX_EPT_CPU:
157             return v3_start_vmx_guest(info);
158             break;
159 #endif
160         default:
161             PrintError("Attempting to enter a guest on an invalid CPU\n");
162             return -1;
163     }
164     // should not happen
165     return 0;
166 }
167
168
169 static uint32_t get_next_core(unsigned int cpu_mask, uint32_t last_proc)
170 {
171     uint32_t proc_to_use;
172
173     PrintDebug("In get_next_core cpu_mask=0x%x last_proc=%u\n",cpu_mask,last_proc);
174
175     proc_to_use=(last_proc+1) % 32; // only 32 procs
176     // This will wrap around, and eventually we can use proc 0, 
177     // since that's clearly available
178     while (!((cpu_mask >> proc_to_use)&0x1)) {
179         proc_to_use=(proc_to_use+1)%32;
180     }
181     return proc_to_use;
182 }
183
184 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
185     uint32_t i;
186     uint32_t last_proc;
187     uint32_t proc_to_use;
188     char tname[16];
189
190     V3_Print("V3 --  Starting VM (%u cores)\n",vm->num_cores);
191
192     // We assume that we are running on CPU 0 of the underlying system
193     last_proc=0;
194
195     // We will fork off cores 1..n first, then boot core zero
196     
197     // for the AP, we need to create threads
198  
199     for (i = 1; i < vm->num_cores; i++) {
200         if (!os_hooks->start_thread_on_cpu) { 
201             PrintError("Host OS does not support start_thread_on_cpu - FAILING\n");
202             return -1;
203         }
204
205         proc_to_use=get_next_core(cpu_mask,last_proc);
206         last_proc=proc_to_use;
207
208         // vm->cores[i].cpu_id=i;
209         // vm->cores[i].physical_cpu_id=proc_to_use;
210
211         PrintDebug("Starting virtual core %u on logical core %u\n",i,proc_to_use);
212         
213         sprintf(tname,"core%u",i);
214
215         PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
216                    proc_to_use, start_core, &(vm->cores[i]), tname);
217
218         // TODO: actually manage these threads instead of just launching them
219         if (!(os_hooks->start_thread_on_cpu(proc_to_use,start_core,&(vm->cores[i]),tname))) { 
220             PrintError("Thread launch failed\n");
221             return -1;
222         }
223     }
224
225     // vm->cores[0].cpu_id=0;
226     // vm->cores[0].physical_cpu_id=0;
227
228     // Finally launch the BSP on core 0
229     sprintf(tname,"core%u",0);
230
231 #if CONFIG_LINUX
232     if (vm->num_cores==1) { 
233         start_core(&(vm->cores[0]));
234         return -1;
235     } else {
236         if (!os_hooks->start_thread_on_cpu(0,start_core,&(vm->cores[0]),tname)) { 
237             PrintError("Thread launch failed\n");
238             return -1;
239         }
240     }
241 #else
242     if (!os_hooks->start_thread_on_cpu(0,start_core,&(vm->cores[0]),tname)) { 
243         PrintError("Thread launch failed\n");
244         return -1;
245     }
246 #endif
247
248     return 0;
249
250 }
251
252
253 #ifdef __V3_32BIT__
254
255 v3_cpu_mode_t v3_get_host_cpu_mode() {
256     uint32_t cr4_val;
257     struct cr4_32 * cr4;
258
259     __asm__ (
260              "movl %%cr4, %0; "
261              : "=r"(cr4_val) 
262              );
263
264     
265     cr4 = (struct cr4_32 *)&(cr4_val);
266
267     if (cr4->pae == 1) {
268         return PROTECTED_PAE;
269     } else {
270         return PROTECTED;
271     }
272 }
273
274 #elif __V3_64BIT__
275
276 v3_cpu_mode_t v3_get_host_cpu_mode() {
277     return LONG;
278 }
279
280 #endif 
281
282
283 #define V3_Yield(addr)                                  \
284     do {                                                \
285         extern struct v3_os_hooks * os_hooks;           \
286         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
287             (os_hooks)->yield_cpu();                    \
288         }                                               \
289     } while (0)                                         \
290
291
292
293 void v3_yield_cond(struct guest_info * info) {
294     uint64_t cur_cycle;
295     cur_cycle = v3_get_host_time(&info->time_state);
296
297     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
298
299         /*
300           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
301           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
302         */
303         V3_Yield();
304         info->yield_start_cycle = v3_get_host_time(&info->time_state);
305     }
306 }
307
308
309 /* 
310  * unconditional cpu yield 
311  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
312  * Non guest context threads should call this function with a NULL argument
313  */
314 void v3_yield(struct guest_info * info) {
315     V3_Yield();
316
317     if (info) {
318         info->yield_start_cycle = v3_get_host_time(&info->time_state);
319     }
320 }
321
322
323
324
325 void v3_print_cond(const char * fmt, ...) {
326     if (v3_dbg_enable == 1) {
327         char buf[2048];
328         va_list ap;
329
330         va_start(ap, fmt);
331         vsnprintf(buf, 2048, fmt, ap);
332         va_end(ap);
333
334         V3_Print("%s", buf);
335     }    
336 }
337
338
339
340
341 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
342     extern struct v3_os_hooks * os_hooks;
343
344     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
345         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
346     }
347 }
348
349
350
351 unsigned int v3_get_cpu_id() {
352     extern struct v3_os_hooks * os_hooks;
353     unsigned int ret = (unsigned int)-1;
354
355     if ((os_hooks) && (os_hooks)->get_cpu) {
356         ret = os_hooks->get_cpu();
357     }
358
359     return ret;
360 }
361
362
363
364 int v3_vm_enter(struct guest_info * info) {
365     switch (v3_cpu_types[info->cpu_id]) {
366 #ifdef CONFIG_SVM
367         case V3_SVM_CPU:
368         case V3_SVM_REV3_CPU:
369             return v3_svm_enter(info);
370             break;
371 #endif
372 #if CONFIG_VMX
373         case V3_VMX_CPU:
374         case V3_VMX_EPT_CPU:
375             return v3_vmx_enter(info);
376             break;
377 #endif
378         default:
379             PrintError("Attemping to enter a guest on an invalid CPU\n");
380             return -1;
381     }
382 }