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.


debugging tweaks and minor fixes
[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     // 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 #ifdef INSTRUMENT_VMM
88     v3_init_instrumentation();
89 #endif
90
91     if ((hooks) && (hooks->call_on_cpu)) {
92
93         for (i = 0; i < num_cpus; i++) {
94
95             V3_Print("Initializing VMM extensions on cpu %d\n", i);
96             hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
97         }
98     }
99 }
100
101
102 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
103     return v3_cpu_types[cpu_id];
104 }
105
106
107 struct guest_info * v3_create_vm(void * cfg) {
108     struct guest_info * info = allocate_guest();
109     
110     if (!info) {
111         PrintError("Could not allocate Guest\n");
112         return NULL;
113     }
114
115     if (v3_config_guest(info, cfg) == -1) {
116         PrintError("Could not configure guest\n");
117         return NULL;
118     }
119
120     return info;
121 }
122
123
124 int v3_start_vm(struct guest_info * info, unsigned int cpu_mask) {
125     
126     info->cpu_id = v3_get_cpu_id();
127
128     V3_Print("V3 --  Starting VM\n");
129
130     switch (v3_cpu_types[info->cpu_id]) {
131 #ifdef CONFIG_SVM
132         case V3_SVM_CPU:
133         case V3_SVM_REV3_CPU:
134             return v3_start_svm_guest(info);
135             break;
136 #endif
137 #if CONFIG_VMX
138         case V3_VMX_CPU:
139         case V3_VMX_EPT_CPU:
140             return v3_start_vmx_guest(info);
141             break;
142 #endif
143         default:
144             PrintError("Attemping to enter a guest on an invalid CPU\n");
145             return -1;
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->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 guest_info * info, 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(info, 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 }