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 decoder support for cr0 write handler
[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
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 {
196     addr_t rip_addr;
197     char buf[15];
198     addr_t host_addr;
199
200
201     rip_addr = get_addr_linear(info, guest_state->rip, &(info->segments.cs));
202
203
204
205     PrintError("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
206     PrintError("RIP: %x\n", guest_state->rip);
207     PrintError("RIP Linear: %x\n", rip_addr);
208     
209     PrintError("SVM Returned: Exit Code: %x\n",exit_code); 
210     
211     PrintError("io_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
212     PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
213     
214     PrintError("io_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
215     PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
216
217     
218
219     if (info->mem_mode == PHYSICAL_MEM) {
220       if (guest_pa_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
221         PrintError("Could not translate guest_state->rip to host address\n");
222         return -1;
223       }
224     } else if (info->mem_mode == VIRTUAL_MEM) {
225       if (guest_va_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
226         PrintError("Could not translate guest_state->rip to host address\n");
227         return -1;
228       }
229     } else {
230       PrintError("Invalid memory mode\n");
231       return -1;
232     }
233
234     PrintError("Host Address of rip = 0x%x\n", host_addr);
235
236     memset(buf, 0, 32);
237     
238     PrintError("Reading instruction stream in guest\n", rip_addr);
239     
240     if (info->mem_mode == PHYSICAL_MEM) {
241       read_guest_pa_memory(info, rip_addr-16, 32, buf);
242     } else {
243       read_guest_va_memory(info, rip_addr-16, 32, buf);
244     }
245
246     PrintDebug("16 bytes before Rip\n");
247     PrintTraceMemDump(buf, 16);
248     PrintDebug("Rip onward\n");
249     PrintTraceMemDump(buf+16, 16);
250
251
252
253     return -1;
254
255   }
256
257
258   // Update the low level state
259
260   if (intr_pending(info)) {
261
262     switch (get_intr_type(info)) {
263     case EXTERNAL_IRQ: 
264       {
265         uint_t irq = get_intr_number(info);
266
267         // check to see if ==-1 (non exists)
268
269         /*      
270           guest_ctrl->EVENTINJ.vector = irq;
271           guest_ctrl->EVENTINJ.valid = 1;
272           guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXTERNAL_INTR;
273         */
274         
275         guest_ctrl->guest_ctrl.V_IRQ = 1;
276         guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
277         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
278         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
279 #ifdef DEBUG_INTERRUPTS
280         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
281 #endif
282         injecting_intr(info, irq, EXTERNAL_IRQ);
283         
284         break;
285       }
286     case NMI:
287       guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
288       break;
289     case EXCEPTION:
290       {
291         uint_t excp = get_intr_number(info);
292
293         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
294         
295         if (info->intr_state.excp_error_code_valid) {  //PAD
296           guest_ctrl->EVENTINJ.error_code = info->intr_state.excp_error_code;
297           guest_ctrl->EVENTINJ.ev = 1;
298 #ifdef DEBUG_INTERRUPTS
299           PrintDebug("Injecting error code %x\n", guest_ctrl->EVENTINJ.error_code);
300 #endif
301         }
302         
303         guest_ctrl->EVENTINJ.vector = excp;
304         
305         guest_ctrl->EVENTINJ.valid = 1;
306 #ifdef DEBUG_INTERRUPTS
307         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
308 #endif
309         injecting_intr(info, excp, EXCEPTION);
310         break;
311       }
312     case SOFTWARE_INTR:
313       guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
314       break;
315     case VIRTUAL_INTR:
316       guest_ctrl->EVENTINJ.type = SVM_INJECTION_VIRTUAL_INTR;
317       break;
318
319     case INVALID_INTR: 
320     default:
321       PrintError("Attempted to issue an invalid interrupt\n");
322       return -1;
323     }
324
325   }
326
327
328   guest_state->cr0 = info->ctrl_regs.cr0;
329   guest_state->cr2 = info->ctrl_regs.cr2;
330   guest_state->cr3 = info->ctrl_regs.cr3;
331   guest_state->cr4 = info->ctrl_regs.cr4;
332   guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
333   guest_state->rflags = info->ctrl_regs.rflags;
334   guest_state->efer = info->ctrl_regs.efer;
335
336   guest_state->cpl = info->cpl;
337
338   guest_state->rax = info->vm_regs.rax;
339   guest_state->rip = info->rip;
340   guest_state->rsp = info->vm_regs.rsp;
341
342
343   set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
344
345   if (exit_code == VMEXIT_INTR) {
346     //PrintDebug("INTR ret IP = %x\n", guest_state->rip);
347   }
348
349   return 0;
350 }
351