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.


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