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.


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