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 invlpg support
[palacios.git] / palacios / src / palacios / svm_io.c
1 #include <palacios/svm_io.h>
2 #include <palacios/vmm_io.h>
3 #include <palacios/vmm_ctrl_regs.h>
4 #include <palacios/vmm_emulate.h>
5 #include <palacios/vm_guest_mem.h>
6
7
8 // This should package up an IO request and call vmm_handle_io
9 int handle_svm_io_in(struct guest_info * info) {
10   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
11   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
12   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
13
14   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
15   uint_t read_size = 0;
16
17   if (hook == NULL) {
18     PrintDebug("Hook Not present for in on port %x\n", io_info->port);
19     // error, we should not have exited on this port
20     return -1;
21   }
22
23   //PrintDebug("IN on  port %d (0x%x)\n", io_info->port, io_info->port);
24
25   if (io_info->sz8) { 
26     read_size = 1;
27   } else if (io_info->sz16) {
28     read_size = 2;
29   } else if (io_info->sz32) {
30     read_size = 4;
31   }
32
33
34   if (hook->read(io_info->port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) {
35     // not sure how we handle errors.....
36     PrintDebug("Read Failure for in on port %x\n", io_info->port);
37     return -1;
38   }
39
40   info->rip = ctrl_area->exit_info2;
41
42   return 0;
43 }
44
45
46
47
48
49 /* We might not handle wrap around of the RDI register correctly...
50  * In that if we do wrap around the effect will manifest in the higher bits of the register
51  */
52 int handle_svm_io_ins(struct guest_info * info) {
53   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
54   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
55   
56   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
57   
58   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
59   uint_t read_size = 0;
60
61   addr_t dst_addr = 0;
62   uint_t rep_num = 1;
63   ullong_t mask = 0;
64
65
66
67   // This is kind of hacky...
68   // direction can equal either 1 or -1
69   // We will multiply the final added offset by this value to go the correct direction
70   int direction = 1;
71   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
72   if (flags->df) {
73     direction = -1;
74   }
75
76
77   if (hook == NULL) {
78    PrintDebug("Hook Not present for ins on port %x\n", io_info->port);
79     // error, we should not have exited on this port
80     return -1;
81   }
82
83   //PrintDebug("INS on  port %d (0x%x)\n", io_info->port, io_info->port);
84
85   if (io_info->sz8) { 
86     read_size = 1;
87   } else if (io_info->sz16) {
88     read_size = 2;
89   } else if (io_info->sz32) {
90     read_size = 4;
91   }
92
93
94   if (io_info->addr16) {
95     mask = 0xffff;
96   } else if (io_info->addr32) {
97     mask = 0xffffffff;
98   } else if (io_info->addr64) {
99     mask = 0xffffffffffffffffLL;
100   } else {
101     // should never happen
102     return -1;
103   }
104
105   if (io_info->rep) {
106     rep_num = info->vm_regs.rcx & mask;
107   }
108
109
110
111   while (rep_num > 0) {
112     addr_t host_addr;
113     dst_addr = get_addr_linear(info, info->vm_regs.rdi & mask, &(info->segments.es));
114     
115     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
116       // either page fault or gpf...
117     }
118
119     if (hook->read(io_info->port, (char*)host_addr, read_size, hook->priv_data) != read_size) {
120       // not sure how we handle errors.....
121       PrintDebug("Read Failure for ins on port %x\n", io_info->port);
122       return -1;
123     }
124
125     info->vm_regs.rdi += read_size * direction;
126
127     if (io_info->rep)
128       info->vm_regs.rcx--;
129     
130     rep_num--;
131   }
132
133
134   info->rip = ctrl_area->exit_info2;
135
136   return 0;
137 }
138
139 int handle_svm_io_out(struct guest_info * info) {
140   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
141   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
142   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
143
144   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
145   uint_t write_size = 0;
146
147   if (hook == NULL) {
148     PrintDebug("Hook Not present for out on port %x\n", io_info->port);
149     // error, we should not have exited on this port
150     return -1;
151   }
152
153   //PrintDebug("OUT on  port %d (0x%x)\n", io_info->port, io_info->port);
154
155   if (io_info->sz8) { 
156     write_size = 1;
157   } else if (io_info->sz16) {
158     write_size = 2;
159   } else if (io_info->sz32) {
160     write_size = 4;
161   }
162
163
164   if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
165     // not sure how we handle errors.....
166     PrintDebug("Write Failure for out on port %x\n", io_info->port);
167     return -1;
168   }
169
170   info->rip = ctrl_area->exit_info2;
171
172   return 0;
173 }
174
175
176 /* We might not handle wrap around of the RSI register correctly...
177  * In that if we do wrap around the effect will manifest in the higher bits of the register
178  */
179
180 int handle_svm_io_outs(struct guest_info * info) {
181   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
182   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
183   
184   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
185   
186   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
187   uint_t write_size = 0;
188
189   addr_t dst_addr = 0;
190   uint_t rep_num = 1;
191   ullong_t mask = 0;
192
193
194
195   // This is kind of hacky...
196   // direction can equal either 1 or -1
197   // We will multiply the final added offset by this value to go the correct direction
198   int direction = 1;
199   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
200   if (flags->df) {
201     direction = -1;
202   }
203
204
205   if (hook == NULL) {
206     PrintDebug("Hook Not present for outs on port %x\n", io_info->port);
207     // error, we should not have exited on this port
208     return -1;
209   }
210
211   //PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
212
213   if (io_info->sz8) { 
214     write_size = 1;
215   } else if (io_info->sz16) {
216     write_size = 2;
217   } else if (io_info->sz32) {
218     write_size = 4;
219   }
220
221
222   if (io_info->addr16) {
223     mask = 0xffff;
224   } else if (io_info->addr32) {
225     mask = 0xffffffff;
226   } else if (io_info->addr64) {
227     mask = 0xffffffffffffffffLL;
228   } else {
229     // should never happen
230     return -1;
231   }
232
233   if (io_info->rep) {
234     rep_num = info->vm_regs.rcx & mask;
235   }
236
237
238   while (rep_num > 0) {
239     addr_t host_addr;
240     dst_addr = get_addr_linear(info, (info->vm_regs.rsi & mask), &(info->segments.ds));
241     
242     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
243       // either page fault or gpf...
244     }
245
246     if (hook->write(io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
247       // not sure how we handle errors.....
248       PrintDebug("Write Failure for outs on port %x\n", io_info->port);
249       return -1;
250     }
251
252     info->vm_regs.rsi += write_size * direction;
253
254     if (io_info->rep)
255       info->vm_regs.rcx--;
256     
257     rep_num--;
258   }
259
260
261   info->rip = ctrl_area->exit_info2;
262
263
264   return 0;
265 }