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.


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