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.


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