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 support for SMI interrupt
[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   PrintDebug("SVM Returned: Exit Code: 0x%x \t\t(tsc=%ul)\n",exit_code, (uint_t)info->time_state.guest_tsc); 
45     //  }
46   // PrintDebugVMCB((vmcb_t*)(info->vmm_data));
47
48
49   // PrintDebug("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
50   //PrintDebug("RIP: %x\n", guest_state->rip);
51
52   
53   //PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
54   
55   if (exit_code == VMEXIT_IOIO) {
56     struct svm_io_info * io_info = (struct svm_io_info *)&(guest_ctrl->exit_info1);
57     
58     if (io_info->type == 0) {
59       if (io_info->str) {
60         if (handle_svm_io_outs(info) == -1 ) {
61           return -1;
62         }
63       } else {
64         if (handle_svm_io_out(info) == -1) {
65           return -1;
66         }
67       }
68     } else {
69       if (io_info->str) {
70         if (handle_svm_io_ins(info) == -1) {
71           return -1;
72         }
73       } else {
74         if (handle_svm_io_in(info) == -1) {
75           return -1;
76         }
77       }
78     }
79   } else if (exit_code == VMEXIT_CR0_WRITE) {
80     PrintDebug("CR0 Write\n");
81
82     if (handle_cr0_write(info) == -1) {
83       return -1;
84     }
85   } else if (exit_code == VMEXIT_CR0_READ) {
86     PrintDebug("CR0 Read\n");
87
88     if (handle_cr0_read(info) == -1) {
89       return -1;
90     }
91   } else if (exit_code == VMEXIT_CR3_WRITE) {
92     PrintDebug("CR3 Write\n");
93
94     if (handle_cr3_write(info) == -1) {
95       return -1;
96     }    
97   } else if (exit_code == VMEXIT_CR3_READ) {
98     PrintDebug("CR3 Read\n");
99
100     if (handle_cr3_read(info) == -1) {
101       return -1;
102     }
103
104   } else if (exit_code == VMEXIT_EXCP14) {
105     addr_t fault_addr = guest_ctrl->exit_info2;
106     pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
107     
108     PrintDebug("PageFault at %x (error=%d)\n", fault_addr, *error_code);
109
110     if (info->shdw_pg_mode == SHADOW_PAGING) {
111       if (handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
112         return -1;
113       }
114     } else {
115       PrintDebug("Page fault in un implemented paging mode\n");
116       return -1;
117     }
118
119   } else if (exit_code == VMEXIT_INVLPG) {
120     if (info->shdw_pg_mode == SHADOW_PAGING) {
121       PrintDebug("Invlpg\n");
122       if (handle_shadow_invlpg(info) == -1) {
123         return -1;
124       }
125     }
126    
127     /*
128       (exit_code == VMEXIT_INVLPGA)   || 
129     */
130     
131   } else if (exit_code == VMEXIT_INTR) {
132
133     //    handle_svm_intr(info);
134
135   } else if (exit_code == VMEXIT_SMI) { 
136
137     //   handle_svm_smi(info); // ignored for now
138
139   } else if (exit_code == VMEXIT_HLT) {
140     PrintDebug("Guest halted\n");
141     if (handle_svm_halt(info) == -1) {
142       return -1;
143     }
144   } else {
145     addr_t rip_addr;
146     char buf[15];
147     addr_t host_addr;
148
149
150     rip_addr = get_addr_linear(info, guest_state->rip, &(info->segments.cs));
151
152
153
154     PrintDebug("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
155     PrintDebug("RIP: %x\n", guest_state->rip);
156     PrintDebug("RIP Linear: %x\n", rip_addr);
157     
158     PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
159     
160     PrintDebug("io_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
161     PrintDebug("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
162     
163     PrintDebug("io_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
164     PrintDebug("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
165
166     
167
168     if (info->mem_mode == PHYSICAL_MEM) {
169       if (guest_pa_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
170         PrintDebug("Could not translate guest_state->rip to host address\n");
171         return -1;
172       }
173     } else if (info->mem_mode == VIRTUAL_MEM) {
174       if (guest_va_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
175         PrintDebug("Could not translate guest_state->rip to host address\n");
176         return -1;
177       }
178     } else {
179       PrintDebug("Invalid memory mode\n");
180       return -1;
181     }
182
183     PrintDebug("Host Address of rip = 0x%x\n", host_addr);
184
185     memset(buf, 0, 15);
186     
187     PrintDebug("Reading from 0x%x in guest\n", rip_addr);
188     
189     if (info->mem_mode == PHYSICAL_MEM) {
190       read_guest_pa_memory(info, rip_addr, 15, buf);
191     } else {
192       read_guest_va_memory(info, rip_addr, 15, buf);
193     }
194
195     PrintTraceMemDump(buf, 15);
196
197     while(1);
198
199   }
200
201
202   // Update the low level state
203
204   if (intr_pending(info)) {
205
206     switch (get_intr_type(info)) {
207     case EXTERNAL_IRQ: 
208       {
209         uint_t irq = get_intr_number(info);
210         /*      
211           guest_ctrl->EVENTINJ.vector = irq;
212           guest_ctrl->EVENTINJ.valid = 1;
213           guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXTERNAL_INTR;
214         */
215         
216         guest_ctrl->guest_ctrl.V_IRQ = 1;
217         guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
218         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
219         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
220
221         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
222
223         injecting_intr(info, irq, EXTERNAL_IRQ);
224         
225         break;
226       }
227     case NMI:
228       guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
229       break;
230     case EXCEPTION:
231       {
232         uint_t excp = get_intr_number(info);
233
234         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
235         
236         if (info->intr_state.excp_error_code) {
237           guest_ctrl->EVENTINJ.error_code = info->intr_state.excp_error_code;
238           guest_ctrl->EVENTINJ.ev = 1;
239           PrintDebug("Injecting error code %x\n", guest_ctrl->EVENTINJ.error_code);
240         }
241         
242         guest_ctrl->EVENTINJ.vector = excp;
243         
244         guest_ctrl->EVENTINJ.valid = 1;
245         PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
246         injecting_intr(info, excp, EXCEPTION);
247         break;
248       }
249     case SOFTWARE_INTR:
250       guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
251       break;
252     case VIRTUAL_INTR:
253       guest_ctrl->EVENTINJ.type = SVM_INJECTION_VIRTUAL_INTR;
254       break;
255
256     case INVALID_INTR: 
257     default:
258       PrintDebug("Attempted to issue an invalid interrupt\n");
259       return -1;
260     }
261
262   }
263
264
265   guest_state->cr0 = info->ctrl_regs.cr0;
266   guest_state->cr2 = info->ctrl_regs.cr2;
267   guest_state->cr3 = info->ctrl_regs.cr3;
268   guest_state->cr4 = info->ctrl_regs.cr4;
269   guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
270   guest_state->rflags = info->ctrl_regs.rflags;
271
272
273   guest_state->cpl = info->cpl;
274
275   guest_state->rax = info->vm_regs.rax;
276   guest_state->rip = info->rip;
277   guest_state->rsp = info->vm_regs.rsp;
278
279
280   set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
281
282   if (exit_code == VMEXIT_INTR) {
283     PrintDebug("INTR ret IP = %x\n", guest_state->rip);
284   }
285
286   return 0;
287 }
288