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 and a number of other small changes
[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 static int msr_read(uint_t msr, struct v3_msr * dst, void * priv_data) {
34     struct guest_info * info = (struct guest_info *)priv_data;
35     struct v3_sym_state * state = &(info->sym_state);
36
37     dst->value = state->guest_pg_addr;
38
39     return 0;
40 }
41
42 static int msr_write(uint_t msr, struct v3_msr src, void * priv_data) {
43     struct guest_info * info = (struct guest_info *)priv_data;
44     struct v3_sym_state * state = &(info->sym_state);
45
46
47     PrintDebug("Symbiotic MSR write for page %p\n", (void *)src.value);
48
49     if (state->active == 1) {
50         // unmap page
51         struct v3_shadow_region * old_reg = v3_get_shadow_region(info, (addr_t)state->guest_pg_addr);
52
53         if (old_reg == NULL) {
54             PrintError("Could not find previously active symbiotic page (%p)\n", (void *)state->guest_pg_addr);
55             return -1;
56         }
57
58         v3_delete_shadow_region(info, old_reg);
59     }
60
61     state->guest_pg_addr = src.value;
62     state->guest_pg_addr &= ~0xfffLL;
63
64     state->active = 1;
65
66     // map page
67     v3_add_shadow_mem(info, (addr_t)state->guest_pg_addr, 
68                       (addr_t)(state->guest_pg_addr + PAGE_SIZE_4KB - 1), 
69                       state->sym_page_pa);
70
71     return 0;
72 }
73
74 static int cpuid_fn(struct guest_info * info, uint32_t cpuid, 
75                     uint32_t * eax, uint32_t * ebx,
76                     uint32_t * ecx, uint32_t * edx,
77                     void * private_data) {
78
79     memset(eax, 0, sizeof(uint32_t));
80     memcpy(eax, "V3V", 3);
81
82     return 0;
83 }
84     
85
86 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data);
87
88
89
90 int v3_init_sym_iface(struct guest_info * info) {
91     struct v3_sym_state * state = &(info->sym_state);
92     memset(state, 0, sizeof(struct v3_sym_state));
93
94     state->sym_page_pa = (addr_t)V3_AllocPages(1);
95     state->sym_page = (struct v3_sym_interface *)V3_VAddr((void *)state->sym_page_pa);
96     memset(state->sym_page, 0, PAGE_SIZE_4KB);
97
98     
99     memcpy(&(state->sym_page->magic), "V3V", 3);
100
101     v3_hook_msr(info, SYM_PAGE_MSR, msr_read, msr_write, info);
102
103     v3_hook_cpuid(info, SYM_CPUID_NUM, cpuid_fn, info);
104
105
106     v3_register_hypercall(info, SYM_CALL_RET_HCALL, sym_call_ret, NULL);
107
108     return 0;
109 }
110
111 int v3_sym_map_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) {
112     struct v3_sym_state * state = &(info->sym_state);
113     uint_t dev_index = (bus << 8) + (dev << 3) + fn;
114     uint_t major = dev_index / 8;
115     uint_t minor = dev_index % 8;
116
117     if (bus > 3) {
118         PrintError("Invalid PCI bus %d\n", bus);
119         return -1;
120     }
121
122     PrintDebug("Setting passthrough pci map for index=%d\n", dev_index);
123
124     state->sym_page->pci_pt_map[major] |= 0x1 << minor;
125
126     PrintDebug("pt_map entry=%x\n",   state->sym_page->pci_pt_map[major]);
127
128     PrintDebug("pt map vmm addr=%p\n", state->sym_page->pci_pt_map);
129
130     return 0;
131 }
132
133 int v3_sym_unmap_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) {
134     struct v3_sym_state * state = &(info->sym_state);
135     uint_t dev_index = (bus << 8) + (dev << 3) + fn;
136     uint_t major = dev_index / 8;
137     uint_t minor = dev_index % 8;
138
139     if (bus > 3) {
140         PrintError("Invalid PCI bus %d\n", bus);
141         return -1;
142     }
143
144     state->sym_page->pci_pt_map[major] &= ~(0x1 << minor);
145
146     return 0;
147 }
148
149
150
151 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data) {
152     struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
153     struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx);
154
155
156     PrintError("Return from sym call\n");
157     v3_print_guest_state(info);
158     v3_print_mem_map(info);
159
160
161     if (state->notifier != NULL) {
162         if (state->notifier(info, state->private_data) == -1) {
163             PrintError("Error in return from symcall.\n");
164             return -1;
165         }
166     }
167
168
169     // restore guest state
170     memcpy(&(info->vm_regs), &(old_ctx->vm_regs), sizeof(struct v3_gprs));
171     memcpy(&(info->segments.cs), &(old_ctx->cs), sizeof(struct v3_segment));
172     memcpy(&(info->segments.ss), &(old_ctx->ss), sizeof(struct v3_segment));
173     info->segments.gs.base = old_ctx->gs_base;
174     info->segments.fs.base = old_ctx->fs_base;
175     info->rip = old_ctx->rip;
176     info->cpl = old_ctx->cpl;
177
178
179     PrintDebug("restoring guest state\n");
180     v3_print_guest_state(info);
181
182     // clear sym flags
183     state->call_active = 0;
184
185
186     return 0;
187 }
188
189
190 int v3_sym_call(struct guest_info * info, 
191                 uint64_t arg0, uint64_t arg1, 
192                 uint64_t arg2, uint64_t arg3,
193                 uint64_t arg4, uint64_t arg5, 
194                 int (*notifier)(struct guest_info * info, void * private_data),
195                 void * private_data) {
196     struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
197
198
199     PrintDebug("Making Sym call\n");
200
201     if ((state->sym_page->sym_call_enabled == 0) ||
202         (state->call_active == 1) || 
203         (state->call_pending == 1)) {
204         return -1;
205     }
206
207     state->args[0] = arg0;
208     state->args[1] = arg1;
209     state->args[2] = arg2;
210     state->args[3] = arg3;
211     state->args[4] = arg4;
212     state->args[5] = arg5;
213
214     state->notifier = notifier;
215     state->private_data = private_data;
216
217     state->call_pending = 1;
218
219     return 0;
220 }
221
222
223
224 int v3_activate_sym_call(struct guest_info * info) {
225     struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
226     struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx);
227     struct v3_segment sym_cs;
228     struct v3_segment sym_ss;
229
230
231     if ((state->sym_page->sym_call_enabled == 0) || 
232         (state->call_pending == 0)) {
233         // Unable to make sym call or none pending
234         if (state->call_active == 1) {
235             PrintError("handled exit while in symcall\n");
236         }
237         return 0;
238     }
239
240
241     PrintDebug("Activating Symbiotic call\n");
242     v3_print_guest_state(info);
243
244
245     // Save the old context
246     memcpy(&(old_ctx->vm_regs), &(info->vm_regs), sizeof(struct v3_gprs));
247     memcpy(&(old_ctx->cs), &(info->segments.cs), sizeof(struct v3_segment));
248     memcpy(&(old_ctx->ss), &(info->segments.ss), sizeof(struct v3_segment));
249     old_ctx->gs_base = info->segments.gs.base;
250     old_ctx->fs_base = info->segments.fs.base;
251     old_ctx->rip = info->rip;
252     old_ctx->cpl = info->cpl;
253
254     
255  
256     // Setup the sym call context
257     info->rip = state->sym_page->sym_call_rip;
258     info->vm_regs.rsp = state->sym_page->sym_call_rsp;
259
260     v3_translate_segment(info, state->sym_page->sym_call_cs, &sym_cs);
261     memcpy(&(info->segments.cs), &sym_cs, sizeof(struct v3_segment));
262  
263     v3_translate_segment(info, state->sym_page->sym_call_cs + 8, &sym_ss);
264     memcpy(&(info->segments.ss), &sym_ss, sizeof(struct v3_segment));
265
266     info->segments.gs.base = state->sym_page->sym_call_gs;
267     info->segments.fs.base = 0;
268     info->cpl = 0;
269
270     info->vm_regs.rax = state->args[0];
271     info->vm_regs.rbx = state->args[1];
272     info->vm_regs.rcx = state->args[2];
273     info->vm_regs.rdx = state->args[3];
274     info->vm_regs.rsi = state->args[4];
275     info->vm_regs.rdi = state->args[5];
276
277     // Mark sym call as active
278     state->call_pending = 0;
279     state->call_active = 1;
280
281
282     PrintDebug("Sym state\n");
283     v3_print_guest_state(info);
284
285     return 1;
286 }