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