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.


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