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.


1571c4871fc966941ad869315659fd2173a5e2ba
[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 static struct guest_info * allocate_guest() {
42     void * info = V3_Malloc(sizeof(struct guest_info));
43     memset(info, 0, sizeof(struct guest_info));
44     return info;
45 }
46
47
48 struct vmm_init_arg {
49     int cpu_id;
50     struct v3_ctrl_ops * vmm_ops;
51 };
52
53 static void init_cpu(void * arg) {
54     struct vmm_init_arg * vmm_arg = (struct vmm_init_arg *)arg;
55     int cpu_id = vmm_arg->cpu_id;
56     struct v3_ctrl_ops * vmm_ops = vmm_arg->vmm_ops;
57
58 #ifdef CONFIG_SVM
59     if (v3_is_svm_capable()) {
60         PrintDebug("Machine is SVM Capable\n");
61         v3_init_svm_cpu(cpu_id);
62         
63         if (cpu_id == 0) {
64             v3_init_svm_hooks(vmm_ops);
65         }
66     } else 
67 #endif
68 #ifdef CONFIG_VMX
69     if (v3_is_vmx_capable()) {
70         PrintDebug("Machine is VMX Capable\n");
71         v3_init_vmx_cpu(cpu_id);
72
73         if (cpu_id == 0) {
74             v3_init_vmx_hooks(vmm_ops);
75         }       
76     } else 
77 #endif
78     {
79        PrintError("CPU has no virtualization Extensions\n");
80     }
81 }
82
83
84
85 void Init_V3(struct v3_os_hooks * hooks, struct v3_ctrl_ops * vmm_ops, int num_cpus) {
86     int i;
87     struct vmm_init_arg arg;
88     arg.vmm_ops = vmm_ops;    
89
90     // Set global variables. 
91     os_hooks = hooks;
92
93     for (i = 0; i < CONFIG_MAX_CPUS; i++) {
94         v3_cpu_types[i] = V3_INVALID_CPU;
95     }
96
97     // Register all the possible device types
98     v3_init_devices();
99
100
101 #ifdef INSTRUMENT_VMM
102     v3_init_instrumentation();
103 #endif
104
105     vmm_ops->allocate_guest = &allocate_guest;
106
107
108     if ((hooks) && (hooks->call_on_cpu)) {
109
110         for (i = 0; i < num_cpus; i++) {
111             arg.cpu_id = i;
112
113             V3_Print("Initializing VMM extensions on cpu %d\n", i);
114             hooks->call_on_cpu(i, &init_cpu, &arg);
115         }
116     }
117
118
119 }
120
121
122
123 #ifdef __V3_32BIT__
124
125 v3_cpu_mode_t v3_get_host_cpu_mode() {
126     uint32_t cr4_val;
127     struct cr4_32 * cr4;
128
129     __asm__ (
130              "movl %%cr4, %0; "
131              : "=r"(cr4_val) 
132              );
133
134     
135     cr4 = (struct cr4_32 *)&(cr4_val);
136
137     if (cr4->pae == 1) {
138         return PROTECTED_PAE;
139     } else {
140         return PROTECTED;
141     }
142 }
143
144 #elif __V3_64BIT__
145
146 v3_cpu_mode_t v3_get_host_cpu_mode() {
147     return LONG;
148 }
149
150 #endif 
151
152
153 #define V3_Yield(addr)                                  \
154     do {                                                \
155         extern struct v3_os_hooks * os_hooks;           \
156         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
157             (os_hooks)->yield_cpu();                    \
158         }                                               \
159     } while (0)                                         \
160
161
162 void v3_yield_cond(struct guest_info * info) {
163     uint64_t cur_cycle;
164     rdtscll(cur_cycle);
165
166     if (cur_cycle > (info->yield_start_cycle + info->yield_cycle_period)) {
167
168         /*
169           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
170           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
171         */
172         V3_Yield();
173         rdtscll(info->yield_start_cycle);
174     }
175 }
176
177 /* 
178  * unconditional cpu yield 
179  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
180  * Non guest context threads should call this function with a NULL argument
181  */
182 void v3_yield(struct guest_info * info) {
183     V3_Yield();
184
185     if (info) {
186         rdtscll(info->yield_start_cycle);
187     }
188 }
189
190
191
192 void v3_interrupt_cpu(struct guest_info * info, int logical_cpu) {
193     extern struct v3_os_hooks * os_hooks;
194
195     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
196         (os_hooks)->interrupt_cpu(info, logical_cpu);
197     }
198 }
199
200
201
202 int v3_vm_enter(struct guest_info * info) {
203     switch (v3_cpu_types[info->cpu_id]) {
204 #ifdef CONFIG_SVM
205         case V3_SVM_CPU:
206         case V3_SVM_REV3_CPU:
207             return v3_svm_enter(info);
208             break;
209 #endif
210 #if CONFIG_VMX && 0
211         case V3_VMX_CPU:
212         case V3_VMX_EPT_CPU:
213             return v3_vmx_enter(info);
214             break;
215 #endif
216         default:
217             PrintError("Attemping to enter a guest on an invalid CPU\n");
218             return -1;
219     }
220 }