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.


reworked the generic device to handle run time configurability
[palacios.git] / palacios / src / devices / generic.c
1 /* (c) 2008, Peter Dinda <pdinda@northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
3
4
5 #include <devices/generic.h>
6 #include <palacios/vmm.h>
7 #include <palacios/vmm_types.h>
8 #include <palacios/vmm_list.h>
9
10
11
12 #ifndef DEBUG_GENERIC
13 #undef PrintDebug
14 #define PrintDebug(fmt, args...)
15 #endif
16
17
18 #define PORT_HOOKS 1
19 #define MEM_HOOKS  0   // not yet implmented in device model
20 #define IRQ_HOOKS  0   // not yet implemented in device model
21
22
23 struct generic_internal {
24   struct list_head port_range;
25   uint_t num_port_ranges;
26   struct list_head mem_range;
27   uint_t num_mem_ranges;
28   struct list_head irq_range;
29   uint_t num_irq_ranges;
30 };
31
32
33 struct port_range {
34   uint_t start;
35   uint_t end;
36   uint_t type;
37   struct list_head range_list;
38 };
39
40 struct mem_range {
41   void * start;
42   void * end;
43   uint_t type;
44   struct list_head range_list;
45 };
46
47 struct irq_range {
48   uint_t start;
49   uint_t end;
50   uint_t type;
51   struct list_head range_list;
52 };
53
54
55
56 int generic_reset_device(struct vm_device * dev)
57 {
58   PrintDebug("generic: reset device\n");
59  
60   return 0;
61
62 }
63
64
65
66
67
68 int generic_start_device(struct vm_device * dev)
69 {
70   PrintDebug("generic: start device\n");
71   return 0;
72 }
73
74
75 int generic_stop_device(struct vm_device * dev)
76 {
77   PrintDebug("generic: stop device\n");
78   return 0;
79 }
80
81
82
83
84 int generic_write_port_passthrough(ushort_t port,
85                                    void * src, 
86                                    uint_t length,
87                                    struct vm_device * dev)
88 {
89   uint_t i;
90
91   PrintDebug("generic: writing 0x");
92
93   for (i = 0; i < length; i++) { 
94     PrintDebug("%x", ((uchar_t*)src)[i]);
95   }
96   
97   PrintDebug(" to port 0x%x ... ", port);
98
99
100   switch (length) {
101   case 1:
102
103     v3_outb(port,((uchar_t*)src)[0]);
104     break;
105   case 2:
106     v3_outw(port,((ushort_t*)src)[0]);
107     break;
108   case 4:
109     v3_outdw(port,((uint_t*)src)[0]);
110
111     break;
112   default:
113     for (i = 0; i < length; i++) { 
114       v3_outb(port, ((uchar_t*)src)[i]);
115     }
116   } //switch length
117
118
119   PrintDebug(" done\n");
120   
121   return length;
122 }
123
124 int generic_read_port_passthrough(ushort_t port,
125                                   void * src, 
126                                   uint_t length,
127                                   struct vm_device * dev)
128 {
129   uint_t i;
130
131   PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
132
133
134     switch (length) {
135     case 1:
136       ((uchar_t*)src)[0] = v3_inb(port);
137       break;
138     case 2:
139       ((ushort_t*)src)[0] = v3_inw(port);
140       break;
141     case 4:
142       ((uint_t*)src)[0] = v3_indw(port);
143       break;
144     default:
145       for (i = 0; i < length; i++) { 
146         ((uchar_t*)src)[i] = v3_inb(port);
147       }
148     }//switch length
149
150   PrintDebug(" done ... read 0x");
151
152   for (i = 0; i < length; i++) { 
153     PrintDebug("%x", ((uchar_t*)src)[i]);
154   }
155
156   PrintDebug("\n");
157
158   return length;
159 }
160
161 int generic_write_port_ignore(ushort_t port,
162                               void * src, 
163                               uint_t length,
164                               struct vm_device * dev)
165 {
166   uint_t i;
167
168   PrintDebug("generic: writing 0x");
169
170   for (i = 0; i < length; i++) { 
171     PrintDebug("%x", ((uchar_t*)src)[i]);
172   }
173   
174   PrintDebug(" to port 0x%x ... ignored\n", port);
175  
176   return length;
177 }
178
179 int generic_read_port_ignore(ushort_t port,
180                              void * src, 
181                              uint_t length,
182                              struct vm_device * dev)
183 {
184
185   PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
186
187   memset((char*)src, 0, length);
188   PrintDebug(" ignored (return zeroed buffer)\n");
189
190   return length;
191 }
192
193
194
195 int generic_interrupt(uint_t irq, struct vm_device * dev) {
196   PrintDebug("generic: interrupt 0x%x - injecting into VM\n", irq);
197
198   dev->vm->vm_ops.raise_irq(dev->vm, irq);
199
200   return 0;
201 }
202
203
204 int generic_init_device(struct vm_device * dev) {
205   struct generic_internal * state = (struct generic_internal *)(dev->private_data);
206
207   PrintDebug("generic: init_device\n");
208   generic_reset_device(dev);
209
210
211   if (PORT_HOOKS) { // This is a runtime conditional on a #define
212     struct port_range * tmp;
213
214     list_for_each_entry(tmp, &(state->port_range), range_list) {
215       uint_t i = 0;
216       
217       PrintDebug("generic: hooking ports 0x%x to 0x%x as %x\n", 
218                  tmp->start, tmp->end, 
219                  (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
220       
221       for (i = tmp->start; i <= tmp->end; i++) { 
222         if (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) { 
223           
224           if (dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough)) { 
225             PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
226           }
227           
228         } else if (tmp->type == GENERIC_PRINT_AND_IGNORE) { 
229           
230           if (dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore)) { 
231             PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
232           }
233         } 
234       }
235
236     }
237   } else {
238     PrintDebug("generic: hooking ports not supported\n");
239   }
240
241
242
243   if (MEM_HOOKS) { // This is a runtime conditional on a #define
244     struct mem_range * tmp;
245
246     list_for_each_entry(tmp, &(state->mem_range), range_list) {
247
248       PrintDebug("generic: hooking addresses 0x%x to 0x%x\n", 
249                  tmp->start, tmp->end); 
250       
251       
252       if (dev_hook_mem(dev, tmp->start, tmp->end)) {
253         PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
254                    tmp->start, tmp->end); 
255       }
256     }
257   } else {
258     PrintDebug("generic: hooking addresses not supported\n");
259   }
260
261
262
263
264   if (IRQ_HOOKS) { // This is a runtime conditional on a #define
265     struct irq_range * tmp;
266     
267     list_for_each_entry(tmp, &(state->irq_range), range_list) {
268       uint_t i;
269
270       PrintDebug("generic: hooking irqs 0x%x to 0x%x\n",
271                  tmp->start, tmp->end);
272       
273       for (i = tmp->start; i <= tmp->end; i++) { 
274         if (dev_hook_irq(dev, i, &generic_interrupt)) { 
275           PrintDebug("generic: can't hook irq  0x%x (already hooked?)\n", i);
276         }
277       }
278
279     }
280   } else {
281     PrintDebug("generic: hooking irqs not supported\n");
282   }
283
284
285
286   return 0;
287 }
288
289 int generic_deinit_device(struct vm_device * dev) {
290   struct generic_internal * state = (struct generic_internal *)(dev->private_data);
291
292
293   PrintDebug("generic: deinit_device\n");
294
295
296   if (IRQ_HOOKS) { // This is a runtime conditional on a #define
297     struct irq_range * tmp;
298     struct irq_range * cur;
299     
300     list_for_each_entry_safe(cur, tmp, &(state->irq_range), range_list) {
301       uint_t i;
302
303       PrintDebug("generic: unhooking irqs 0x%x to 0x%x\n", 
304                  cur->start, cur->end);
305       
306
307       for (i = cur->start; i <= cur->end; i++) { 
308         if (dev_unhook_irq(dev, i)) {
309           PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n", i);
310         }
311       }
312
313       V3_Free(cur);
314     }
315   } else {
316     PrintDebug("generic: unhooking irqs not supported\n");
317   }
318
319
320   if (MEM_HOOKS) {
321     struct mem_range * tmp;
322     struct mem_range * cur;
323     
324     list_for_each_entry_safe(cur, tmp, &(state->mem_range), range_list) {
325
326       PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
327                  cur->start, cur->end); 
328
329       if (dev_unhook_mem(dev, cur->start, cur->end)) {
330         PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
331                    cur->start, cur->end); 
332       }
333
334       V3_Free(cur);
335     }
336   } else {
337     PrintDebug("generic: unhooking addresses not supported\n");
338   }
339   
340
341   if (PORT_HOOKS) {
342     struct port_range * tmp;
343     struct port_range * cur;
344     
345     list_for_each_entry_safe(cur, tmp, &(state->mem_range), range_list) {
346       uint_t i;
347
348       PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
349                    cur->start, cur->end);
350                 
351       for (i = cur->start; i <= cur->end; i++) {
352         if (dev_unhook_io(dev, i)) {
353           PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
354         }
355       }
356
357       V3_Free(cur);
358     }
359   } else {
360     PrintDebug("generic: unhooking ports not supported\n");
361   }
362
363
364
365   generic_reset_device(dev);
366   return 0;
367 }
368
369
370
371
372
373 static struct vm_device_ops dev_ops = { 
374   .init = generic_init_device, 
375   .deinit = generic_deinit_device,
376   .reset = generic_reset_device,
377   .start = generic_start_device,
378   .stop = generic_stop_device,
379 };
380
381
382
383
384 int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
385
386   if (PORT_HOOKS) {
387     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
388
389     struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
390     range->start = start;
391     range->end = end;
392     range->type = type;
393     
394     list_add(&(state->port_range), &(range->range_list));
395     state->num_port_ranges++;
396   } else {
397     PrintDebug("generic: hooking IO ports not supported\n");
398     return -1;
399   }
400
401   return 0;
402 }
403
404 int v3_generic_add_mem_range(struct vm_device * dev, void * start, void * end, uint_t type) {
405
406   if (MEM_HOOKS) {
407     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
408     
409     struct mem_range * range = (struct mem_range *)V3_Malloc(sizeof(struct mem_range));
410     range->start = start;
411     range->end = end;
412     range->type = type;
413     
414     list_add(&(state->port_range), &(range->range_list));
415     state->num_mem_ranges++;
416   } else {
417     PrintDebug("generic: hooking memory not supported\n");
418     return -1;
419   }
420
421   return 0;
422 }
423
424
425 int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
426
427   if (IRQ_HOOKS) {
428     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
429     
430     struct irq_range * range = (struct irq_range *)V3_Malloc(sizeof(struct irq_range));
431     range->start = start;
432     range->end = end;
433     range->type = type;
434     
435     list_add(&(state->port_range), &(range->range_list));
436     state->num_irq_ranges++;
437   } else {
438     PrintDebug("generic: hooking IRQs not supported\n");
439     return -1;
440   }
441
442   return 0;
443 }
444
445
446
447 struct vm_device *create_generic() {
448   struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
449   
450   generic_state->num_port_ranges = 0;
451   generic_state->num_mem_ranges = 0;
452   generic_state->num_irq_ranges = 0;
453
454   INIT_LIST_HEAD(&(generic_state->port_range));
455   INIT_LIST_HEAD(&(generic_state->mem_range));
456   INIT_LIST_HEAD(&(generic_state->irq_range));
457     
458   struct vm_device * device = create_device("GENERIC", &dev_ops, generic_state);
459
460   return device;
461 }