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.


Generic device now supports host device interface (and memory hooks)
Peter Dinda [Thu, 14 Apr 2011 18:56:46 +0000 (13:56 -0500)]
palacios/src/devices/generic.c

index b7d1a18..a979df6 100644 (file)
 #include <palacios/vmm_list.h>
 #include <palacios/vmm_io.h>
 #include <palacios/vmm_dev_mgr.h>
+#include <palacios/vm_guest_mem.h>
+
+#ifdef CONFIG_HOST_DEVICE
+#include <interfaces/vmm_host_dev.h>
+#endif
 
 #ifndef CONFIG_DEBUG_GENERIC
 #undef PrintDebug
@@ -37,32 +42,58 @@ typedef enum {GENERIC_IGNORE,
              GENERIC_PRINT_AND_IGNORE} generic_mode_t;
 
 struct generic_internal {
+    enum {GENERIC_PHYSICAL, GENERIC_HOST} forward_type;
+#ifdef CONFIG_HOST_DEVICE
+    v3_host_dev_t                         host_dev;
+#endif
 };
 
 
 
 
-static int generic_write_port_passthrough(struct guest_info * core, uint16_t port, void * src, 
-                                         uint_t length, void * priv_data) {
+static int generic_write_port_passthrough(struct guest_info * core, 
+                                         uint16_t port, 
+                                         void * src, 
+                                         uint_t length, 
+                                         void * priv_data) 
+{
+    struct generic_internal *state = (struct generic_internal *) priv_data;
     uint_t i;
 
-    switch (length) {
-       case 1:
-           v3_outb(port, ((uint8_t *)src)[0]);
-           break;
-       case 2:
-           v3_outw(port, ((uint16_t *)src)[0]);
+    switch (state->forward_type) { 
+       case GENERIC_PHYSICAL:
+           switch (length) {
+               case 1:
+                   v3_outb(port, ((uint8_t *)src)[0]);
+                   break;
+               case 2:
+                   v3_outw(port, ((uint16_t *)src)[0]);
+                   break;
+               case 4:
+                   v3_outdw(port, ((uint32_t *)src)[0]);
+                   break;
+               default:
+                   for (i = 0; i < length; i++) { 
+                       v3_outb(port, ((uint8_t *)src)[i]);
+                   }
+                   break;
+           }
+           return length;
            break;
-       case 4:
-           v3_outdw(port, ((uint32_t *)src)[0]);
+#ifdef CONFIG_HOST_DEVICE
+       case GENERIC_HOST:
+           if (state->host_dev) { 
+               return v3_host_dev_write_io(state->host_dev,port,src,length);
+           } else {
+               return -1;
+           }
            break;
+#endif
        default:
-           for (i = 0; i < length; i++) { 
-               v3_outb(port, ((uint8_t *)src)[i]);
-           }
+           PrintError("generic: unknown forwarding type\n");
+           return -1;
+           break;
     }
-
-    return length;
 }
 
 static int generic_write_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
@@ -70,6 +101,14 @@ static int generic_write_port_print_and_passthrough(struct guest_info * core, ui
     uint_t i;
     int rc;
 
+#ifdef CONFIG_DEBUG_GENERIC
+    struct generic_internal *state = (struct generic_internal *) priv_data;
+#endif
+
+    PrintDebug("generic: writing 0x%x bytes to port 0x%x using %s ...", length, port,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" :
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+
     PrintDebug("generic: writing 0x");
 
     for (i = 0; i < length; i++) { 
@@ -85,35 +124,63 @@ static int generic_write_port_print_and_passthrough(struct guest_info * core, ui
     return rc;
 }
 
-static int generic_read_port_passthrough(struct guest_info * core, uint16_t port, void * src, 
-                                        uint_t length, void * priv_data) {
+static int generic_read_port_passthrough(struct guest_info * core, 
+                                        uint16_t port, 
+                                        void * dst, 
+                                        uint_t length, 
+                                        void * priv_data) 
+{
+    struct generic_internal *state = (struct generic_internal *) priv_data;
+
     uint_t i;
 
-    switch (length) {
-       case 1:
-           ((uint8_t *)src)[0] = v3_inb(port);
-           break;
-       case 2:
-           ((uint16_t *)src)[0] = v3_inw(port);
+    switch (state->forward_type) { 
+       case GENERIC_PHYSICAL:
+           switch (length) {
+               case 1:
+                   ((uint8_t *)dst)[0] = v3_inb(port);
+                   break;
+               case 2:
+                   ((uint16_t *)dst)[0] = v3_inw(port);
+                   break;
+               case 4:
+                   ((uint32_t *)dst)[0] = v3_indw(port);
+                   break;
+               default:
+                   for (i = 0; i < length; i++) { 
+                       ((uint8_t *)dst)[i] = v3_inb(port);
+                   }
+           }
+           return length;
            break;
-       case 4:
-           ((uint32_t *)src)[0] = v3_indw(port);
+#ifdef CONFIG_HOST_DEVICE
+       case GENERIC_HOST:
+           if (state->host_dev) { 
+               return v3_host_dev_read_io(state->host_dev,port,dst,length);
+           }
            break;
+#endif
        default:
-           for (i = 0; i < length; i++) { 
-               ((uint8_t *)src)[i] = v3_inb(port);
-           }
+           PrintError("generic: unknown forwarding type\n");
+           return -1;
+           break;
     }
 
-    return length;
+    return -1;
 }
 
 static int generic_read_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
                                                   uint_t length, void * priv_data) {
     uint_t i;
     int rc;
-    
-    PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
+
+#ifdef CONFIG_DEBUG_GENERIC
+    struct generic_internal *state = (struct generic_internal *) priv_data;
+#endif
+
+    PrintDebug("generic: reading 0x%x bytes from port 0x%x using %s ...", length, port,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" :
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
 
 
     rc=generic_read_port_passthrough(core,port,src,length,priv_data);
@@ -141,7 +208,14 @@ static int generic_read_port_ignore(struct guest_info * core, uint16_t port, voi
 static int generic_read_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
                                              uint_t length, void * priv_data) {
    
-    PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
+#ifdef CONFIG_DEBUG_GENERIC
+    struct generic_internal *state = (struct generic_internal *) priv_data;
+#endif
+
+    PrintDebug("generic: reading 0x%x bytes from port 0x%x using %s ...", length, port,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" :
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+
 
     memset((uint8_t *)src, 0, length);
     PrintDebug(" ignored (return zeroed buffer)\n");
@@ -159,8 +233,14 @@ static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_
                                              uint_t length, void * priv_data) {
     int i;
 
-    PrintDebug("generic: writing 0x%x bytes to port 0x%x ", length, port);
+#ifdef CONFIG_DEBUG_GENERIC
+    struct generic_internal *state = (struct generic_internal *) priv_data;
+#endif
 
+    PrintDebug("generic: writing 0x%x bytes to port 0x%x using %s ", length, port,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" :
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+    
     memset((uint8_t *)src, 0, length);
     PrintDebug(" ignored - data was: 0x");
 
@@ -175,10 +255,186 @@ static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_
 
 
 
+static int generic_write_mem_passthrough(struct guest_info * core, 
+                                        addr_t              gpa,
+                                        void              * src,
+                                        uint_t              len,
+                                        void              * priv)
+{
+    struct vm_device *dev = (struct vm_device *) priv;
+    struct generic_internal *state = (struct generic_internal *) dev->private_data;
+    
+    switch (state->forward_type) { 
+       case GENERIC_PHYSICAL:
+           memcpy(V3_VAddr((void*)gpa),src,len);
+           return len;
+           break;
+#ifdef CONFIG_HOST_DEVICE
+       case GENERIC_HOST:
+           if (state->host_dev) { 
+               return v3_host_dev_write_mem(state->host_dev,gpa,src,len);
+           } else {
+               return -1;
+           }
+           break;
+#endif
+       default:
+           PrintError("generic: unknown forwarding type\n");
+           return -1;
+           break;
+    }
+}
+
+static int generic_write_mem_print_and_passthrough(struct guest_info * core, 
+                                                  addr_t              gpa,
+                                                  void              * src,
+                                                  uint_t              len,
+                                                  void              * priv)
+{
+#ifdef CONFIG_DEBUG_GENERIC
+    struct vm_device *dev = (struct vm_device *) priv;
+    struct generic_internal *state = (struct generic_internal *) dev->private_data;
+#endif
+
+    PrintDebug("generic: writing %u bytes to GPA 0x%p via %s ... ",
+              len,(void*)gpa,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" : 
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+    
+    int rc = generic_write_mem_passthrough(core,gpa,src,len,priv);
+
+    PrintDebug("done\n");
+    
+    return rc;
+}
+
+static int generic_write_mem_ignore(struct guest_info * core, 
+                                   addr_t              gpa,
+                                   void              * src,
+                                   uint_t              len,
+                                   void              * priv)
+{
+    return len;
+}
+
+static int generic_write_mem_print_and_ignore(struct guest_info * core, 
+                                             addr_t              gpa,
+                                             void              * src,
+                                             uint_t              len,
+                                             void              * priv)
+{
+#ifdef CONFIG_DEBUG_GENERIC
+    struct vm_device *dev = (struct vm_device *) priv;
+    struct generic_internal *state = (struct generic_internal *) dev->private_data;
+#endif
+
+    PrintDebug("generic: ignoring write of %u bytes to GPA 0x%p via %s",
+              len,(void*)gpa,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" : 
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+    
+    return len;
+}
+
+static int generic_read_mem_passthrough(struct guest_info * core, 
+                                       addr_t              gpa,
+                                       void              * dst,
+                                       uint_t              len,
+                                       void              * priv)
+{
+    struct vm_device *dev = (struct vm_device *) priv;
+    struct generic_internal *state = (struct generic_internal *) dev->private_data;
+    
+    switch (state->forward_type) { 
+       case GENERIC_PHYSICAL:
+           memcpy(dst,V3_VAddr((void*)gpa),len);
+           return len;
+           break;
+#ifdef CONFIG_HOST_DEVICE
+       case GENERIC_HOST:
+           if (state->host_dev) { 
+               return v3_host_dev_read_mem(state->host_dev,gpa,dst,len);
+           } else {
+               return -1;
+           }
+           break;
+#endif
+       default:
+           PrintError("generic: unknown forwarding type\n");
+           break;
+    }
+    
+    return -1;
+}
+
+static int generic_read_mem_print_and_passthrough(struct guest_info * core, 
+                                                 addr_t              gpa,
+                                                 void              * dst,
+                                                 uint_t              len,
+                                                 void              * priv)
+{
+#ifdef CONFIG_DEBUG_GENERIC
+    struct vm_device *dev = (struct vm_device *) priv;
+    struct generic_internal *state = (struct generic_internal *) dev->private_data;
+#endif
+
+    PrintDebug("generic: attempting to read %u bytes from GPA 0x%p via %s ... ",
+              len,(void*)gpa,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" : 
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+    
+    int rc = generic_read_mem_passthrough(core,gpa,dst,len,priv);
+
+    PrintDebug("done - read %d bytes\n", rc);
+    
+    return rc;
+}
+
+static int generic_read_mem_ignore(struct guest_info * core, 
+                                  addr_t              gpa,
+                                  void              * dst,
+                                  uint_t              len,
+                                  void              * priv)
+{
+#ifdef CONFIG_DEBUG_GENERIC
+    struct vm_device *dev = (struct vm_device *) priv;
+    struct generic_internal *state = (struct generic_internal *) dev->private_data;
+#endif
+
+    PrintDebug("generic: ignoring attempt to read %u bytes from GPA 0x%p via %s ... ",
+              len,(void*)gpa,
+              state->forward_type == GENERIC_PHYSICAL ? "physical" : 
+              state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
+
+    memset((uint8_t *)dst, 0, len);
+
+    PrintDebug("returning zeros\n");
+
+    return len;
+}
+
+
+static int generic_read_mem_print_and_ignore(struct guest_info * core, 
+                                            addr_t              gpa,
+                                            void              * dst,
+                                            uint_t              len,
+                                            void              * priv)
+{
+    memset((uint8_t *)dst, 0, len);
+    return len;
+}
+
 
 static int generic_free(struct generic_internal * state) {
     PrintDebug("generic: deinit_device\n");
 
+#ifdef CONFIG_HOST_DEVICE
+    if (state->host_dev) { 
+       v3_host_dev_close(state->host_dev);
+       state->host_dev=0;
+    }
+#endif
+
     V3_Free(state);
     return 0;
 }
@@ -197,53 +453,156 @@ static struct v3_device_ops dev_ops = {
 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
     uint_t i = 0;
 
-    PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %s\n", 
+    PrintDebug("generic: adding port range 0x%x to 0x%x as %s\n", 
               start, end, 
-              (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
-    
+              (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : 
+              (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
+              (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
+              (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
+       
     for (i = start; i <= end; i++) { 
-       if (mode == GENERIC_PRINT_AND_PASSTHROUGH) { 
-           if (v3_dev_hook_io(dev, i, 
-                               &generic_read_port_print_and_passthrough, 
-                               &generic_write_port_print_and_passthrough) == -1) { 
-               PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+       switch (mode) { 
+           case GENERIC_PRINT_AND_PASSTHROUGH:
+               if (v3_dev_hook_io(dev, i, 
+                                  &generic_read_port_print_and_passthrough, 
+                                  &generic_write_port_print_and_passthrough) == -1) { 
+                   PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+                   return -1;
+               }
+               break;
+               
+           case GENERIC_PRINT_AND_IGNORE:
+               if (v3_dev_hook_io(dev, i, 
+                                  &generic_read_port_print_and_ignore, 
+                                  &generic_write_port_print_and_ignore) == -1) { 
+                   PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+                   return -1;
+               }
+               break;
+           case GENERIC_PASSTHROUGH:
+               if (v3_dev_hook_io(dev, i, 
+                                  &generic_read_port_passthrough, 
+                                  &generic_write_port_passthrough) == -1) { 
+                   PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+                   return -1;
+               }
+               break;
+           case  GENERIC_IGNORE:
+               if (v3_dev_hook_io(dev, i, 
+                                  &generic_read_port_ignore, 
+                                  &generic_write_port_ignore) == -1) { 
+                   PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+                   return -1;
+               }
+               break;
+           default:
+               PrintError("generic: huh?\n");
+               break;
+       }
+    }
+    
+    return 0;
+}
+
+
+static int add_mem_range(struct vm_device * dev, addr_t start, addr_t end, generic_mode_t mode) {
+
+    PrintDebug("generic: adding memory range 0x%p to 0x%p as %s\n", 
+              (void*)start, (void*)end, 
+              (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : 
+              (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
+              (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
+              (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
+       
+    switch (mode) { 
+       case GENERIC_PRINT_AND_PASSTHROUGH:
+           if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
+                                &generic_read_mem_print_and_passthrough, 
+                                &generic_write_mem_print_and_passthrough, dev) == -1) { 
+               PrintError("generic: can't hook memory region 0x%p to 0x%p\n",(void*)start,(void*)end);
                return -1;
            }
-       } else if (mode == GENERIC_PRINT_AND_IGNORE) { 
-           if (v3_dev_hook_io(dev, i, 
-                               &generic_read_port_print_and_ignore, 
-                               &generic_write_port_print_and_ignore) == -1) { 
-               PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+           break;
+           
+       case GENERIC_PRINT_AND_IGNORE:
+           if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
+                                &generic_read_mem_print_and_ignore, 
+                                &generic_write_mem_print_and_ignore, dev) == -1) { 
+               PrintError("generic: can't hook memory region 0x%p to 0x%p\n",(void*)start,(void*)end);
                return -1;
            }
-       } else if (mode == GENERIC_PASSTHROUGH) { 
-           if (v3_dev_hook_io(dev, i, 
-                               &generic_read_port_passthrough, 
-                               &generic_write_port_passthrough) == -1) { 
-               PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+           break;
+
+       case GENERIC_PASSTHROUGH:
+           if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
+                                &generic_read_mem_passthrough, 
+                                &generic_write_mem_passthrough, dev) == -1) { 
+               PrintError("generic: can't hook memory region 0x%p to 0x%p\n",(void*)start,(void*)end);
                return -1;
            }
-       } else if (mode == GENERIC_IGNORE) { 
-           if (v3_dev_hook_io(dev, i, 
-                               &generic_read_port_ignore, 
-                               &generic_write_port_ignore) == -1) { 
-               PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
+           break;
+
+       case  GENERIC_IGNORE:
+           if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
+                                &generic_read_mem_ignore, 
+                                &generic_write_mem_ignore, dev) == -1) { 
+               PrintError("generic: can't hook memory region 0x%p to 0x%p\n",(void*)start,(void*)end);
                return -1;
            }
-       } 
+           break;
+       default:
+           PrintError("generic: huh?\n");
+           break;
     }
-    
+
     return 0;
 }
 
 
 
+/*
+   The device can be used to forward to the underlying physical device 
+   or to a host device that has a given url.   Both memory and ports can be forwarded as
+
+        GENERIC_PASSTHROUGH => send writes and reads to physical device or host
+        GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
+
+        GENERIC_IGNORE => ignore writes and reads
+        GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
+
+
+       The purpose of the "PRINT" variants is to make it easy to spy on
+       device interactions (although you will not see DMA or interrupts)
+
+
+   <device class="generic" id="my_id" 
+         empty | forward="physical_device" or forward="host_device" host_device="url">
+
+  (empty implies physical_dev)
+
+     <ports>
+         <start>portno1</start>
+         <end>portno2</end>   => portno1 through portno2 (inclusive)
+         <mode>PRINT_AND_PASSTHROUGH</mode>  (as above)
+     </ports>
 
+     <memory>
+         <start>gpa1</start>
+         <end>gpa2</end>     => memory addreses gpa1 through gpa2 (inclusive); page granularity
+         <mode> ... as above </mode>
+     </memory>
+
+*/
 
 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     struct generic_internal * state = NULL;
     char * dev_id = v3_cfg_val(cfg, "ID");
+    char * forward = v3_cfg_val(cfg, "forward");
+#ifdef CONFIG_HOST_DEVICE
+    char * host_dev = v3_cfg_val(cfg, "hostdev");
+#endif
     v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
+    v3_cfg_tree_t * mem_cfg = v3_cfg_subtree(cfg, "memory");
 
 
     state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
@@ -254,6 +613,26 @@ static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     }
     
     memset(state, 0, sizeof(struct generic_internal));
+
+    if (!forward) { 
+       state->forward_type=GENERIC_PHYSICAL;
+    } else {
+       if (!strcasecmp(forward,"physical_device")) { 
+           state->forward_type=GENERIC_PHYSICAL;
+       } else if (!strcasecmp(forward,"host_device")) { 
+#ifdef CONFIG_HOST_DEVICE
+           state->forward_type=GENERIC_HOST;
+#else
+           PrintError("generic: cannot configure host device since host device support is not built in\n");
+           V3_Free(state);
+           return -1;
+#endif
+       } else {
+           PrintError("generic: unknown forwarding type \"%s\"\n", forward);
+           V3_Free(state);
+           return -1;
+       }
+    }
     
     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
 
@@ -263,6 +642,26 @@ static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        return -1;
     }
 
+
+#ifdef CONFIG_HOST_DEVICE
+    if (state->forward_type==GENERIC_HOST) { 
+       if (!host_dev) { 
+           PrintError("generic: host forwarding requested, but no host device given\n");
+           v3_remove_device(dev);
+           return -1;
+       } else {
+           state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev);
+           if (!(state->host_dev)) { 
+               PrintError("generic: unable to open host device \"%s\"\n",host_dev);
+               v3_remove_device(dev);
+               return -1;
+           } else {
+               PrintDebug("generic: successfully attached host device \"%s\"\n",host_dev);
+           }
+       }
+    }
+#endif
+
     PrintDebug("generic: init_device\n");
 
     // scan port list....
@@ -281,13 +680,13 @@ static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        } else if (strcasecmp(mode_str, "ignore") == 0) {
            mode = GENERIC_IGNORE;
        } else {
-           PrintError("Invalid Mode %s\n", mode_str);
+           PrintError("generic: invalid mode %s in adding ports\n", mode_str);
            v3_remove_device(dev);
            return -1;
        }
        
        if (add_port_range(dev, start, end, mode) == -1) {
-           PrintError("Could not add port range %d-%d\n", start, end);
+           PrintError("generic: could not add port range 0x%x to 0x%x\n", start, end);
            v3_remove_device(dev);
            return -1;
        }
@@ -295,6 +694,37 @@ static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        port_cfg = v3_cfg_next_branch(port_cfg);
     }
 
+    // scan memory list....
+    while (mem_cfg) {
+       addr_t  start = atox(v3_cfg_val(mem_cfg, "start"));
+       addr_t end = atox(v3_cfg_val(mem_cfg, "end"));
+       char * mode_str = v3_cfg_val(mem_cfg, "mode");
+       generic_mode_t mode = GENERIC_IGNORE;
+
+       if (strcasecmp(mode_str, "print_and_ignore") == 0) {
+           mode = GENERIC_PRINT_AND_IGNORE;
+       } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
+           mode = GENERIC_PRINT_AND_PASSTHROUGH;
+       } else if (strcasecmp(mode_str, "passthrough") == 0) {
+           mode = GENERIC_PASSTHROUGH;
+       } else if (strcasecmp(mode_str, "ignore") == 0) {
+           mode = GENERIC_IGNORE;
+       } else {
+           PrintError("generic: invalid mode %s for adding memory\n", mode_str);
+           v3_remove_device(dev);
+           return -1;
+       }
+       
+       if (add_mem_range(dev, start, end, mode) == -1) {
+           PrintError("generic: could not add memory range 0x%p to 0x%p\n", (void*)start, (void*)end);
+           v3_remove_device(dev);
+           return -1;
+       }
+
+       mem_cfg = v3_cfg_next_branch(port_cfg);
+    }
+    
+    PrintDebug("generic: initialization complete\n");
 
     return 0;
 }