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.


vnet fixes for compilation
[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 virtualization Extensions\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 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
133     int i = 0;
134     V3_Print("V3 --  Starting VM\n");
135
136
137     for (i = 0; i < vm->num_cores; i++) {
138         struct guest_info * info = &(vm->cores[i]);
139
140         /* GRUESOM HACK... */
141         //      vm->cpu_id = v3_get_cpu_id();
142
143         switch (v3_cpu_types[info->cpu_id]) {
144 #ifdef CONFIG_SVM
145             case V3_SVM_CPU:
146             case V3_SVM_REV3_CPU:
147                 return v3_start_svm_guest(info);
148                 break;
149 #endif
150 #if CONFIG_VMX
151             case V3_VMX_CPU:
152             case V3_VMX_EPT_CPU:
153                 return v3_start_vmx_guest(info);
154                 break;
155 #endif
156             default:
157                 PrintError("Attemping to enter a guest on an invalid CPU\n");
158                 return -1;
159         }
160     }
161
162     return 0;
163 }
164
165
166 #ifdef __V3_32BIT__
167
168 v3_cpu_mode_t v3_get_host_cpu_mode() {
169     uint32_t cr4_val;
170     struct cr4_32 * cr4;
171
172     __asm__ (
173              "movl %%cr4, %0; "
174              : "=r"(cr4_val) 
175              );
176
177     
178     cr4 = (struct cr4_32 *)&(cr4_val);
179
180     if (cr4->pae == 1) {
181         return PROTECTED_PAE;
182     } else {
183         return PROTECTED;
184     }
185 }
186
187 #elif __V3_64BIT__
188
189 v3_cpu_mode_t v3_get_host_cpu_mode() {
190     return LONG;
191 }
192
193 #endif 
194
195
196 #define V3_Yield(addr)                                  \
197     do {                                                \
198         extern struct v3_os_hooks * os_hooks;           \
199         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
200             (os_hooks)->yield_cpu();                    \
201         }                                               \
202     } while (0)                                         \
203
204
205
206 void v3_yield_cond(struct guest_info * info) {
207     uint64_t cur_cycle;
208     rdtscll(cur_cycle);
209
210     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
211
212         /*
213           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
214           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
215         */
216         V3_Yield();
217         rdtscll(info->yield_start_cycle);
218     }
219 }
220
221
222 /* 
223  * unconditional cpu yield 
224  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
225  * Non guest context threads should call this function with a NULL argument
226  */
227 void v3_yield(struct guest_info * info) {
228     V3_Yield();
229
230     if (info) {
231         rdtscll(info->yield_start_cycle);
232     }
233 }
234
235
236
237
238 void v3_print_cond(const char * fmt, ...) {
239     if (v3_dbg_enable == 1) {
240         char buf[2048];
241         va_list ap;
242
243         va_start(ap, fmt);
244         vsnprintf(buf, 2048, fmt, ap);
245         va_end(ap);
246
247         V3_Print("%s", buf);
248     }    
249 }
250
251
252
253
254 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu) {
255     extern struct v3_os_hooks * os_hooks;
256
257     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
258         (os_hooks)->interrupt_cpu(vm, logical_cpu);
259     }
260 }
261
262
263
264 unsigned int v3_get_cpu_id() {
265     extern struct v3_os_hooks * os_hooks;
266     unsigned int ret = (unsigned int)-1;
267
268     if ((os_hooks) && (os_hooks)->get_cpu) {
269         ret = os_hooks->get_cpu();
270     }
271
272     return ret;
273 }
274
275
276
277 int v3_vm_enter(struct guest_info * info) {
278     switch (v3_cpu_types[info->cpu_id]) {
279 #ifdef CONFIG_SVM
280         case V3_SVM_CPU:
281         case V3_SVM_REV3_CPU:
282             return v3_svm_enter(info);
283             break;
284 #endif
285 #if CONFIG_VMX
286         case V3_VMX_CPU:
287         case V3_VMX_EPT_CPU:
288             return v3_vmx_enter(info);
289             break;
290 #endif
291         default:
292             PrintError("Attemping to enter a guest on an invalid CPU\n");
293             return -1;
294     }
295 }