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.


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