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