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.


code for new irq hooking mechanism
[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         // check to see if ==-1 (non exists)
254
255         /*      
256           guest_ctrl->EVENTINJ.vector = irq;
257           guest_ctrl->EVENTINJ.valid = 1;
258           guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXTERNAL_INTR;
259         */
260         
261         guest_ctrl->guest_ctrl.V_IRQ = 1;
262         guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
263         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
264         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
265
266         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
267
268         injecting_intr(info, irq, EXTERNAL_IRQ);
269         
270         break;
271       }
272     case NMI:
273       guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
274       break;
275     case EXCEPTION:
276       {
277         uint_t excp = get_intr_number(info);
278
279         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
280         
281         if (info->intr_state.excp_error_code_valid) {  //PAD
282           guest_ctrl->EVENTINJ.error_code = info->intr_state.excp_error_code;
283           guest_ctrl->EVENTINJ.ev = 1;
284           PrintDebug("Injecting error code %x\n", guest_ctrl->EVENTINJ.error_code);
285         }
286         
287         guest_ctrl->EVENTINJ.vector = excp;
288         
289         guest_ctrl->EVENTINJ.valid = 1;
290         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
291         injecting_intr(info, excp, EXCEPTION);
292         break;
293       }
294     case SOFTWARE_INTR:
295       guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
296       break;
297     case VIRTUAL_INTR:
298       guest_ctrl->EVENTINJ.type = SVM_INJECTION_VIRTUAL_INTR;
299       break;
300
301     case INVALID_INTR: 
302     default:
303       PrintDebug("Attempted to issue an invalid interrupt\n");
304       return -1;
305     }
306
307   }
308
309
310   guest_state->cr0 = info->ctrl_regs.cr0;
311   guest_state->cr2 = info->ctrl_regs.cr2;
312   guest_state->cr3 = info->ctrl_regs.cr3;
313   guest_state->cr4 = info->ctrl_regs.cr4;
314   guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
315   guest_state->rflags = info->ctrl_regs.rflags;
316
317
318   guest_state->cpl = info->cpl;
319
320   guest_state->rax = info->vm_regs.rax;
321   guest_state->rip = info->rip;
322   guest_state->rsp = info->vm_regs.rsp;
323
324
325   set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
326
327   if (exit_code == VMEXIT_INTR) {
328     //PrintDebug("INTR ret IP = %x\n", guest_state->rip);
329   }
330
331   return 0;
332 }
333