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.


*** empty log message ***
[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   } else {
92     PrintDebug("io_info Invalid Size\n");
93     return -1;
94   }
95
96   
97   if (io_info->addr16) {
98     mask = 0xffff;
99   } else if (io_info->addr32) {
100     mask = 0xffffffff;
101   } else if (io_info->addr64) {
102     mask = 0xffffffffffffffffLL;
103   } else {
104     // This value should be set depending on the host register size...
105     mask = get_gpr_mask(info);
106   }
107
108   if (io_info->rep) {
109     //    rep_num = info->vm_regs.rcx & mask;
110     rep_num = info->vm_regs.rcx;
111   }
112
113
114   PrintDebug("INS size=%d for %d steps\n", read_size, rep_num);
115
116   while (rep_num > 0) {
117     addr_t host_addr;
118     dst_addr = get_addr_linear(info, info->vm_regs.rdi & mask, &(info->segments.es));
119     
120     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
121       // either page fault or gpf...
122       PrintDebug("Could not convert Guest VA to host VA\n");
123       return -1;
124     }
125
126     if (hook->read(io_info->port, (char*)host_addr, read_size, hook->priv_data) != read_size) {
127       // not sure how we handle errors.....
128       PrintDebug("Read Failure for ins on port %x\n", io_info->port);
129       return -1;
130     }
131
132     info->vm_regs.rdi += read_size * direction;
133
134     if (io_info->rep)
135       info->vm_regs.rcx--;
136     
137     rep_num--;
138   }
139
140
141   info->rip = ctrl_area->exit_info2;
142
143   return 0;
144 }
145
146 int handle_svm_io_out(struct guest_info * info) {
147   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
148   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
149   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
150
151   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
152   uint_t write_size = 0;
153
154   if (hook == NULL) {
155     PrintDebug("Hook Not present for out on port %x\n", io_info->port);
156     // error, we should not have exited on this port
157     return -1;
158   }
159
160   PrintDebug("OUT on  port %d (0x%x)\n", io_info->port, io_info->port);
161
162   if (io_info->sz8) { 
163     write_size = 1;
164   } else if (io_info->sz16) {
165     write_size = 2;
166   } else if (io_info->sz32) {
167     write_size = 4;
168   }
169
170
171   if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
172     // not sure how we handle errors.....
173     PrintDebug("Write Failure for out on port %x\n", io_info->port);
174     return -1;
175   }
176
177   info->rip = ctrl_area->exit_info2;
178
179   return 0;
180 }
181
182
183 /* We might not handle wrap around of the RSI register correctly...
184  * In that if we do wrap around the effect will manifest in the higher bits of the register
185  */
186
187 int handle_svm_io_outs(struct guest_info * info) {
188   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
189   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
190   
191   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
192   
193   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
194   uint_t write_size = 0;
195
196   addr_t dst_addr = 0;
197   uint_t rep_num = 1;
198   ullong_t mask = 0;
199
200
201
202   // This is kind of hacky...
203   // direction can equal either 1 or -1
204   // We will multiply the final added offset by this value to go the correct direction
205   int direction = 1;
206   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
207   if (flags->df) {
208     direction = -1;
209   }
210
211
212   if (hook == NULL) {
213     PrintDebug("Hook Not present for outs on port %x\n", io_info->port);
214     // error, we should not have exited on this port
215     return -1;
216   }
217
218   PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
219
220   if (io_info->sz8) { 
221     write_size = 1;
222   } else if (io_info->sz16) {
223     write_size = 2;
224   } else if (io_info->sz32) {
225     write_size = 4;
226   }
227
228
229   if (io_info->addr16) {
230     mask = 0xffff;
231   } else if (io_info->addr32) {
232     mask = 0xffffffff;
233   } else if (io_info->addr64) {
234     mask = 0xffffffffffffffffLL;
235   } else {
236     // should never happen
237     PrintDebug("Invalid Address length\n");
238     return -1;
239   }
240
241   if (io_info->rep) {
242     rep_num = info->vm_regs.rcx & mask;
243   }
244
245
246   while (rep_num > 0) {
247     addr_t host_addr;
248     dst_addr = get_addr_linear(info, (info->vm_regs.rsi & mask), &(info->segments.ds));
249     
250     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
251       // either page fault or gpf...
252     }
253
254     if (hook->write(io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
255       // not sure how we handle errors.....
256       PrintDebug("Write Failure for outs on port %x\n", io_info->port);
257       return -1;
258     }
259
260     info->vm_regs.rsi += write_size * direction;
261
262     if (io_info->rep)
263       info->vm_regs.rcx--;
264     
265     rep_num--;
266   }
267
268
269   info->rip = ctrl_area->exit_info2;
270
271
272   return 0;
273 }