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.


90118eb297709e14b21c979ab6a184ff0257cb2f
[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
28 #ifdef CONFIG_SVM
29 #include <palacios/svm.h>
30 #endif
31 #ifdef CONFIG_VMX
32 #include <palacios/vmx.h>
33 #endif
34
35
36 v3_cpu_arch_t v3_cpu_types[CONFIG_MAX_CPUS];
37 struct v3_os_hooks * os_hooks = NULL;
38
39
40
41
42
43
44 static struct guest_info * allocate_guest() {
45     void * info = V3_Malloc(sizeof(struct guest_info));
46     memset(info, 0, sizeof(struct guest_info));
47     return info;
48 }
49
50
51 static void init_cpu(void * arg) {
52     uint32_t cpu_id = (uint32_t)(addr_t)arg;
53
54 #ifdef CONFIG_SVM
55     if (v3_is_svm_capable()) {
56         PrintDebug("Machine is SVM Capable\n");
57         v3_init_svm_cpu(cpu_id);
58         
59     } else 
60 #endif
61 #ifdef CONFIG_VMX
62     if (v3_is_vmx_capable()) {
63         PrintDebug("Machine is VMX Capable\n");
64         v3_init_vmx_cpu(cpu_id);
65
66     } else 
67 #endif
68     {
69        PrintError("CPU has no virtualization Extensions\n");
70     }
71 }
72
73
74
75
76
77 void Init_V3(struct v3_os_hooks * hooks, int num_cpus) {
78     int i;
79
80     // Set global variables. 
81     os_hooks = hooks;
82
83     for (i = 0; i < CONFIG_MAX_CPUS; i++) {
84         v3_cpu_types[i] = V3_INVALID_CPU;
85     }
86
87     // Register all the possible device types
88     v3_init_devices();
89
90 #ifdef INSTRUMENT_VMM
91     v3_init_instrumentation();
92 #endif
93
94     if ((hooks) && (hooks->call_on_cpu)) {
95
96         for (i = 0; i < num_cpus; i++) {
97
98             V3_Print("Initializing VMM extensions on cpu %d\n", i);
99             hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
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 int v3_start_vm(struct guest_info * info, unsigned int cpu_mask) {
126     
127     info->cpu_id = v3_get_cpu_id();
128
129     V3_Print("V3 --  Starting VM\n");
130
131     switch (v3_cpu_types[info->cpu_id]) {
132 #ifdef CONFIG_SVM
133         case V3_SVM_CPU:
134         case V3_SVM_REV3_CPU:
135             return v3_start_svm_guest(info);
136             break;
137 #endif
138 #if CONFIG_VMX
139         case V3_VMX_CPU:
140         case V3_VMX_EPT_CPU:
141             return v3_start_vmx_guest(info);
142             break;
143 #endif
144         default:
145             PrintError("Attemping to enter a guest on an invalid CPU\n");
146             return -1;
147     }
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 void v3_yield_cond(struct guest_info * info) {
194     uint64_t cur_cycle;
195     rdtscll(cur_cycle);
196
197     if (cur_cycle > (info->yield_start_cycle + info->yield_cycle_period)) {
198
199         /*
200           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
201           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
202         */
203         V3_Yield();
204         rdtscll(info->yield_start_cycle);
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 void v3_interrupt_cpu(struct guest_info * info, int logical_cpu) {
224     extern struct v3_os_hooks * os_hooks;
225
226     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
227         (os_hooks)->interrupt_cpu(info, logical_cpu);
228     }
229 }
230
231
232
233 unsigned int v3_get_cpu_id() {
234     extern struct v3_os_hooks * os_hooks;
235     unsigned int ret = (unsigned int)-1;
236
237     if ((os_hooks) && (os_hooks)->get_cpu) {
238         ret = os_hooks->get_cpu();
239     }
240
241     return ret;
242 }
243
244
245
246
247
248 int v3_vm_enter(struct guest_info * info) {
249     switch (v3_cpu_types[info->cpu_id]) {
250 #ifdef CONFIG_SVM
251         case V3_SVM_CPU:
252         case V3_SVM_REV3_CPU:
253             return v3_svm_enter(info);
254             break;
255 #endif
256 #if CONFIG_VMX && 0
257         case V3_VMX_CPU:
258         case V3_VMX_EPT_CPU:
259             return v3_vmx_enter(info);
260             break;
261 #endif
262         default:
263             PrintError("Attemping to enter a guest on an invalid CPU\n");
264             return -1;
265     }
266 }
267
268
269