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.


build fixes to merge the Palacios configuration parameters with Linux parameters.
[palacios.releases.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 <palacios/vmm.h>
23 #include <palacios/vmm_types.h>
24 #include <palacios/vmm_list.h>
25 #include <palacios/vmm_io.h>
26 #include <palacios/vmm_dev_mgr.h>
27 #include <palacios/vm_guest_mem.h>
28
29 #ifdef V3_CONFIG_HOST_DEVICE
30 #include <interfaces/vmm_host_dev.h>
31 #endif
32
33 #ifndef V3_CONFIG_DEBUG_GENERIC
34 #undef PrintDebug
35 #define PrintDebug(fmt, args...)
36 #endif
37
38 #define MAX_NAME      32
39 #define MAX_MEM_HOOKS 16
40
41 typedef enum {GENERIC_IGNORE, 
42               GENERIC_PASSTHROUGH, 
43               GENERIC_PRINT_AND_PASSTHROUGH, 
44               GENERIC_PRINT_AND_IGNORE} generic_mode_t;
45
46 struct generic_internal {
47     enum {GENERIC_PHYSICAL, GENERIC_HOST} forward_type;
48 #ifdef V3_CONFIG_HOST_DEVICE
49     v3_host_dev_t                         host_dev;
50 #endif
51     struct vm_device                      *dev; // me
52
53     char                                  name[MAX_NAME];
54     
55     uint32_t                              num_mem_hooks;
56     addr_t                                mem_hook[MAX_MEM_HOOKS];
57 };
58
59
60
61
62 static int generic_write_port_passthrough(struct guest_info * core, 
63                                           uint16_t port, 
64                                           void * src, 
65                                           uint_t length, 
66                                           void * priv_data) 
67 {
68     struct generic_internal *state = (struct generic_internal *) priv_data;
69     uint_t i;
70
71     switch (state->forward_type) { 
72         case GENERIC_PHYSICAL:
73             switch (length) {
74                 case 1:
75                     v3_outb(port, ((uint8_t *)src)[0]);
76                     break;
77                 case 2:
78                     v3_outw(port, ((uint16_t *)src)[0]);
79                     break;
80                 case 4:
81                     v3_outdw(port, ((uint32_t *)src)[0]);
82                     break;
83                 default:
84                     for (i = 0; i < length; i++) { 
85                         v3_outb(port, ((uint8_t *)src)[i]);
86                     }
87                     break;
88             }
89             return length;
90             break;
91 #ifdef V3_CONFIG_HOST_DEVICE
92         case GENERIC_HOST:
93             if (state->host_dev) { 
94                 return v3_host_dev_write_io(state->host_dev,port,src,length);
95             } else {
96                 return -1;
97             }
98             break;
99 #endif
100         default:
101             PrintError("generic (%s): unknown forwarding type\n", state->name);
102             return -1;
103             break;
104     }
105 }
106
107 static int generic_write_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
108                                                     uint_t length, void * priv_data) {
109     uint_t i;
110     int rc;
111
112 #ifdef V3_CONFIG_DEBUG_GENERIC
113     struct generic_internal *state = (struct generic_internal *) priv_data;
114 #endif
115
116     PrintDebug("generic (%s): writing 0x%x bytes to port 0x%x using %s ...", state->name,
117                length, port,
118                state->forward_type == GENERIC_PHYSICAL ? "physical" :
119                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
120
121     PrintDebug("generic (%s): writing 0x", state->name);
122
123     for (i = 0; i < length; i++) { 
124         PrintDebug("%x", ((uint8_t *)src)[i]);
125     }
126   
127     PrintDebug(" to port 0x%x ... ", port);
128
129     rc=generic_write_port_passthrough(core,port,src,length,priv_data);
130
131     PrintDebug(" done\n");
132   
133     return rc;
134 }
135
136 static int generic_read_port_passthrough(struct guest_info * core, 
137                                          uint16_t port, 
138                                          void * dst, 
139                                          uint_t length, 
140                                          void * priv_data) 
141 {
142     struct generic_internal *state = (struct generic_internal *) priv_data;
143
144     uint_t i;
145
146     switch (state->forward_type) { 
147         case GENERIC_PHYSICAL:
148             switch (length) {
149                 case 1:
150                     ((uint8_t *)dst)[0] = v3_inb(port);
151                     break;
152                 case 2:
153                     ((uint16_t *)dst)[0] = v3_inw(port);
154                     break;
155                 case 4:
156                     ((uint32_t *)dst)[0] = v3_indw(port);
157                     break;
158                 default:
159                     for (i = 0; i < length; i++) { 
160                         ((uint8_t *)dst)[i] = v3_inb(port);
161                     }
162             }
163             return length;
164             break;
165 #ifdef V3_CONFIG_HOST_DEVICE
166         case GENERIC_HOST:
167             if (state->host_dev) { 
168                 return v3_host_dev_read_io(state->host_dev,port,dst,length);
169             }
170             break;
171 #endif
172         default:
173             PrintError("generic (%s): unknown forwarding type\n", state->name);
174             return -1;
175             break;
176     }
177
178     return -1;
179 }
180
181 static int generic_read_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
182                                                    uint_t length, void * priv_data) {
183     uint_t i;
184     int rc;
185
186 #ifdef V3_CONFIG_DEBUG_GENERIC
187     struct generic_internal *state = (struct generic_internal *) priv_data;
188 #endif
189
190     PrintDebug("generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
191                state->forward_type == GENERIC_PHYSICAL ? "physical" :
192                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
193
194
195     rc=generic_read_port_passthrough(core,port,src,length,priv_data);
196
197     PrintDebug(" done ... read 0x");
198
199     for (i = 0; i < rc; i++) { 
200         PrintDebug("%x", ((uint8_t *)src)[i]);
201     }
202
203     PrintDebug("\n");
204
205     return rc;
206 }
207
208
209 static int generic_read_port_ignore(struct guest_info * core, uint16_t port, void * src, 
210                                     uint_t length, void * priv_data) {
211
212     memset((uint8_t *)src, 0, length);
213
214     return length;
215 }
216
217 static int generic_read_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
218                                               uint_t length, void * priv_data) {
219    
220 #ifdef V3_CONFIG_DEBUG_GENERIC
221     struct generic_internal *state = (struct generic_internal *) priv_data;
222 #endif
223
224     PrintDebug("generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
225                state->forward_type == GENERIC_PHYSICAL ? "physical" :
226                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
227
228
229     memset((uint8_t *)src, 0, length);
230     PrintDebug(" ignored (return zeroed buffer)\n");
231
232     return length;
233 }
234
235 static int generic_write_port_ignore(struct guest_info * core, uint16_t port, void * src, 
236                                      uint_t length, void * priv_data) {
237
238     return length;
239 }
240
241 static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
242                                               uint_t length, void * priv_data) {
243     int i;
244
245 #ifdef V3_CONFIG_DEBUG_GENERIC
246     struct generic_internal *state = (struct generic_internal *) priv_data;
247 #endif
248
249     PrintDebug("generic (%s): writing 0x%x bytes to port 0x%x using %s ", state->name, length, port,
250                state->forward_type == GENERIC_PHYSICAL ? "physical" :
251                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
252     
253     memset((uint8_t *)src, 0, length);
254     PrintDebug(" ignored - data was: 0x");
255
256     for (i = 0; i < length; i++) { 
257         PrintDebug("%x", ((uint8_t *)src)[i]);
258     }
259     
260     PrintDebug("\n");
261
262     return length;
263 }
264
265
266
267 static int generic_write_mem_passthrough(struct guest_info * core, 
268                                          addr_t              gpa,
269                                          void              * src,
270                                          uint_t              len,
271                                          void              * priv)
272 {
273     struct vm_device *dev = (struct vm_device *) priv;
274     struct generic_internal *state = (struct generic_internal *) dev->private_data;
275     
276     switch (state->forward_type) { 
277         case GENERIC_PHYSICAL:
278             memcpy(V3_VAddr((void*)gpa),src,len);
279             return len;
280             break;
281 #ifdef V3_CONFIG_HOST_DEVICE
282         case GENERIC_HOST:
283             if (state->host_dev) { 
284                 return v3_host_dev_write_mem(state->host_dev,gpa,src,len);
285             } else {
286                 return -1;
287             }
288             break;
289 #endif
290         default:
291             PrintError("generic (%s): unknown forwarding type\n", state->name);
292             return -1;
293             break;
294     }
295 }
296
297 static int generic_write_mem_print_and_passthrough(struct guest_info * core, 
298                                                    addr_t              gpa,
299                                                    void              * src,
300                                                    uint_t              len,
301                                                    void              * priv)
302 {
303 #ifdef V3_CONFIG_DEBUG_GENERIC
304     struct vm_device *dev = (struct vm_device *) priv;
305     struct generic_internal *state = (struct generic_internal *) dev->private_data;
306 #endif
307
308     PrintDebug("generic (%s): writing %u bytes to GPA 0x%p via %s ... ", state->name,
309                len,(void*)gpa,
310                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
311                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
312     
313     int rc = generic_write_mem_passthrough(core,gpa,src,len,priv);
314
315     PrintDebug("done\n");
316     
317     return rc;
318 }
319
320 static int generic_write_mem_ignore(struct guest_info * core, 
321                                     addr_t              gpa,
322                                     void              * src,
323                                     uint_t              len,
324                                     void              * priv)
325 {
326     return len;
327 }
328
329 static int generic_write_mem_print_and_ignore(struct guest_info * core, 
330                                               addr_t              gpa,
331                                               void              * src,
332                                               uint_t              len,
333                                               void              * priv)
334 {
335 #ifdef V3_CONFIG_DEBUG_GENERIC
336     struct vm_device *dev = (struct vm_device *) priv;
337     struct generic_internal *state = (struct generic_internal *) dev->private_data;
338 #endif
339
340     PrintDebug("generic (%s): ignoring write of %u bytes to GPA 0x%p via %s", state->name,
341                len,(void*)gpa,
342                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
343                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
344     
345     return len;
346 }
347
348 static int generic_read_mem_passthrough(struct guest_info * core, 
349                                         addr_t              gpa,
350                                         void              * dst,
351                                         uint_t              len,
352                                         void              * priv)
353 {
354     struct vm_device *dev = (struct vm_device *) priv;
355     struct generic_internal *state = (struct generic_internal *) dev->private_data;
356     
357     switch (state->forward_type) { 
358         case GENERIC_PHYSICAL:
359             memcpy(dst,V3_VAddr((void*)gpa),len);
360             return len;
361             break;
362 #ifdef V3_CONFIG_HOST_DEVICE
363         case GENERIC_HOST:
364             if (state->host_dev) { 
365                 return v3_host_dev_read_mem(state->host_dev,gpa,dst,len);
366             } else {
367                 return -1;
368             }
369             break;
370 #endif
371         default:
372             PrintError("generic (%s): unknown forwarding type\n", state->name);
373             break;
374     }
375     
376     return -1;
377 }
378
379 static int generic_read_mem_print_and_passthrough(struct guest_info * core, 
380                                                   addr_t              gpa,
381                                                   void              * dst,
382                                                   uint_t              len,
383                                                   void              * priv)
384 {
385 #ifdef V3_CONFIG_DEBUG_GENERIC
386     struct vm_device *dev = (struct vm_device *) priv;
387     struct generic_internal *state = (struct generic_internal *) dev->private_data;
388 #endif
389
390     PrintDebug("generic (%s): attempting to read %u bytes from GPA 0x%p via %s ... ", state->name,
391                len,(void*)gpa,
392                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
393                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
394     
395     int rc = generic_read_mem_passthrough(core,gpa,dst,len,priv);
396
397     PrintDebug("done - read %d bytes\n", rc);
398     
399     return rc;
400 }
401
402 static int generic_read_mem_ignore(struct guest_info * core, 
403                                    addr_t              gpa,
404                                    void              * dst,
405                                    uint_t              len,
406                                    void              * priv)
407 {
408 #ifdef V3_CONFIG_DEBUG_GENERIC
409     struct vm_device *dev = (struct vm_device *) priv;
410     struct generic_internal *state = (struct generic_internal *) dev->private_data;
411 #endif
412
413     PrintDebug("generic (%s): ignoring attempt to read %u bytes from GPA 0x%p via %s ... ", state->name,
414                len,(void*)gpa,
415                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
416                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
417
418     memset((uint8_t *)dst, 0, len);
419
420     PrintDebug("returning zeros\n");
421
422     return len;
423 }
424
425
426 static int generic_read_mem_print_and_ignore(struct guest_info * core, 
427                                              addr_t              gpa,
428                                              void              * dst,
429                                              uint_t              len,
430                                              void              * priv)
431 {
432     memset((uint8_t *)dst, 0, len);
433     return len;
434 }
435
436
437 static int generic_free(struct generic_internal * state) {
438     int i;
439     
440     PrintDebug("generic (%s): deinit_device\n", state->name);
441     
442 #ifdef V3_CONFIG_HOST_DEVICE
443     if (state->host_dev) { 
444         v3_host_dev_close(state->host_dev);
445         state->host_dev=0;
446     }
447 #endif
448     
449     // Note that the device manager handles unhooking the I/O ports
450     // We need to handle unhooking memory regions    
451     for (i=0;i<state->num_mem_hooks;i++) {
452         if (v3_unhook_mem(state->dev->vm,V3_MEM_CORE_ANY,state->mem_hook[i])<0) { 
453             PrintError("generic (%s): unable to unhook memory starting at 0x%p\n", state->name,(void*)(state->mem_hook[i]));
454             return -1;
455         }
456     }
457              
458     V3_Free(state);
459     return 0;
460 }
461
462
463
464
465
466 static struct v3_device_ops dev_ops = { 
467     .free = (int (*)(void *))generic_free, 
468 };
469
470
471
472
473 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
474     uint_t i = 0;
475
476     struct generic_internal *state = (struct generic_internal *) dev->private_data;
477
478     PrintDebug("generic (%s): adding port range 0x%x to 0x%x as %s\n", state->name,
479                start, end, 
480                (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : 
481                (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
482                (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
483                (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
484         
485     for (i = start; i <= end; i++) { 
486         switch (mode) { 
487             case GENERIC_PRINT_AND_PASSTHROUGH:
488                 if (v3_dev_hook_io(dev, i, 
489                                    &generic_read_port_print_and_passthrough, 
490                                    &generic_write_port_print_and_passthrough) == -1) { 
491                     PrintError("generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
492                     return -1;
493                 }
494                 break;
495                 
496             case GENERIC_PRINT_AND_IGNORE:
497                 if (v3_dev_hook_io(dev, i, 
498                                    &generic_read_port_print_and_ignore, 
499                                    &generic_write_port_print_and_ignore) == -1) { 
500                     PrintError("generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
501                     return -1;
502                 }
503                 break;
504             case GENERIC_PASSTHROUGH:
505                 if (v3_dev_hook_io(dev, i, 
506                                    &generic_read_port_passthrough, 
507                                    &generic_write_port_passthrough) == -1) { 
508                     PrintError("generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
509                     return -1;
510                 }
511                 break;
512             case  GENERIC_IGNORE:
513                 if (v3_dev_hook_io(dev, i, 
514                                    &generic_read_port_ignore, 
515                                    &generic_write_port_ignore) == -1) { 
516                     PrintError("generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
517                     return -1;
518                 }
519                 break;
520             default:
521                 PrintError("generic (%s): huh?\n", state->name);
522                 break;
523         }
524     }
525     
526     return 0;
527 }
528
529
530 static int add_mem_range(struct vm_device * dev, addr_t start, addr_t end, generic_mode_t mode) {
531
532     struct generic_internal *state = (struct generic_internal *) dev->private_data;
533
534     PrintDebug("generic (%s): adding memory range 0x%p to 0x%p as %s\n", state->name,
535                (void*)start, (void*)end, 
536                (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : 
537                (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
538                (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
539                (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
540         
541     switch (mode) { 
542         case GENERIC_PRINT_AND_PASSTHROUGH:
543             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
544                                  &generic_read_mem_print_and_passthrough, 
545                                  &generic_write_mem_print_and_passthrough, dev) == -1) { 
546                 PrintError("generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
547                 return -1;
548             }
549             break;
550             
551         case GENERIC_PRINT_AND_IGNORE:
552             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
553                                  &generic_read_mem_print_and_ignore, 
554                                  &generic_write_mem_print_and_ignore, dev) == -1) { 
555                 PrintError("generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
556                 return -1;
557             }
558             break;
559
560         case GENERIC_PASSTHROUGH:
561             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
562                                  &generic_read_mem_passthrough, 
563                                  &generic_write_mem_passthrough, dev) == -1) { 
564                 PrintError("generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
565                 return -1;
566             }
567             break;
568
569         case  GENERIC_IGNORE:
570             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
571                                  &generic_read_mem_ignore, 
572                                  &generic_write_mem_ignore, dev) == -1) { 
573                 PrintError("generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
574                 return -1;
575             }
576             break;
577         default:
578             PrintError("generic (%s): huh?\n",state->name);
579             break;
580     }
581
582     return 0;
583 }
584
585
586
587 /*
588    The device can be used to forward to the underlying physical device 
589    or to a host device that has a given url.   Both memory and ports can be forwarded as
590
591         GENERIC_PASSTHROUGH => send writes and reads to physical device or host
592         GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
593
594         GENERIC_IGNORE => ignore writes and reads
595         GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
596
597
598         The purpose of the "PRINT" variants is to make it easy to spy on
599         device interactions (although you will not see DMA or interrupts)
600
601
602    <device class="generic" id="my_id" 
603          empty | forward="physical_device" or forward="host_device" host_device="url">
604
605   (empty implies physical_dev)
606
607      <ports>
608          <start>portno1</start>
609          <end>portno2</end>   => portno1 through portno2 (inclusive)
610          <mode>PRINT_AND_PASSTHROUGH</mode>  (as above)
611      </ports>
612
613      <memory>
614          <start>gpa1</start>
615          <end>gpa2</end>     => memory addreses gpa1 through gpa2 (inclusive); page granularity
616          <mode> ... as above </mode>
617      </memory>
618
619 */
620
621 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
622     struct generic_internal * state = NULL;
623     char * dev_id = v3_cfg_val(cfg, "ID");
624     char * forward = v3_cfg_val(cfg, "forward");
625 #ifdef V3_CONFIG_HOST_DEVICE
626     char * host_dev = v3_cfg_val(cfg, "hostdev");
627 #endif
628     v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
629     v3_cfg_tree_t * mem_cfg = v3_cfg_subtree(cfg, "memory");
630
631
632     state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
633
634     if (state == NULL) {
635         PrintError("generic (%s): could not allocate generic state\n",dev_id);
636         return -1;
637     }
638     
639     memset(state, 0, sizeof(struct generic_internal));
640     strncpy(state->name,dev_id,MAX_NAME);
641
642     if (!forward) { 
643         state->forward_type=GENERIC_PHYSICAL;
644     } else {
645         if (!strcasecmp(forward,"physical_device")) { 
646             state->forward_type=GENERIC_PHYSICAL;
647         } else if (!strcasecmp(forward,"host_device")) { 
648 #ifdef V3_CONFIG_HOST_DEVICE
649             state->forward_type=GENERIC_HOST;
650 #else
651             PrintError("generic (%s): cannot configure host device since host device support is not built in\n", state->name);
652             V3_Free(state);
653             return -1;
654 #endif
655         } else {
656             PrintError("generic (%s): unknown forwarding type \"%s\"\n", state->name, forward);
657             V3_Free(state);
658             return -1;
659         }
660     }
661     
662     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
663
664     if (dev == NULL) {
665         PrintError("generic: could not attach device %s\n", state->name);
666         V3_Free(state);
667         return -1;
668     }
669
670     state->dev=dev;
671
672
673 #ifdef V3_CONFIG_HOST_DEVICE
674     if (state->forward_type==GENERIC_HOST) { 
675         if (!host_dev) { 
676             PrintError("generic (%s): host forwarding requested, but no host device given\n", state->name);
677             v3_remove_device(dev);
678             return -1;
679         } else {
680             state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev,vm);
681             if (!(state->host_dev)) { 
682                 PrintError("generic (%s): unable to open host device \"%s\"\n", state->name,host_dev);
683                 v3_remove_device(dev);
684                 return -1;
685             } else {
686                 PrintDebug("generic (%s): successfully attached host device \"%s\"\n", state->name,host_dev);
687             }
688         }
689     }
690 #endif
691
692     PrintDebug("generic (%s): init_device\n", state->name);
693
694     // scan port list....
695     while (port_cfg) {
696         uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
697         uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
698         char * mode_str = v3_cfg_val(port_cfg, "mode");
699         generic_mode_t mode = GENERIC_IGNORE;
700         if (strcasecmp(mode_str, "print_and_ignore") == 0) {
701             mode = GENERIC_PRINT_AND_IGNORE;
702         } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
703             mode = GENERIC_PRINT_AND_PASSTHROUGH;
704         } else if (strcasecmp(mode_str, "passthrough") == 0) {
705             mode = GENERIC_PASSTHROUGH;
706         } else if (strcasecmp(mode_str, "ignore") == 0) {
707             mode = GENERIC_IGNORE;
708         } else {
709             PrintError("generic (%s): invalid mode %s in adding ports\n", state->name, mode_str);
710             v3_remove_device(dev);
711             return -1;
712         }
713         
714         
715         if (add_port_range(dev, start, end, mode) == -1) {
716             PrintError("generic (%s): could not add port range 0x%x to 0x%x\n", state->name, start, end);
717             v3_remove_device(dev);
718             return -1;
719         }
720
721         port_cfg = v3_cfg_next_branch(port_cfg);
722     }
723
724     // scan memory list....
725     while (mem_cfg) {
726         addr_t  start = atox(v3_cfg_val(mem_cfg, "start"));
727         addr_t end = atox(v3_cfg_val(mem_cfg, "end"));
728         char * mode_str = v3_cfg_val(mem_cfg, "mode");
729         generic_mode_t mode = GENERIC_IGNORE;
730
731         if (strcasecmp(mode_str, "print_and_ignore") == 0) {
732             mode = GENERIC_PRINT_AND_IGNORE;
733         } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
734             mode = GENERIC_PRINT_AND_PASSTHROUGH;
735         } else if (strcasecmp(mode_str, "passthrough") == 0) {
736             mode = GENERIC_PASSTHROUGH;
737         } else if (strcasecmp(mode_str, "ignore") == 0) {
738             mode = GENERIC_IGNORE;
739         } else {
740             PrintError("generic (%s): invalid mode %s for adding memory\n", state->name, mode_str);
741             v3_remove_device(dev);
742             return -1;
743         }
744
745         if (state->num_mem_hooks>=MAX_MEM_HOOKS) { 
746             PrintError("generic (%s): cannot add another memory hook (increase MAX_MEM_HOOKS)\n", state->name);
747             v3_remove_device(dev);
748             return -1;
749         }
750         
751         if (add_mem_range(dev, start, end, mode) == -1) {
752             PrintError("generic (%s): could not add memory range 0x%p to 0x%p\n", state->name, (void*)start, (void*)end);
753             v3_remove_device(dev);
754             return -1;
755         }
756         
757         state->mem_hook[state->num_mem_hooks] = start;
758         state->num_mem_hooks++;
759
760         mem_cfg = v3_cfg_next_branch(port_cfg);
761     }
762     
763     PrintDebug("generic (%s): initialization complete\n", state->name);
764
765     return 0;
766 }
767
768 device_register("GENERIC", generic_init)