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.


bug fixes to generic
[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_list;
25   uint_t num_port_ranges;
26   struct list_head mem_list;
27   uint_t num_mem_ranges;
28   struct list_head irq_list;
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_link;
38 };
39
40 struct mem_range {
41   void * start;
42   void * end;
43   uint_t type;
44   struct list_head range_link;
45 };
46
47 struct irq_range {
48   uint_t start;
49   uint_t end;
50   uint_t type;
51   struct list_head range_link;
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 = NULL;
213
214     list_for_each_entry(tmp, &(state->port_list), range_link) {
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_list), range_link) {
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_list), range_link) {
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_list), range_link) {
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       list_del(&(cur->range_link));
314       state->num_irq_ranges--;
315       V3_Free(cur);
316     }
317   } else {
318     PrintDebug("generic: unhooking irqs not supported\n");
319   }
320
321
322   if (MEM_HOOKS) {
323     struct mem_range * tmp;
324     struct mem_range * cur;
325     
326     list_for_each_entry_safe(cur, tmp, &(state->mem_list), range_link) {
327
328       PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
329                  cur->start, cur->end); 
330
331       if (dev_unhook_mem(dev, cur->start, cur->end)) {
332         PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
333                    cur->start, cur->end); 
334       }
335
336       list_del(&(cur->range_link));
337       state->num_mem_ranges--;
338       V3_Free(cur);
339     }
340   } else {
341     PrintDebug("generic: unhooking addresses not supported\n");
342   }
343   
344
345   if (PORT_HOOKS) {
346     struct port_range * tmp;
347     struct port_range * cur;
348     
349     list_for_each_entry_safe(cur, tmp, &(state->port_list), range_link) {
350       uint_t i;
351
352       PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
353                    cur->start, cur->end);
354                 
355       for (i = cur->start; i <= cur->end; i++) {
356         if (dev_unhook_io(dev, i)) {
357           PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
358         }
359       }
360
361       list_del(&(cur->range_link));
362       state->num_port_ranges--;
363       V3_Free(cur);
364     }
365   } else {
366     PrintDebug("generic: unhooking ports not supported\n");
367   }
368
369
370
371   generic_reset_device(dev);
372   return 0;
373 }
374
375
376
377
378
379 static struct vm_device_ops dev_ops = { 
380   .init = generic_init_device, 
381   .deinit = generic_deinit_device,
382   .reset = generic_reset_device,
383   .start = generic_start_device,
384   .stop = generic_stop_device,
385 };
386
387
388
389
390 int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
391
392   if (PORT_HOOKS) {
393     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
394
395     struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
396     range->start = start;
397     range->end = end;
398     range->type = type;
399     
400       
401     PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %x\n", 
402                range->start, range->end, 
403                (range->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
404     
405     list_add(&(range->range_link), &(state->port_list));
406     state->num_port_ranges++;
407   } else {
408     PrintDebug("generic: hooking IO ports not supported\n");
409     return -1;
410   }
411
412   return 0;
413 }
414
415 int v3_generic_add_mem_range(struct vm_device * dev, void * start, void * end, uint_t type) {
416
417   if (MEM_HOOKS) {
418     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
419     
420     struct mem_range * range = (struct mem_range *)V3_Malloc(sizeof(struct mem_range));
421     range->start = start;
422     range->end = end;
423     range->type = type;
424     
425     list_add(&(range->range_link), &(state->port_list));
426     state->num_mem_ranges++;
427   } else {
428     PrintDebug("generic: hooking memory not supported\n");
429     return -1;
430   }
431
432   return 0;
433 }
434
435
436 int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
437
438   if (IRQ_HOOKS) {
439     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
440     
441     struct irq_range * range = (struct irq_range *)V3_Malloc(sizeof(struct irq_range));
442     range->start = start;
443     range->end = end;
444     range->type = type;
445     
446     list_add(&(range->range_link), &(state->port_list));
447     state->num_irq_ranges++;
448   } else {
449     PrintDebug("generic: hooking IRQs not supported\n");
450     return -1;
451   }
452
453   return 0;
454 }
455
456
457
458 struct vm_device * create_generic() {
459   struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
460   
461   generic_state->num_port_ranges = 0;
462   generic_state->num_mem_ranges = 0;
463   generic_state->num_irq_ranges = 0;
464
465   INIT_LIST_HEAD(&(generic_state->port_list));
466   INIT_LIST_HEAD(&(generic_state->mem_list));
467   INIT_LIST_HEAD(&(generic_state->irq_list));
468     
469   struct vm_device * device = create_device("GENERIC", &dev_ops, generic_state);
470
471   return device;
472 }