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