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.


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