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.


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