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.


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