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.


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