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.


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