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.


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