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 emulator
[palacios.git] / palacios / src / palacios / svm_handler.c
1 #include <palacios/svm_handler.h>
2 #include <palacios/vmm.h>
3 #include <palacios/vm_guest_mem.h>
4 #include <palacios/vmm_decoder.h>
5 #include <palacios/vmm_ctrl_regs.h>
6 #include <palacios/svm_io.h>
7 #include <palacios/svm_halt.h>
8 #include <palacios/svm_pause.h>
9 #include <palacios/vmm_intr.h>
10 #include <palacios/vmm_emulator.h>
11
12 int handle_svm_exit(struct guest_info * info) {
13   vmcb_ctrl_t * guest_ctrl = 0;
14   vmcb_saved_state_t * guest_state = 0;
15   ulong_t exit_code = 0;
16   
17   guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
18   guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
19   
20
21   // Update the high level state 
22   info->rip = guest_state->rip;
23   info->vm_regs.rsp = guest_state->rsp;
24   info->vm_regs.rax = guest_state->rax;
25
26   info->cpl = guest_state->cpl;
27
28
29   info->ctrl_regs.cr0 = guest_state->cr0;
30   info->ctrl_regs.cr2 = guest_state->cr2;
31   info->ctrl_regs.cr3 = guest_state->cr3;
32   info->ctrl_regs.cr4 = guest_state->cr4;
33   info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
34   info->ctrl_regs.rflags = guest_state->rflags;
35   info->ctrl_regs.efer = guest_state->efer;
36
37   get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
38   info->cpu_mode = get_cpu_mode(info);
39   info->mem_mode = get_mem_mode(info);
40
41
42   exit_code = guest_ctrl->exit_code;
43  
44
45   // Disable printing io exits due to bochs debug messages
46   //if (!((exit_code == VMEXIT_IOIO) && ((ushort_t)(guest_ctrl->exit_info1 >> 16) == 0x402))) {
47
48
49   //  PrintDebug("SVM Returned: Exit Code: 0x%x \t\t(tsc=%ul)\n",exit_code, (uint_t)info->time_state.guest_tsc); 
50   
51   if ((0) && (exit_code < 0x4f)) {
52     char instr[32];
53     int ret;
54     // Dump out the instr stream
55
56     //PrintDebug("RIP: %x\n", guest_state->rip);
57     PrintDebug("RIP Linear: %x\n", get_addr_linear(info, info->rip, &(info->segments.cs)));
58
59     // OK, now we will read the instruction
60     // The only difference between PROTECTED and PROTECTED_PG is whether we read
61     // from guest_pa or guest_va
62     if (info->mem_mode == PHYSICAL_MEM) { 
63       // The real rip address is actually a combination of the rip + CS base 
64       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 32, instr);
65     } else { 
66       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 32, instr);
67     }
68     
69     if (ret != 32) {
70       // I think we should inject a GPF into the guest
71       PrintDebug("Could not read instruction (ret=%d)\n", ret);
72     } else {
73
74       PrintDebug("Instr Stream:\n");
75       PrintTraceMemDump(instr, 32);
76     }
77   }
78
79
80     //  }
81   // PrintDebugVMCB((vmcb_t*)(info->vmm_data));
82
83
84   // PrintDebug("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
85   //PrintDebug("RIP: %x\n", guest_state->rip);
86
87   
88   //PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
89   
90   if (exit_code == VMEXIT_IOIO) {
91     struct svm_io_info * io_info = (struct svm_io_info *)&(guest_ctrl->exit_info1);
92     
93     if (io_info->type == 0) {
94       if (io_info->str) {
95         if (handle_svm_io_outs(info) == -1 ) {
96           return -1;
97         }
98       } else {
99         if (handle_svm_io_out(info) == -1) {
100           return -1;
101         }
102       }
103     } else {
104       if (io_info->str) {
105         if (handle_svm_io_ins(info) == -1) {
106           return -1;
107         }
108       } else {
109         if (handle_svm_io_in(info) == -1) {
110           return -1;
111         }
112       }
113     }
114   } else if (exit_code == VMEXIT_CR0_WRITE) {
115 #ifdef DEBUG_CTRL_REGS
116     PrintDebug("CR0 Write\n");
117 #endif
118     if (handle_cr0_write(info) == -1) {
119       return -1;
120     }
121   } else if (exit_code == VMEXIT_CR0_READ) {
122 #ifdef DEBUG_CTRL_REGS
123     PrintDebug("CR0 Read\n");
124 #endif
125     if (handle_cr0_read(info) == -1) {
126       return -1;
127     }
128   } else if (exit_code == VMEXIT_CR3_WRITE) {
129 #ifdef DEBUG_CTRL_REGS
130     PrintDebug("CR3 Write\n");
131 #endif
132     if (handle_cr3_write(info) == -1) {
133       return -1;
134     }    
135   } else if (exit_code == VMEXIT_CR3_READ) {
136 #ifdef DEBUG_CTRL_REGS
137     PrintDebug("CR3 Read\n");
138 #endif
139     if (handle_cr3_read(info) == -1) {
140       return -1;
141     }
142
143   } else if (exit_code == VMEXIT_EXCP14) {
144     addr_t fault_addr = guest_ctrl->exit_info2;
145     pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
146 #ifdef DEBUG_SHADOW_PAGING
147     PrintDebug("PageFault at %x (error=%d)\n", fault_addr, *error_code);
148 #endif
149     if (info->shdw_pg_mode == SHADOW_PAGING) {
150       if (handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
151         return -1;
152       }
153     } else {
154
155       PrintError("Page fault in un implemented paging mode\n");
156      
157       return -1;
158     }
159   } else if (exit_code == VMEXIT_NPF) {
160     PrintError("Currently unhandled Nested Page Fault\n");
161     return -1;
162
163   } else if (exit_code == VMEXIT_INVLPG) {
164     if (info->shdw_pg_mode == SHADOW_PAGING) {
165 #ifdef DEBUG_SHADOW_PAGING
166       PrintDebug("Invlpg\n");
167 #endif
168       if (handle_shadow_invlpg(info) == -1) {
169         return -1;
170       }
171     }
172    
173     /*
174       (exit_code == VMEXIT_INVLPGA)   || 
175     */
176     
177   } else if (exit_code == VMEXIT_INTR) {
178
179     //    handle_svm_intr(info);
180
181   } else if (exit_code == VMEXIT_SMI) { 
182
183     //   handle_svm_smi(info); // ignored for now
184
185   } else if (exit_code == VMEXIT_HLT) {
186     PrintDebug("Guest halted\n");
187     if (handle_svm_halt(info) == -1) {
188       return -1;
189     }
190   } else if (exit_code == VMEXIT_PAUSE) { 
191     PrintDebug("Guest paused\n");
192     if (handle_svm_pause(info) == -1) { 
193       return -1;
194     }
195   } else if (exit_code == VMEXIT_VMMCALL) {
196     PrintDebug("VMMCALL\n");
197     if (info->run_state == VM_EMULATING) {
198       if (v3_emulation_exit_handler(info) == -1) {
199         return -1;
200       }
201     } else {
202       PrintError("VMMCALL with not emulator...\n");
203       return -1;
204     }
205
206   } else {
207     addr_t rip_addr;
208     char buf[15];
209     addr_t host_addr;
210
211
212     rip_addr = get_addr_linear(info, guest_state->rip, &(info->segments.cs));
213
214
215
216     PrintError("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
217     PrintError("RIP: %x\n", guest_state->rip);
218     PrintError("RIP Linear: %x\n", rip_addr);
219     
220     PrintError("SVM Returned: Exit Code: %x\n",exit_code); 
221     
222     PrintError("io_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
223     PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
224     
225     PrintError("io_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
226     PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
227
228     
229
230     if (info->mem_mode == PHYSICAL_MEM) {
231       if (guest_pa_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
232         PrintError("Could not translate guest_state->rip to host address\n");
233         return -1;
234       }
235     } else if (info->mem_mode == VIRTUAL_MEM) {
236       if (guest_va_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
237         PrintError("Could not translate guest_state->rip to host address\n");
238         return -1;
239       }
240     } else {
241       PrintError("Invalid memory mode\n");
242       return -1;
243     }
244
245     PrintError("Host Address of rip = 0x%x\n", host_addr);
246
247     memset(buf, 0, 32);
248     
249     PrintError("Reading instruction stream in guest\n", rip_addr);
250     
251     if (info->mem_mode == PHYSICAL_MEM) {
252       read_guest_pa_memory(info, rip_addr-16, 32, buf);
253     } else {
254       read_guest_va_memory(info, rip_addr-16, 32, buf);
255     }
256
257     PrintDebug("16 bytes before Rip\n");
258     PrintTraceMemDump(buf, 16);
259     PrintDebug("Rip onward\n");
260     PrintTraceMemDump(buf+16, 16);
261
262
263
264     return -1;
265
266   }
267
268
269   // Update the low level state
270
271   if (intr_pending(info)) {
272
273     switch (get_intr_type(info)) {
274     case EXTERNAL_IRQ: 
275       {
276         uint_t irq = get_intr_number(info);
277
278         // check to see if ==-1 (non exists)
279
280         /*      
281           guest_ctrl->EVENTINJ.vector = irq;
282           guest_ctrl->EVENTINJ.valid = 1;
283           guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXTERNAL_INTR;
284         */
285         
286         guest_ctrl->guest_ctrl.V_IRQ = 1;
287         guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
288         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
289         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
290 #ifdef DEBUG_INTERRUPTS
291         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
292 #endif
293         injecting_intr(info, irq, EXTERNAL_IRQ);
294         
295         break;
296       }
297     case NMI:
298       guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
299       break;
300     case EXCEPTION:
301       {
302         uint_t excp = get_intr_number(info);
303
304         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
305         
306         if (info->intr_state.excp_error_code_valid) {  //PAD
307           guest_ctrl->EVENTINJ.error_code = info->intr_state.excp_error_code;
308           guest_ctrl->EVENTINJ.ev = 1;
309 #ifdef DEBUG_INTERRUPTS
310           PrintDebug("Injecting error code %x\n", guest_ctrl->EVENTINJ.error_code);
311 #endif
312         }
313         
314         guest_ctrl->EVENTINJ.vector = excp;
315         
316         guest_ctrl->EVENTINJ.valid = 1;
317 #ifdef DEBUG_INTERRUPTS
318         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
319 #endif
320         injecting_intr(info, excp, EXCEPTION);
321         break;
322       }
323     case SOFTWARE_INTR:
324       guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
325       break;
326     case VIRTUAL_INTR:
327       guest_ctrl->EVENTINJ.type = SVM_INJECTION_VIRTUAL_INTR;
328       break;
329
330     case INVALID_INTR: 
331     default:
332       PrintError("Attempted to issue an invalid interrupt\n");
333       return -1;
334     }
335
336   } else {
337 #ifdef DEBUG_INTERRUPTS
338     PrintDebug("No interrupts/exceptions pending\n");
339 #endif
340   }
341
342   guest_state->cr0 = info->ctrl_regs.cr0;
343   guest_state->cr2 = info->ctrl_regs.cr2;
344   guest_state->cr3 = info->ctrl_regs.cr3;
345   guest_state->cr4 = info->ctrl_regs.cr4;
346   guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
347   guest_state->rflags = info->ctrl_regs.rflags;
348   guest_state->efer = info->ctrl_regs.efer;
349
350   guest_state->cpl = info->cpl;
351
352   guest_state->rax = info->vm_regs.rax;
353   guest_state->rip = info->rip;
354   guest_state->rsp = info->vm_regs.rsp;
355
356
357   set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
358
359   if (exit_code == VMEXIT_INTR) {
360     //PrintDebug("INTR ret IP = %x\n", guest_state->rip);
361   }
362
363   return 0;
364 }
365