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.


added global module registry
[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
87 #ifdef CONFIG_SYMMOD
88     V3_init_symmod();
89 #endif
90
91 #ifdef CONFIG_INSTRUMENT_VMM
92     v3_init_instrumentation();
93 #endif
94
95     if ((hooks) && (hooks->call_on_cpu)) {
96
97         for (i = 0; i < num_cpus; i++) {
98
99             V3_Print("Initializing VMM extensions on cpu %d\n", i);
100             hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
101         }
102     }
103 }
104
105
106 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
107     return v3_cpu_types[cpu_id];
108 }
109
110
111 struct v3_vm_info * v3_create_vm(void * cfg) {
112     struct v3_vm_info * vm = v3_config_guest(cfg);
113
114     if (vm == NULL) {
115         PrintError("Could not configure guest\n");
116         return NULL;
117     }
118
119     return vm;
120 }
121
122
123 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
124     int i = 0;
125     V3_Print("V3 --  Starting VM\n");
126
127
128     for (i = 0; i < vm->num_cores; i++) {
129         struct guest_info * info = &(vm->cores[i]);
130
131         /* GRUESOM HACK... */
132         //      vm->cpu_id = v3_get_cpu_id();
133
134         switch (v3_cpu_types[info->cpu_id]) {
135 #ifdef CONFIG_SVM
136             case V3_SVM_CPU:
137             case V3_SVM_REV3_CPU:
138                 return v3_start_svm_guest(info);
139                 break;
140 #endif
141 #if CONFIG_VMX
142             case V3_VMX_CPU:
143             case V3_VMX_EPT_CPU:
144                 return v3_start_vmx_guest(info);
145                 break;
146 #endif
147             default:
148                 PrintError("Attemping to enter a guest on an invalid CPU\n");
149                 return -1;
150         }
151     }
152
153     return 0;
154 }
155
156
157 #ifdef __V3_32BIT__
158
159 v3_cpu_mode_t v3_get_host_cpu_mode() {
160     uint32_t cr4_val;
161     struct cr4_32 * cr4;
162
163     __asm__ (
164              "movl %%cr4, %0; "
165              : "=r"(cr4_val) 
166              );
167
168     
169     cr4 = (struct cr4_32 *)&(cr4_val);
170
171     if (cr4->pae == 1) {
172         return PROTECTED_PAE;
173     } else {
174         return PROTECTED;
175     }
176 }
177
178 #elif __V3_64BIT__
179
180 v3_cpu_mode_t v3_get_host_cpu_mode() {
181     return LONG;
182 }
183
184 #endif 
185
186
187 #define V3_Yield(addr)                                  \
188     do {                                                \
189         extern struct v3_os_hooks * os_hooks;           \
190         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
191             (os_hooks)->yield_cpu();                    \
192         }                                               \
193     } while (0)                                         \
194
195
196
197 void v3_yield_cond(struct guest_info * info) {
198     uint64_t cur_cycle;
199     rdtscll(cur_cycle);
200
201     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
202
203         /*
204           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
205           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
206         */
207         V3_Yield();
208         rdtscll(info->yield_start_cycle);
209     }
210 }
211
212
213 /* 
214  * unconditional cpu yield 
215  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
216  * Non guest context threads should call this function with a NULL argument
217  */
218 void v3_yield(struct guest_info * info) {
219     V3_Yield();
220
221     if (info) {
222         rdtscll(info->yield_start_cycle);
223     }
224 }
225
226
227
228
229 void v3_print_cond(const char * fmt, ...) {
230     if (v3_dbg_enable == 1) {
231         char buf[2048];
232         va_list ap;
233
234         va_start(ap, fmt);
235         vsnprintf(buf, 2048, fmt, ap);
236         va_end(ap);
237
238         V3_Print("%s", buf);
239     }    
240 }
241
242
243
244
245 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu) {
246     extern struct v3_os_hooks * os_hooks;
247
248     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
249         (os_hooks)->interrupt_cpu(vm, logical_cpu);
250     }
251 }
252
253
254
255 unsigned int v3_get_cpu_id() {
256     extern struct v3_os_hooks * os_hooks;
257     unsigned int ret = (unsigned int)-1;
258
259     if ((os_hooks) && (os_hooks)->get_cpu) {
260         ret = os_hooks->get_cpu();
261     }
262
263     return ret;
264 }
265
266
267
268 int v3_vm_enter(struct guest_info * info) {
269     switch (v3_cpu_types[info->cpu_id]) {
270 #ifdef CONFIG_SVM
271         case V3_SVM_CPU:
272         case V3_SVM_REV3_CPU:
273             return v3_svm_enter(info);
274             break;
275 #endif
276 #if CONFIG_VMX
277         case V3_VMX_CPU:
278         case V3_VMX_EPT_CPU:
279             return v3_vmx_enter(info);
280             break;
281 #endif
282         default:
283             PrintError("Attemping to enter a guest on an invalid CPU\n");
284             return -1;
285     }
286 }