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.


svm_io.c now correctly handles segment prefix overrides in ins/outs instructions.
[palacios.git] / palacios / src / devices / generic.c
1 #include <devices/generic.h>
2 #include <palacios/vmm.h>
3 #include <palacios/vmm_types.h>
4 #include <geekos/io.h>
5
6
7 #define GENERIC_DEBUG 1
8
9 #if GENERIC_DEBUG
10 #define GENERIC_DEBUG_PRINT(first, rest...) PrintDebug(first, ##rest) 
11 #else
12 #define GENERIC_DEBUG_PRINT(first, rest...)
13 #endif
14
15
16 #define PORT_HOOKS 1
17 #define MEM_HOOKS  0   // not yet implmented in device model
18 #define IRQ_HOOKS  0   // not yet implemented in device model
19
20 struct generic_internal {
21   generic_port_range_type    *port_ranges;
22   uint_t                     num_port_ranges;
23   generic_address_range_type *address_ranges;
24   uint_t                     num_address_ranges;
25   generic_irq_range_type     *irq_ranges;
26   uint_t                     num_irq_ranges;
27 };
28
29
30   
31     
32
33
34
35
36 int generic_reset_device(struct vm_device * dev)
37 {
38   GENERIC_DEBUG_PRINT("generic: reset device\n");
39  
40   return 0;
41
42 }
43
44
45
46
47
48 int generic_start_device(struct vm_device *dev)
49 {
50   GENERIC_DEBUG_PRINT("generic: start device\n");
51   return 0;
52 }
53
54
55 int generic_stop_device(struct vm_device *dev)
56 {
57   GENERIC_DEBUG_PRINT("generic: stop device\n");
58   return 0;
59 }
60
61
62
63
64 int generic_write_port_passthrough(ushort_t port,
65                                    void * src, 
66                                    uint_t length,
67                                    struct vm_device * dev)
68 {
69   uint_t i;
70
71   GENERIC_DEBUG_PRINT("generic: writing 0x");
72
73   for (i = 0; i < length; i++) { 
74     GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
75   }
76   
77   GENERIC_DEBUG_PRINT(" to port 0x%x ... ", port);
78
79   switch (length) {
80   case 1:
81     Out_Byte(port,((uchar_t*)src)[0]);
82     break;
83   case 2:
84     Out_Word(port,((ushort_t*)src)[0]);
85     break;
86   case 4:
87     Out_DWord(port,((uint_t*)src)[0]);
88     break;
89   default:
90     for (i = 0; i < length; i++) { 
91       Out_Byte(port, ((uchar_t*)src)[i]);
92     }
93   }
94
95   GENERIC_DEBUG_PRINT(" done\n");
96   
97   return length;
98 }
99
100 int generic_read_port_passthrough(ushort_t port,
101                                   void * src, 
102                                   uint_t length,
103                                   struct vm_device * dev)
104 {
105   uint_t i;
106
107   GENERIC_DEBUG_PRINT("generic: reading 0x%x bytes from port 0x%x ...", length, port);
108
109   switch (length) {
110   case 1:
111     ((uchar_t*)src)[0] = In_Byte(port);
112     break;
113   case 2:
114     ((ushort_t*)src)[0] = In_Word(port);
115     break;
116   case 4:
117     ((uint_t*)src)[0] = In_DWord(port);
118     break;
119   default:
120     for (i = 0; i < length; i++) { 
121       ((uchar_t*)src)[i] = In_Byte(port);
122     }
123   }
124
125   GENERIC_DEBUG_PRINT(" done ... read 0x");
126
127   for (i = 0; i < length; i++) { 
128     GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
129   }
130
131   GENERIC_DEBUG_PRINT("\n");
132
133   return length;
134 }
135
136 int generic_write_port_ignore(ushort_t port,
137                               void * src, 
138                               uint_t length,
139                               struct vm_device * dev)
140 {
141   uint_t i;
142
143   GENERIC_DEBUG_PRINT("generic: writing 0x");
144
145   for (i = 0; i < length; i++) { 
146     GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
147   }
148   
149   GENERIC_DEBUG_PRINT(" to port 0x%x ... ", port);
150
151   GENERIC_DEBUG_PRINT(" ignored\n");
152   
153   return length;
154 }
155
156 int generic_read_port_ignore(ushort_t port,
157                              void * src, 
158                              uint_t length,
159                              struct vm_device * dev)
160 {
161
162   GENERIC_DEBUG_PRINT("generic: reading 0x%x bytes from port 0x%x ...", length, port);
163
164   memset((char*)src,0,length);
165   GENERIC_DEBUG_PRINT(" ignored (return zeroed buffer)\n");
166
167   return length;
168 }
169
170
171
172 int generic_interrupt(uint_t irq,
173                       struct vm_device * dev) 
174 {
175   PrintDebug("generic: interrupt 0x%x - injecting into VM\n", irq);
176
177   dev->vm->vm_ops.raise_irq(dev->vm, irq);
178
179   return 0;
180
181 }
182
183
184 int generic_init_device(struct vm_device * dev) 
185 {
186   struct generic_internal *state = (struct generic_internal *)(dev->private_data);
187   uint_t i, j;
188
189   GENERIC_DEBUG_PRINT("generic: init_device\n");
190
191   // Would read state here
192
193   generic_reset_device(dev);
194
195   for (i = 0; i < state->num_port_ranges; i++) { 
196     GENERIC_DEBUG_PRINT("generic: hooking ports 0x%x to 0x%x as %x\n", state->port_ranges[i][0], state->port_ranges[i][1], state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH ? "print-and-passthrough" : "print-and-ignore");
197
198 #if PORT_HOOKS
199     for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) { 
200       if (state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH) { 
201         if (dev_hook_io(dev, j, &generic_read_port_passthrough, &generic_write_port_passthrough)) { 
202           GENERIC_DEBUG_PRINT("generic: can't hook port 0x%x (already hooked?)\n", j);
203         }
204       } else if (state->port_ranges[i][2]==GENERIC_PRINT_AND_IGNORE) { 
205         if (dev_hook_io(dev, j, &generic_read_port_ignore, &generic_write_port_ignore)) { 
206           GENERIC_DEBUG_PRINT("generic: can't hook port 0x%x (already hooked?)\n", j);
207         }
208       } 
209     }
210 #else
211     GENERIC_DEBUG_PRINT("generic: hooking ports not supported\n");
212 #endif
213
214   }
215
216   for (i = 0; i < state->num_address_ranges; i++) { 
217     GENERIC_DEBUG_PRINT("generic: hooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]); 
218
219 #if MEM_HOOKS
220     if (dev_hook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
221       GENERIC_DEBUG_PRINT("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
222                   state->address_ranges[i][0], state->address_ranges[i][1]); 
223     }
224 #else
225     GENERIC_DEBUG_PRINT("generic: hooking addresses not supported\n");
226 #endif
227
228   }
229
230   for (i = 0; i < state->num_irq_ranges; i++) { 
231     GENERIC_DEBUG_PRINT("generic: hooking irqs 0x%x to 0x%x\n",state->irq_ranges[i][0],state->irq_ranges[i][1]);
232
233 #if IRQ_HOOKS
234     for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) { 
235       if (dev_hook_irq(dev, j, &generic_interrupt)) { 
236         GENERIC_DEBUG_PRINT("generic: can't hook irq  0x%x (already hooked?)\n", j);
237       }
238     }
239 #else
240     GENERIC_DEBUG_PRINT("generic: hooking irqs not supported\n");
241 #endif
242
243   }
244
245   return 0;
246 }
247
248 int generic_deinit_device(struct vm_device *dev)
249 {
250   struct generic_internal *state = (struct generic_internal *)(dev->private_data);
251   uint_t i, j;
252
253   GENERIC_DEBUG_PRINT("generic: deinit_device\n");
254
255   for (i = 0; i < state->num_irq_ranges; i++) { 
256     GENERIC_DEBUG_PRINT("generic: unhooking irqs 0x%x to 0x%x\n", state->irq_ranges[i][0], state->irq_ranges[i][1]);
257
258 #if IRQ_HOOKS
259     for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) { 
260       if (dev_unhook_irq(dev, j)) {
261         GENERIC_DEBUG_PRINT("generic: can't unhook irq 0x%x (already unhooked?)\n",j);
262       }
263     }
264 #else
265     GENERIC_DEBUG_PRINT("generic: unhooking irqs not supported\n");
266 #endif
267
268   }
269
270   for (i = 0; i < state->num_address_ranges; i++) { 
271     GENERIC_DEBUG_PRINT("generic: unhooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]); 
272
273 #if MEM_HOOKS
274     if (dev_unhook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
275       GENERIC_DEBUG_PRINT("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
276                   state->address_ranges[i][0], state->address_ranges[i][1]); 
277     }
278 #else
279     GENERIC_DEBUG_PRINT("generic: unhooking addresses not supported\n");
280 #endif
281
282   }
283
284   for (i = 0; i < state->num_port_ranges; i++) { 
285     GENERIC_DEBUG_PRINT("generic: unhooking ports 0x%x to 0x%x\n",state->port_ranges[i][0],state->port_ranges[i][1]);
286
287 #if PORT_HOOKS
288     for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) { 
289       if (dev_unhook_io(dev, j)) {
290         GENERIC_DEBUG_PRINT("generic: can't unhook port 0x%x (already unhooked?)\n", j);
291       }
292     }
293 #else
294     GENERIC_DEBUG_PRINT("generic: unhooking ports not supported\n");
295 #endif
296
297   }
298
299   generic_reset_device(dev);
300   return 0;
301 }
302
303
304
305
306
307 static struct vm_device_ops dev_ops = { 
308   .init = generic_init_device, 
309   .deinit = generic_deinit_device,
310   .reset = generic_reset_device,
311   .start = generic_start_device,
312   .stop = generic_stop_device,
313 };
314
315
316
317
318 struct vm_device *create_generic(generic_port_range_type    port_ranges[], 
319                                  uint_t                     num_port_ranges,
320                                  generic_address_range_type address_ranges[],
321                                  uint_t                     num_address_ranges,
322                                  generic_irq_range_type     irq_ranges[],
323                                  uint_t                     num_irq_ranges)
324 {
325   struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
326
327
328   generic_state->num_port_ranges = num_port_ranges;
329
330   if (num_port_ranges > 0) { 
331     generic_state->port_ranges = V3_Malloc(sizeof(generic_address_range_type) * num_port_ranges);
332     memcpy(generic_state->port_ranges, port_ranges, sizeof(generic_port_range_type) * num_port_ranges);
333   } else {
334     generic_state->port_ranges = NULL;
335   }
336
337
338   generic_state->num_address_ranges = num_address_ranges;
339
340   if (num_address_ranges > 0) { 
341     generic_state->address_ranges = V3_Malloc(sizeof(generic_address_range_type) * num_address_ranges);
342     memcpy(generic_state->address_ranges, address_ranges, sizeof(generic_address_range_type) * num_address_ranges);
343   } else {
344     generic_state->address_ranges = NULL;
345   }
346
347
348   generic_state->num_irq_ranges = num_irq_ranges;
349
350   if (num_irq_ranges > 0) { 
351     generic_state->irq_ranges = V3_Malloc(sizeof(generic_address_range_type) * num_irq_ranges);
352     memcpy(generic_state->irq_ranges, irq_ranges, sizeof(generic_irq_range_type) * num_port_ranges);
353   } else {
354     generic_state->irq_ranges = NULL;
355   }
356
357
358   struct vm_device *device = create_device("GENERIC", &dev_ops, generic_state);
359
360   return device;
361 }