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.


Update virtual NE2000
[palacios-OLD.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 %s\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%p to 0x%p\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%p to 0x%p (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%p to 0x%p\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%p to 0x%p (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 %s\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 }