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.


1545cad7d60a6d545f622ab8899932f16a143a27
[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, 15);
234     
235     PrintError("Reading from 0x%x in guest\n", rip_addr);
236     
237     if (info->mem_mode == PHYSICAL_MEM) {
238       read_guest_pa_memory(info, rip_addr, 15, buf);
239     } else {
240       read_guest_va_memory(info, rip_addr, 15, buf);
241     }
242
243     PrintTraceMemDump(buf, 15);
244
245     return -1;
246
247   }
248
249
250   // Update the low level state
251
252   if (intr_pending(info)) {
253
254     switch (get_intr_type(info)) {
255     case EXTERNAL_IRQ: 
256       {
257         uint_t irq = get_intr_number(info);
258
259         // check to see if ==-1 (non exists)
260
261         /*      
262           guest_ctrl->EVENTINJ.vector = irq;
263           guest_ctrl->EVENTINJ.valid = 1;
264           guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXTERNAL_INTR;
265         */
266         
267         guest_ctrl->guest_ctrl.V_IRQ = 1;
268         guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
269         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
270         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
271 #ifdef DEBUG_INTERRUPTS
272         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
273 #endif
274         injecting_intr(info, irq, EXTERNAL_IRQ);
275         
276         break;
277       }
278     case NMI:
279       guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
280       break;
281     case EXCEPTION:
282       {
283         uint_t excp = get_intr_number(info);
284
285         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
286         
287         if (info->intr_state.excp_error_code_valid) {  //PAD
288           guest_ctrl->EVENTINJ.error_code = info->intr_state.excp_error_code;
289           guest_ctrl->EVENTINJ.ev = 1;
290 #ifdef DEBUG_INTERRUPTS
291           PrintDebug("Injecting error code %x\n", guest_ctrl->EVENTINJ.error_code);
292 #endif
293         }
294         
295         guest_ctrl->EVENTINJ.vector = excp;
296         
297         guest_ctrl->EVENTINJ.valid = 1;
298 #ifdef DEBUG_INTERRUPTS
299         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
300 #endif
301         injecting_intr(info, excp, EXCEPTION);
302         break;
303       }
304     case SOFTWARE_INTR:
305       guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
306       break;
307     case VIRTUAL_INTR:
308       guest_ctrl->EVENTINJ.type = SVM_INJECTION_VIRTUAL_INTR;
309       break;
310
311     case INVALID_INTR: 
312     default:
313       PrintError("Attempted to issue an invalid interrupt\n");
314       return -1;
315     }
316
317   }
318
319
320   guest_state->cr0 = info->ctrl_regs.cr0;
321   guest_state->cr2 = info->ctrl_regs.cr2;
322   guest_state->cr3 = info->ctrl_regs.cr3;
323   guest_state->cr4 = info->ctrl_regs.cr4;
324   guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
325   guest_state->rflags = info->ctrl_regs.rflags;
326
327
328   guest_state->cpl = info->cpl;
329
330   guest_state->rax = info->vm_regs.rax;
331   guest_state->rip = info->rip;
332   guest_state->rsp = info->vm_regs.rsp;
333
334
335   set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
336
337   if (exit_code == VMEXIT_INTR) {
338     //PrintDebug("INTR ret IP = %x\n", guest_state->rip);
339   }
340
341   return 0;
342 }
343