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 new debugging directives
[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 ((0) && (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 #ifdef DEBUG_CTRL_REGS
113     PrintDebug("CR0 Write\n");
114 #endif
115     if (handle_cr0_write(info) == -1) {
116       return -1;
117     }
118   } else if (exit_code == VMEXIT_CR0_READ) {
119 #ifdef DEBUG_CTRL_REGS
120     PrintDebug("CR0 Read\n");
121 #endif
122     if (handle_cr0_read(info) == -1) {
123       return -1;
124     }
125   } else if (exit_code == VMEXIT_CR3_WRITE) {
126 #ifdef DEBUG_CTRL_REGS
127     PrintDebug("CR3 Write\n");
128 #endif
129     if (handle_cr3_write(info) == -1) {
130       return -1;
131     }    
132   } else if (exit_code == VMEXIT_CR3_READ) {
133 #ifdef DEBUG_CTRL_REGS
134     PrintDebug("CR3 Read\n");
135 #endif
136     if (handle_cr3_read(info) == -1) {
137       return -1;
138     }
139
140   } else if (exit_code == VMEXIT_EXCP14) {
141     addr_t fault_addr = guest_ctrl->exit_info2;
142     pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
143 #ifdef DEBUG_SHADOW_PAGING
144     PrintDebug("PageFault at %x (error=%d)\n", fault_addr, *error_code);
145 #endif
146     if (info->shdw_pg_mode == SHADOW_PAGING) {
147       if (handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
148         return -1;
149       }
150     } else {
151
152       PrintError("Page fault in un implemented paging mode\n");
153      
154       return -1;
155     }
156   } else if (exit_code == VMEXIT_NPF) {
157     PrintError("Currently unhandled Nested Page Fault\n");
158     return -1;
159
160   } else if (exit_code == VMEXIT_INVLPG) {
161     if (info->shdw_pg_mode == SHADOW_PAGING) {
162 #ifdef DEBUG_SHADOW_PAGING
163       PrintDebug("Invlpg\n");
164 #endif
165       if (handle_shadow_invlpg(info) == -1) {
166         return -1;
167       }
168     }
169    
170     /*
171       (exit_code == VMEXIT_INVLPGA)   || 
172     */
173     
174   } else if (exit_code == VMEXIT_INTR) {
175
176     //    handle_svm_intr(info);
177
178   } else if (exit_code == VMEXIT_SMI) { 
179
180     //   handle_svm_smi(info); // ignored for now
181
182   } else if (exit_code == VMEXIT_HLT) {
183     PrintDebug("Guest halted\n");
184     if (handle_svm_halt(info) == -1) {
185       return -1;
186     }
187   } else if (exit_code == VMEXIT_PAUSE) { 
188     PrintDebug("Guest paused\n");
189     if (handle_svm_pause(info) == -1) { 
190       return -1;
191     }
192   } else {
193     addr_t rip_addr;
194     char buf[15];
195     addr_t host_addr;
196
197
198     rip_addr = get_addr_linear(info, guest_state->rip, &(info->segments.cs));
199
200
201
202     PrintError("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
203     PrintError("RIP: %x\n", guest_state->rip);
204     PrintError("RIP Linear: %x\n", rip_addr);
205     
206     PrintError("SVM Returned: Exit Code: %x\n",exit_code); 
207     
208     PrintError("io_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
209     PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
210     
211     PrintError("io_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
212     PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
213
214     
215
216     if (info->mem_mode == PHYSICAL_MEM) {
217       if (guest_pa_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
218         PrintError("Could not translate guest_state->rip to host address\n");
219         return -1;
220       }
221     } else if (info->mem_mode == VIRTUAL_MEM) {
222       if (guest_va_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
223         PrintError("Could not translate guest_state->rip to host address\n");
224         return -1;
225       }
226     } else {
227       PrintError("Invalid memory mode\n");
228       return -1;
229     }
230
231     PrintError("Host Address of rip = 0x%x\n", host_addr);
232
233     memset(buf, 0, 32);
234     
235     PrintError("Reading instruction stream in guest\n", rip_addr);
236     
237     if (info->mem_mode == PHYSICAL_MEM) {
238       read_guest_pa_memory(info, rip_addr-16, 32, buf);
239     } else {
240       read_guest_va_memory(info, rip_addr-16, 32, buf);
241     }
242
243     PrintDebug("16 bytes before Rip\n");
244     PrintTraceMemDump(buf, 16);
245     PrintDebug("Rip onward\n");
246     PrintTraceMemDump(buf+16, 16);
247
248
249
250     return -1;
251
252   }
253
254
255   // Update the low level state
256
257   if (intr_pending(info)) {
258
259     switch (get_intr_type(info)) {
260     case EXTERNAL_IRQ: 
261       {
262         uint_t irq = get_intr_number(info);
263
264         // check to see if ==-1 (non exists)
265
266         /*      
267           guest_ctrl->EVENTINJ.vector = irq;
268           guest_ctrl->EVENTINJ.valid = 1;
269           guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXTERNAL_INTR;
270         */
271         
272         guest_ctrl->guest_ctrl.V_IRQ = 1;
273         guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
274         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
275         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
276 #ifdef DEBUG_INTERRUPTS
277         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
278 #endif
279         injecting_intr(info, irq, EXTERNAL_IRQ);
280         
281         break;
282       }
283     case NMI:
284       guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
285       break;
286     case EXCEPTION:
287       {
288         uint_t excp = get_intr_number(info);
289
290         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
291         
292         if (info->intr_state.excp_error_code_valid) {  //PAD
293           guest_ctrl->EVENTINJ.error_code = info->intr_state.excp_error_code;
294           guest_ctrl->EVENTINJ.ev = 1;
295 #ifdef DEBUG_INTERRUPTS
296           PrintDebug("Injecting error code %x\n", guest_ctrl->EVENTINJ.error_code);
297 #endif
298         }
299         
300         guest_ctrl->EVENTINJ.vector = excp;
301         
302         guest_ctrl->EVENTINJ.valid = 1;
303 #ifdef DEBUG_INTERRUPTS
304         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
305 #endif
306         injecting_intr(info, excp, EXCEPTION);
307         break;
308       }
309     case SOFTWARE_INTR:
310       guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
311       break;
312     case VIRTUAL_INTR:
313       guest_ctrl->EVENTINJ.type = SVM_INJECTION_VIRTUAL_INTR;
314       break;
315
316     case INVALID_INTR: 
317     default:
318       PrintError("Attempted to issue an invalid interrupt\n");
319       return -1;
320     }
321
322   }
323
324
325   guest_state->cr0 = info->ctrl_regs.cr0;
326   guest_state->cr2 = info->ctrl_regs.cr2;
327   guest_state->cr3 = info->ctrl_regs.cr3;
328   guest_state->cr4 = info->ctrl_regs.cr4;
329   guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
330   guest_state->rflags = info->ctrl_regs.rflags;
331
332
333   guest_state->cpl = info->cpl;
334
335   guest_state->rax = info->vm_regs.rax;
336   guest_state->rip = info->rip;
337   guest_state->rsp = info->vm_regs.rsp;
338
339
340   set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
341
342   if (exit_code == VMEXIT_INTR) {
343     //PrintDebug("INTR ret IP = %x\n", guest_state->rip);
344   }
345
346   return 0;
347 }
348