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.


quick fix for segmentation bug:
[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 = 0;
59   addr_t dst_addr = 0;
60   uint_t rep_num = 1;
61   ullong_t mask = 0;
62
63
64   if (info->cpu_mode == REAL) {
65     base_addr = (guest_state->es.base << 4);
66   } else if (info->cpu_mode == PROTECTED) {
67     base_addr = guest_state->es.base;
68   }
69
70
71   // This is kind of hacky...
72   // direction can equal either 1 or -1
73   // We will multiply the final added offset by this value to go the correct direction
74   int direction = 1;
75   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
76   if (flags->df) {
77     direction = -1;
78   }
79
80
81   if (hook == NULL) {
82     // error, we should not have exited on this port
83     return -1;
84   }
85
86   PrintDebug("INS on  port %d (0x%x)\n", io_info->port, io_info->port);
87
88   if (io_info->sz8) { 
89     read_size = 1;
90   } else if (io_info->sz16) {
91     read_size = 2;
92   } else if (io_info->sz32) {
93     read_size = 4;
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     // should never happen
105     return -1;
106   }
107
108   if (io_info->rep) {
109     rep_num = info->vm_regs.rcx & mask;
110   }
111
112
113
114   while (rep_num > 0) {
115     addr_t host_addr;
116     dst_addr = base_addr + (info->vm_regs.rdi & mask);
117     
118     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
119       // either page fault or gpf...
120     }
121
122     if (hook->read(io_info->port, (char*)host_addr, read_size) != read_size) {
123       // not sure how we handle errors.....
124       return -1;
125     }
126
127     info->vm_regs.rdi += read_size * direction;
128
129     if (io_info->rep)
130       info->vm_regs.rcx--;
131     
132     rep_num--;
133   }
134
135
136   info->rip = ctrl_area->exit_info2;
137
138   return 0;
139 }
140
141 int handle_svm_io_out(struct guest_info * info) {
142   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
143   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
144   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
145
146   vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port);
147   uint_t write_size = 0;
148
149   if (hook == NULL) {
150     // error, we should not have exited on this port
151     return -1;
152   }
153
154   PrintDebug("OUT on  port %d (0x%x)\n", io_info->port, io_info->port);
155
156   if (io_info->sz8) { 
157     write_size = 1;
158   } else if (io_info->sz16) {
159     write_size = 2;
160   } else if (io_info->sz32) {
161     write_size = 4;
162   }
163
164
165   if (hook->write(io_info->port, &(info->vm_regs.rax), write_size) != write_size) {
166     // not sure how we handle errors.....
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   addr_t base_addr = 0;
189   addr_t dst_addr = 0;
190   uint_t rep_num = 1;
191   ullong_t mask = 0;
192
193
194
195   if (info->cpu_mode == REAL) {
196     base_addr = (guest_state->ds.base << 4);
197   } else if (info->cpu_mode == PROTECTED) {
198     base_addr = guest_state->ds.base;
199   }
200
201   // This is kind of hacky...
202   // direction can equal either 1 or -1
203   // We will multiply the final added offset by this value to go the correct direction
204   int direction = 1;
205   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
206   if (flags->df) {
207     direction = -1;
208   }
209
210
211   if (hook == NULL) {
212     // error, we should not have exited on this port
213     return -1;
214   }
215
216   PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
217
218   if (io_info->sz8) { 
219     write_size = 1;
220   } else if (io_info->sz16) {
221     write_size = 2;
222   } else if (io_info->sz32) {
223     write_size = 4;
224   }
225
226
227   if (io_info->addr16) {
228     mask = 0xffff;
229   } else if (io_info->addr32) {
230     mask = 0xffffffff;
231   } else if (io_info->addr64) {
232     mask = 0xffffffffffffffffLL;
233   } else {
234     // should never happen
235     return -1;
236   }
237
238   if (io_info->rep) {
239     rep_num = info->vm_regs.rcx & mask;
240   }
241
242
243   while (rep_num > 0) {
244     addr_t host_addr;
245     dst_addr = base_addr + (info->vm_regs.rsi & mask);
246     
247     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
248       // either page fault or gpf...
249     }
250
251     if (hook->write(io_info->port, (char*)host_addr, write_size) != write_size) {
252       // not sure how we handle errors.....
253       return -1;
254     }
255
256     info->vm_regs.rsi += write_size * direction;
257
258     if (io_info->rep)
259       info->vm_regs.rcx--;
260     
261     rep_num--;
262   }
263
264
265   info->rip = ctrl_area->exit_info2;
266
267
268   return 0;
269
270
271
272 }