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 symbiotic interface
[palacios.git] / palacios / src / palacios / vmm_sym_iface.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
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_msr.h>
23 #include <palacios/vmm_mem.h>
24 #include <palacios/vmm_hypercall.h>
25
26 #define SYM_PAGE_MSR 0x535
27
28 #define SYM_CPUID_NUM 0x90000000
29
30 #define SYM_CALL_RET_HCALL 0x535
31
32
33 /* Notes: We use a combination of SYSCALL and SYSENTER Semantics 
34  * SYSCALL just sets an EIP, CS/SS seg, and GS seg via swapgs
35  * the RSP is loaded via the structure pointed to by GS
36  * This is safe because it assumes that system calls are guaranteed to be made with an empty kernel stack.
37  * We cannot make that assumption with a symcall, so we have to have our own stack area somewhere.
38  * SYSTENTER does not really use the GS base MSRs, but we do to map to 64 bit kernels
39  */
40
41 #define SYMCALL_RIP_MSR 0x536
42 #define SYMCALL_RSP_MSR 0x537
43 #define SYMCALL_CS_MSR  0x538
44 #define SYMCALL_GS_MSR  0x539
45 #define SYMCALL_FS_MSR  0x540
46
47
48 static int msr_read(uint_t msr, struct v3_msr * dst, void * priv_data) {
49     struct guest_info * info = (struct guest_info *)priv_data;
50     struct v3_sym_state * state = &(info->sym_state);
51
52     switch (msr) {
53         case SYM_PAGE_MSR:
54             dst->value = state->guest_pg_addr;
55             break;
56         case SYMCALL_RIP_MSR:
57             dst->value = state->sym_call_rip;
58             break;
59         case SYMCALL_RSP_MSR:
60             dst->value = state->sym_call_rsp;
61             break;
62         case SYMCALL_CS_MSR:
63             dst->value = state->sym_call_cs;
64             break;
65         case SYMCALL_GS_MSR:
66             dst->value = state->sym_call_gs;
67             break;
68         case SYMCALL_FS_MSR:
69             dst->value = state->sym_call_fs;
70             break;
71         default:
72             return -1;
73     }
74
75     return 0;
76 }
77
78 static int msr_write(uint_t msr, struct v3_msr src, void * priv_data) {
79     struct guest_info * info = (struct guest_info *)priv_data;
80     struct v3_sym_state * state = &(info->sym_state);
81
82     if (msr == SYM_PAGE_MSR) {
83         PrintDebug("Symbiotic MSR write for page %p\n", (void *)src.value);
84
85         if (state->active == 1) {
86             // unmap page
87             struct v3_shadow_region * old_reg = v3_get_shadow_region(info, (addr_t)state->guest_pg_addr);
88
89             if (old_reg == NULL) {
90                 PrintError("Could not find previously active symbiotic page (%p)\n", (void *)state->guest_pg_addr);
91                 return -1;
92             }
93
94             v3_delete_shadow_region(info, old_reg);
95         }
96
97         state->guest_pg_addr = src.value;
98         state->guest_pg_addr &= ~0xfffLL;
99
100         state->active = 1;
101
102         // map page
103         v3_add_shadow_mem(info, (addr_t)state->guest_pg_addr, 
104                           (addr_t)(state->guest_pg_addr + PAGE_SIZE_4KB - 1), 
105                           state->sym_page_pa);
106
107
108     } else if (msr == SYMCALL_RIP_MSR) {
109         state->sym_call_rip = src.value;
110     } else if (msr == SYMCALL_RSP_MSR) {
111         state->sym_call_rsp = src.value;
112     } else if (msr == SYMCALL_CS_MSR) {
113         state->sym_call_cs = src.value;
114     } else if (msr == SYMCALL_GS_MSR) {
115         state->sym_call_gs = src.value;
116     } else if (msr == SYMCALL_FS_MSR) {
117         state->sym_call_fs = src.value;
118     } else {
119         PrintError("Invalid Symbiotic MSR write (0x%x)\n", msr);
120         return -1;
121     }
122
123     return 0;
124 }
125
126 static int cpuid_fn(struct guest_info * info, uint32_t cpuid, 
127                     uint32_t * eax, uint32_t * ebx,
128                     uint32_t * ecx, uint32_t * edx,
129                     void * private_data) {
130     extern v3_cpu_arch_t v3_cpu_types[];
131
132     *eax = *(uint32_t *)"V3V";
133
134     if ((v3_cpu_types[info->cpu_id] == V3_SVM_CPU) || 
135         (v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU)) {
136         *ebx = *(uint32_t *)"SVM";
137     } else if ((v3_cpu_types[info->cpu_id] == V3_VMX_CPU) || 
138                (v3_cpu_types[info->cpu_id] == V3_VMX_EPT_CPU)) {
139         *ebx = *(uint32_t *)"VMX";
140     }
141
142
143     return 0;
144 }
145     
146
147 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data);
148
149
150
151 int v3_init_sym_iface(struct guest_info * info) {
152     struct v3_sym_state * state = &(info->sym_state);
153     memset(state, 0, sizeof(struct v3_sym_state));
154
155     state->sym_page_pa = (addr_t)V3_AllocPages(1);
156     state->sym_page = (struct v3_sym_interface *)V3_VAddr((void *)state->sym_page_pa);
157     memset(state->sym_page, 0, PAGE_SIZE_4KB);
158
159     
160     memcpy(&(state->sym_page->magic), "V3V", 3);
161
162     v3_hook_msr(info, SYM_PAGE_MSR, msr_read, msr_write, info);
163
164     v3_hook_cpuid(info, SYM_CPUID_NUM, cpuid_fn, info);
165
166     v3_hook_msr(info, SYMCALL_RIP_MSR, msr_read, msr_write, info);
167     v3_hook_msr(info, SYMCALL_RSP_MSR, msr_read, msr_write, info);
168     v3_hook_msr(info, SYMCALL_CS_MSR, msr_read, msr_write, info);
169     v3_hook_msr(info, SYMCALL_GS_MSR, msr_read, msr_write, info);
170     v3_hook_msr(info, SYMCALL_FS_MSR, msr_read, msr_write, info);
171
172     v3_register_hypercall(info, SYM_CALL_RET_HCALL, sym_call_ret, NULL);
173
174     return 0;
175 }
176
177 int v3_sym_map_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) {
178     struct v3_sym_state * state = &(info->sym_state);
179     uint_t dev_index = (bus << 8) + (dev << 3) + fn;
180     uint_t major = dev_index / 8;
181     uint_t minor = dev_index % 8;
182
183     if (bus > 3) {
184         PrintError("Invalid PCI bus %d\n", bus);
185         return -1;
186     }
187
188     PrintDebug("Setting passthrough pci map for index=%d\n", dev_index);
189
190     state->sym_page->pci_pt_map[major] |= 0x1 << minor;
191
192     PrintDebug("pt_map entry=%x\n",   state->sym_page->pci_pt_map[major]);
193
194     PrintDebug("pt map vmm addr=%p\n", state->sym_page->pci_pt_map);
195
196     return 0;
197 }
198
199 int v3_sym_unmap_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) {
200     struct v3_sym_state * state = &(info->sym_state);
201     uint_t dev_index = (bus << 8) + (dev << 3) + fn;
202     uint_t major = dev_index / 8;
203     uint_t minor = dev_index % 8;
204
205     if (bus > 3) {
206         PrintError("Invalid PCI bus %d\n", bus);
207         return -1;
208     }
209
210     state->sym_page->pci_pt_map[major] &= ~(0x1 << minor);
211
212     return 0;
213 }
214
215
216
217 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data) {
218     struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
219     struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx);
220
221
222     PrintError("Return from sym call\n");
223     v3_print_guest_state(info);
224     v3_print_mem_map(info);
225
226
227     if (state->notifier != NULL) {
228         if (state->notifier(info, state->private_data) == -1) {
229             PrintError("Error in return from symcall.\n");
230             return -1;
231         }
232     }
233
234
235     // restore guest state
236     memcpy(&(info->vm_regs), &(old_ctx->vm_regs), sizeof(struct v3_gprs));
237     memcpy(&(info->segments.cs), &(old_ctx->cs), sizeof(struct v3_segment));
238     memcpy(&(info->segments.ss), &(old_ctx->ss), sizeof(struct v3_segment));
239     info->segments.gs.base = old_ctx->gs_base;
240     info->segments.fs.base = old_ctx->fs_base;
241     info->rip = old_ctx->rip;
242     info->cpl = old_ctx->cpl;
243
244
245     PrintDebug("restoring guest state\n");
246     v3_print_guest_state(info);
247
248     // clear sym flags
249     state->call_active = 0;
250
251
252     return 0;
253 }
254
255
256 int v3_sym_call(struct guest_info * info, 
257                 uint64_t call_num, uint64_t arg0, 
258                 uint64_t arg1, uint64_t arg2,
259                 uint64_t arg3, uint64_t arg4, 
260                 int (*notifier)(struct guest_info * info, void * private_data),
261                 void * private_data) {
262     struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
263
264
265     PrintDebug("Making Sym call\n");
266
267     if ((state->sym_page->sym_call_enabled == 0) ||
268         (state->call_active == 1) || 
269         (state->call_pending == 1)) {
270         return -1;
271     }
272
273     state->args[0] = call_num;
274     state->args[1] = arg0;
275     state->args[2] = arg1;
276     state->args[3] = arg2;
277     state->args[4] = arg3;
278     state->args[5] = arg4;
279
280     state->notifier = notifier;
281     state->private_data = private_data;
282
283     state->call_pending = 1;
284
285     return 0;
286 }
287
288
289
290 int v3_activate_sym_call(struct guest_info * info) {
291     struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
292     struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx);
293     struct v3_segment sym_cs;
294     struct v3_segment sym_ss;
295
296
297     if ((state->sym_page->sym_call_enabled == 0) || 
298         (state->call_pending == 0)) {
299         // Unable to make sym call or none pending
300         if (state->call_active == 1) {
301             PrintError("handled exit while in symcall\n");
302         }
303         return 0;
304     }
305
306
307     PrintDebug("Activating Symbiotic call\n");
308     v3_print_guest_state(info);
309
310
311     // Save the old context
312     memcpy(&(old_ctx->vm_regs), &(info->vm_regs), sizeof(struct v3_gprs));
313     memcpy(&(old_ctx->cs), &(info->segments.cs), sizeof(struct v3_segment));
314     memcpy(&(old_ctx->ss), &(info->segments.ss), sizeof(struct v3_segment));
315     old_ctx->gs_base = info->segments.gs.base;
316     old_ctx->fs_base = info->segments.fs.base;
317     old_ctx->rip = info->rip;
318     old_ctx->cpl = info->cpl;
319
320     
321  
322     // Setup the sym call context
323     info->rip = state->sym_call_rip;
324     info->vm_regs.rsp = state->sym_call_rsp;
325
326     v3_translate_segment(info, state->sym_call_cs, &sym_cs);
327     memcpy(&(info->segments.cs), &sym_cs, sizeof(struct v3_segment));
328  
329     v3_translate_segment(info, state->sym_call_cs + 8, &sym_ss);
330     memcpy(&(info->segments.ss), &sym_ss, sizeof(struct v3_segment));
331
332     info->segments.gs.base = state->sym_call_gs;
333     info->segments.fs.base = state->sym_call_fs;
334     info->cpl = 0;
335
336     info->vm_regs.rax = state->args[0];
337     info->vm_regs.rbx = state->args[1];
338     info->vm_regs.rcx = state->args[2];
339     info->vm_regs.rdx = state->args[3];
340     info->vm_regs.rsi = state->args[4];
341     info->vm_regs.rdi = state->args[5];
342
343     // Mark sym call as active
344     state->call_pending = 0;
345     state->call_active = 1;
346
347
348     PrintDebug("Sym state\n");
349     v3_print_guest_state(info);
350
351     return 1;
352 }