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.


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