The console is still a complete mess, but my attempt to fix it just made it stop working.
     uint8_t dst;
 } __attribute__((packed));
 
-int v3_apic_send_ipi(struct v3_vm_info * vm, struct vm_device * dev, 
-                    struct v3_gen_ipi * ipi);
+int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data);
 
-int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * apic_dev, 
-                      uint32_t irq, uint32_t dst);
+int v3_apic_raise_intr(struct v3_vm_info * vm, 
+                      uint32_t irq, uint32_t dst,
+                      void * dev_data);
 
 
 
 
 
 
 
-int v3_ide_get_geometry(struct vm_device * ide_dev, int channel_num, int drive_num, 
+int v3_ide_get_geometry(void * ide_data, int channel_num, int drive_num, 
                        uint32_t * cylinders, uint32_t * heads, uint32_t * sectors);
 
 
 
 
 
 int v3_pci_set_irq_bridge(struct vm_device * pci_bus, int bus_num,
-                         int (*raise_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev), 
-                         int (*lower_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev), 
-                         struct vm_device * bridge_dev);
+                         int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data), 
+                         int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data), 
+                         void * dev_data);
 
 
 int v3_pci_raise_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev);
 
 
 typedef enum {V3_SB_INVALID, V3_SB_PIIX3, V3_SB_PIIX4, V3_SB_CMD646} v3_southbridge_type_t;
 
+struct v3_vm_info;
+
 struct v3_southbridge {
     struct vm_device * pci_bus;
     struct pci_device * southbridge_pci;
 
+    struct v3_vm_info * vm;
+    
     v3_southbridge_type_t type;
 };
 
 
 
 struct v3_device_ops;
 
+typedef void * v3_dev_data_t;
+
+struct vm_device;
 
 struct vm_device {
     char name[32];
     struct list_head char_list;
     struct hashtable * char_table;
 
-    struct list_head console_list;
-    struct hashtable * console_table;
+    struct list_head cons_list;
+    struct hashtable * cons_table;
 
 };
 
 
 
 struct v3_device_ops {
-    int (*free)(struct vm_device *dev);
-
-
-    int (*reset)(struct vm_device *dev);
-
-    int (*start)(struct vm_device *dev);
-    int (*stop)(struct vm_device *dev);
-
+    int (*free)(struct vm_device * dev);
 
     //int (*save)(struct vm_device *dev, struct *iostream);
     //int (*restore)(struct vm_device *dev, struct *iostream);
                   int (*read)(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data),
                   int (*write)(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data));
 
-int v3_dev_unhook_io(struct vm_device   *dev,
+int v3_dev_unhook_io(struct vm_device   * dev,
                     ushort_t            port);
 
 
 
 struct v3_dev_net_ops {
     /* Backend implemented functions */
-    int (*send)(uint8_t * buf, uint32_t count, void * private_data, struct vm_device *dest_dev);
-    void (*start_rx)(void *back_data);
-    void (*stop_rx)(void *back_data);
+    int (*send)(uint8_t * buf, uint32_t count, void * private_data);
+    void (*start_rx)(void * back_data);
+    void (*stop_rx)(void * back_data);
 
     /* Frontend implemented functions */
     int (*recv)(uint8_t * buf, uint32_t count, void * frnt_data);
 };
 
 struct v3_dev_console_ops {
+    int (*update_screen)(uint_t x, uint_t y, uint_t length, uint8_t * fb_data, void * private_data);
+    int (*update_cursor)(uint_t x, uint_t y, void * private_data);
+    int (*scroll)(int rows, void * private_data);
 
+    /* frontend implemented functions */
+    int (*get_screen)(uint_t x, uint_t y, uint_t length, void * frontend_data);
+    void * push_fn_arg;
 };
 
 struct v3_dev_char_ops {
                       void * private_data);
 
 
+
+
+int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
+                               char * name, 
+                               int (*connect)(struct v3_vm_info * vm, 
+                                              void * frontend_data, 
+                                              struct v3_dev_console_ops * ops, 
+                                              v3_cfg_tree_t * cfg, 
+                                              void * private_data), 
+                               void * priv_data);
+
+int v3_dev_connect_console(struct v3_vm_info * vm, 
+                          char * frontend_name, 
+                          struct v3_dev_console_ops * ops, 
+                          v3_cfg_tree_t * cfg, 
+                          void * private_data);
+
+
+
 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
                             char * name, 
                             int (*connect)(struct v3_vm_info * vm, 
 
  * This should call out to handle_SQR_WAVE_tics, etc... 
  */
 // Returns true if the the output signal changed state
-static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint_t oscillations) {
+static int handle_crystal_tics(struct pit * pit, struct channel * ch, uint_t oscillations) {
     uint_t channel_cycles = 0;
     uint_t output_changed = 0;
   
 #include <palacios/vm_guest.h>
 
 static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct pit * state = (struct pit *)dev->private_data;
+    struct pit * state = (struct pit *)private_data;
     //  ullong_t tmp_ctr = state->pit_counter;
     ullong_t tmp_cycles;
     uint_t oscillations = 0;
        state->pit_counter = state->pit_reload - cpu_cycles;    
 
        //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
-       if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
+       if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) {
            // raise interrupt
            PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
            v3_raise_irq(info->vm_info, 0);
        }
 
-       //handle_crystal_tics(dev, &(state->ch_1), oscillations);
-       handle_crystal_tics(dev, &(state->ch_2), oscillations);
+       //handle_crystal_tics(state, &(state->ch_1), oscillations);
+       handle_crystal_tics(state, &(state->ch_2), oscillations);
     }
   
 
 
 static struct v3_device_ops dev_ops = {
     .free = pit_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 
 };
 
 
     
 
-    pit_state->timer = v3_add_timer(info, &timer_ops, dev);
+    pit_state->timer = v3_add_timer(info, &timer_ops, pit_state);
 
     if (pit_state->timer == NULL) {
        v3_detach_device(dev);
 
 
 
 static int pic_free(struct vm_device * dev) {
-    v3_dev_unhook_io(dev, MASTER_PORT1);
-    v3_dev_unhook_io(dev, MASTER_PORT2);
-    v3_dev_unhook_io(dev, SLAVE_PORT1);
-    v3_dev_unhook_io(dev, SLAVE_PORT2);
 
     return 0;
 }
 
 static struct v3_device_ops dev_ops = {
     .free = pic_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 
 
 #endif
 
 #ifdef CONFIG_DEBUG_APIC
-static char *shorthand_str[] = { 
+static char * shorthand_str[] = { 
     "(no shorthand)",
     "(self)",
     "(all)",
     "(all-but-me)",
 };
 
-static char *deliverymode_str[] = { 
+static char * deliverymode_str[] = { 
     "(fixed)",
     "(lowest priority)",
     "(SMI)",
 }
 
 
-int v3_apic_send_ipi(struct v3_vm_info * vm, struct vm_device * dev, 
-                    struct v3_gen_ipi * ipi) {
-    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
+int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)dev_data;
     struct int_cmd_reg tmp_icr;
 
     // zero out all the fields
 }
 
 
-int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * dev, 
-                      uint32_t irq, uint32_t dst) {
-    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
+int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev_data);
     struct apic_state * apic = &(apic_dev->apics[dst]); 
 
     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
 
 static struct v3_device_ops dev_ops = {
     .free = apic_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = model_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = disk_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = i440_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 
 
     pci_dev = v3_pci_register_device(state->pci, PCI_STD_DEVICE, 
                                     0, 0, 0, "i440FX", bars,
-                                    NULL, NULL, NULL, dev);
+                                    NULL, NULL, NULL, state);
 
     if (!pci_dev) {
        v3_detach_device(dev);
 
 
 
 #ifdef CONFIG_DEBUG_IDE
-static void print_prd_table(struct vm_device * dev, struct ide_channel * channel) {
+static void print_prd_table(struct ide_internal * ide, struct ide_channel * channel) {
     struct ide_dma_prd prd_entry;
     int index = 0;
 
        uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * index);
        int ret;
 
-       ret = v3_read_gpa_memory(&(dev->vm->cores[0]), prd_entry_addr, sizeof(struct ide_dma_prd), (void *)&prd_entry);
+       ret = v3_read_gpa_memory(&(ide->vm->cores[0]), prd_entry_addr, sizeof(struct ide_dma_prd), (void *)&prd_entry);
        
        if (ret != sizeof(struct ide_dma_prd)) {
            PrintError("Could not read PRD\n");
 
 static int pci_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
     PrintDebug("PCI Config Update\n");
-    /*    struct vm_device * dev = (struct vm_device *)private_data;
-    struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+    /*
+    struct ide_internal * ide = (struct ide_internal *)(private_data);
 
     PrintDebug("\t\tInterupt register (Dev=%s), irq=%d\n", ide->ide_pci->name, ide->ide_pci->config_header.intr_line);
     */
 
        bars[4].io_read = read_dma_port;
        bars[4].io_write = write_dma_port;
-       bars[4].private_data = dev;
+       bars[4].private_data = ide;
 
        pci_dev = v3_pci_register_device(ide->pci_bus, PCI_STD_DEVICE, 0, sb_pci->dev_num, 1, 
                                         "PIIX3_IDE", bars,
-                                        pci_config_update, NULL, NULL, dev);
+                                        pci_config_update, NULL, NULL, ide);
 
        if (pci_dev == NULL) {
            PrintError("Failed to register IDE BUS %d with PCI\n", i); 
 
 
 
-int v3_ide_get_geometry(struct vm_device * ide_dev, int channel_num, int drive_num, 
+int v3_ide_get_geometry(void * ide_data, int channel_num, int drive_num, 
                        uint32_t * cylinders, uint32_t * heads, uint32_t * sectors) {
 
-    struct ide_internal * ide  = (struct ide_internal *)(ide_dev->private_data);  
+    struct ide_internal * ide  = ide_data;  
     struct ide_channel * channel = &(ide->channels[channel_num]);
     struct ide_drive * drive = &(channel->drives[drive_num]);
     
 
   
     struct redir_tbl_entry redir_tbl[24];
 
-    struct vm_device * apic_dev;
+    void * apic_dev_data;
   
 };
 
 
 
 static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
-    struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
+    struct io_apic_state * ioapic = (struct io_apic_state *)(priv_data);
     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
     uint32_t * op_val = (uint32_t *)dst;
 
 
 
 static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
-    struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
+    struct io_apic_state * ioapic = (struct io_apic_state *)(priv_data);
     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
     uint32_t op_val = *(uint32_t *)src;
 
 
 
 static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);  
+    struct io_apic_state * ioapic = (struct io_apic_state *)(private_data);  
     struct redir_tbl_entry * irq_entry = NULL;
 
     if (irq > 24) {
        ipi.dst_shorthand = 0;
 
        // Need to add destination argument here...
-       if (v3_apic_send_ipi(vm, ioapic->apic_dev, &ipi) == -1) {
+       if (v3_apic_send_ipi(vm, &ipi, ioapic->apic_dev_data) == -1) {
            PrintError("Error sending IPI to apic %d\n", ipi.dst);
            return -1;
        }
 
 static struct v3_device_ops dev_ops = {
     .free = io_apic_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 
 
     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
 
-    ioapic->apic_dev = apic_dev;
+    ioapic->apic_dev_data = apic_dev;
 
     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, ioapic);
 
     }
 
 
-    v3_register_intr_router(vm, &router_ops, dev);
+    v3_register_intr_router(vm, &router_ops, ioapic);
 
-    init_ioapic_state(ioapic,vm->num_cores);
+    init_ioapic_state(ioapic, vm->num_cores);
 
     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
-                    ioapic_read, ioapic_write, dev);
+                    ioapic_read, ioapic_write, ioapic);
   
     return 0;
 }
 
     return -1;
 }
 
-static int virtio_reset(struct vm_device * dev) {
-    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
+static int virtio_reset(struct virtio_balloon_state * virtio) {
 
     memset(virtio->queue, 0, sizeof(struct virtio_queue) * 2);
 
 }
 
 
-static int handle_kick(struct guest_info * core, struct vm_device * dev) {
-    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;    
+static int handle_kick(struct guest_info * core, struct virtio_balloon_state * virtio) {
     struct virtio_queue * q = virtio->cur_queue;
 
     PrintDebug("VIRTIO BALLOON KICK: cur_index=%d (mod=%d), avail_index=%d\n", 
            }
 
            /*      
-              if (handle_balloon_op(dev, tmp_desc, buf_desc, status_desc) == -1) {
+              if (handle_balloon_op(virtio, tmp_desc, buf_desc, status_desc) == -1) {
               PrintError("Error handling balloon operation\n");
               return -1;
               }
 }
 
 static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
+    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)private_data;
     int port_idx = port % virtio->io_range_size;
 
 
            break;
        case VRING_Q_NOTIFY_PORT:
            PrintDebug("Handling Kick\n");
-           if (handle_kick(core, dev) == -1) {
+           if (handle_kick(core, virtio) == -1) {
                PrintError("Could not handle Balloon Notification\n");
                return -1;
            }
 
            if (virtio->virtio_cfg.status == 0) {
                PrintDebug("Resetting device\n");
-               virtio_reset(dev);
+               virtio_reset(virtio);
            }
 
            break;
 
 
 static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
+    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)private_data;
     int port_idx = port % virtio->io_range_size;
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = virtio_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
-};
 
+};
 
-static int set_size(struct vm_device * dev, addr_t size) {
-    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
 
+static int set_size(struct virtio_balloon_state * virtio, addr_t size) {
     virtio->balloon_cfg.requested_pages = size / PAGE_SIZE; // number of pages
 
     PrintDebug("Requesting %d pages\n", virtio->balloon_cfg.requested_pages);
 
 
 static int handle_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
+    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)priv_data;
     int tgt_size = info->vm_regs.rcx;
 
     
-    return set_size(dev, tgt_size);
+    return set_size(virtio, tgt_size);
 }
 
 
 
 static int handle_query_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
-    struct vm_device * dev = (struct vm_device *)priv_data;
-    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
+    struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)priv_data;
     
     info->vm_regs.rcx = virtio->balloon_cfg.requested_pages;
     info->vm_regs.rdx = virtio->balloon_cfg.allocated_pages;
 
        bars[0].io_read = virtio_io_read;
        bars[0].io_write = virtio_io_write;
-       bars[0].private_data = dev;
+       bars[0].private_data = virtio_state;
        
 
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, PCI_AUTO_DEV_NUM, 0,
                                         "LNX_VIRTIO_BALLOON", bars,
-                                        NULL, NULL, NULL, dev);
+                                        NULL, NULL, NULL, virtio_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
        virtio_state->pci_bus = pci_bus;
     }
 
-    virtio_reset(dev);
+    virtio_reset(virtio_state);
 
-    v3_register_hypercall(vm, BALLOON_START_HCALL, handle_hcall, dev);
-    v3_register_hypercall(vm, BALLOON_QUERY_HCALL, handle_query_hcall, dev);
+    v3_register_hypercall(vm, BALLOON_START_HCALL, handle_hcall, virtio_state);
+    v3_register_hypercall(vm, BALLOON_QUERY_HCALL, handle_query_hcall, virtio_state);
 
     return 0;
 }
 
 }
 
 
-static int virtio_reset(struct vm_device * dev) {
-    struct virtio_dev_state * dev_state = (struct virtio_dev_state *)(dev->private_data);
-    struct virtio_blk_state * blk_state = NULL;
 
-    list_for_each_entry(blk_state, &(dev_state->dev_list), dev_link) {
-       blk_reset(blk_state);
-    }
-
-    return 0;
-}
 
 static int handle_read_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint64_t len) {
     int ret = -1;
 
 static struct v3_device_ops dev_ops = {
     .free = virtio_free,
-    .reset = virtio_reset,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 
 
        return -ERR_VIRTIO_OTHER;
     }
 
-    return virtio->net_ops->send(buf, len, virtio->backend_data, NULL);
+    return virtio->net_ops->send(buf, len, virtio->backend_data);
 }
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = virtio_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = NULL,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
        bars[0].io_read = virtio_io_read;
        bars[0].io_write = virtio_io_write;
-       bars[0].private_data = dev;
+       bars[0].private_data = virtio_state;
 
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, PCI_AUTO_DEV_NUM, 0,
                                         "LNX_VIRTIO_SYM", bars,
-                                        NULL, NULL, NULL, dev);
+                                        NULL, NULL, NULL, virtio_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
 
 }
 
 
+static int virtio_free(struct vm_device * dev) 
+{
+       
+    return 0;
+}
 
 
 static struct v3_device_ops dev_ops = {
-    .free = NULL,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+    .free = virtio_free,
 };
 
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = disk_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 };
 
 static int bridge_send(uint8_t * buf, uint32_t len, 
-                      void * private_data, struct vm_device *dev){
+                      void * private_data) {
     //struct nic_bridge_state *bridge = (struct nic_bridge_state *)private_data;
 
 #ifdef CONFIG_DEBUG_NIC_BRIDGE
 static int packet_input(struct v3_vm_info * vm,
                        struct v3_packet_event * evt, 
                        void * private_data) {
-    struct nic_bridge_state *bridge = (struct nic_bridge_state *)private_data;
+    struct nic_bridge_state * bridge = (struct nic_bridge_state *)private_data;
 
     PrintDebug("NIC_BRIDGE: Incoming packet size: %d\n", evt->size);
 
     return bridge->net_ops.recv(evt->pkt, 
-       evt->size, 
-       bridge->net_ops.frontend_data);
+                               evt->size, 
+                               bridge->net_ops.frontend_data);
 }
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = vnet_nic_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     PrintDebug("NIC-Bridge: Connect %s to frontend %s\n", 
              dev_id, v3_cfg_val(frontend_cfg, "tag"));
 
-    v3_hook_host_event(vm, HOST_PACKET_EVT, V3_HOST_EVENT_HANDLER(packet_input), dev);
+    v3_hook_host_event(vm, HOST_PACKET_EVT, V3_HOST_EVENT_HANDLER(packet_input), bridge);
 
     return 0;
 }
 
     uint8_t dev_map[MAX_BUS_DEVICES / 8];
 
 
-    int (*raise_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev);
-    int (*lower_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev);
-    struct vm_device * irq_bridge_dev;
+    int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data);
+    int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data);
+    void * irq_dev_data;
 };
 
 
 
 
 int v3_pci_set_irq_bridge(struct  vm_device * pci_bus, int bus_num, 
-                         int (*raise_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev),
-                         int (*lower_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev),
-                         struct vm_device * bridge_dev) {
+                         int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data),
+                         int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data),
+                         void * priv_data) {
     struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
 
 
     pci_state->bus_list[bus_num].raise_pci_irq = raise_pci_irq;
     pci_state->bus_list[bus_num].lower_pci_irq = lower_pci_irq;
-    pci_state->bus_list[bus_num].irq_bridge_dev = bridge_dev;
+    pci_state->bus_list[bus_num].irq_dev_data = priv_data;
 
     return 0;
 }
    struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
    struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
 
-   return bus->raise_pci_irq(bus->irq_bridge_dev, dev);
+   return bus->raise_pci_irq(bus->irq_dev_data, dev);
 }
 
 int v3_pci_lower_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev) {
    struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
    struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
 
-   return bus->lower_pci_irq(bus->irq_bridge_dev, dev);
+   return bus->lower_pci_irq(bus->irq_dev_data, dev);
 }
 
 // if dev_num == -1, auto assign 
 
 
 static struct v3_device_ops dev_ops = {
     .free = NULL,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 
 
 
-static int reset_piix3(struct vm_device * dev) {
-    struct v3_southbridge * piix3 = (struct v3_southbridge *)(dev->private_data);
+static int reset_piix3(struct v3_southbridge * piix3) {
     struct pci_device * pci_dev = piix3->southbridge_pci;
     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(pci_dev->config_data);
 
 
 //irq is pirq_rc[intr_pin + pci_dev_num - 1] & 0x3
 
-static int raise_pci_irq(struct vm_device * dev, struct pci_device * pci_dev) {
-    struct v3_southbridge * piix3 = (struct v3_southbridge *)(dev->private_data);
+static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
+    struct v3_southbridge * piix3 = dev_data;
     struct pci_device * piix3_pci = piix3->southbridge_pci;
     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data);
     int intr_pin = pci_dev->config_header.intr_pin - 1;
     
     //        PrintError("Raising PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]);
     
-    v3_raise_irq(dev->vm, piix3_cfg->pirq_rc[irq_index]);
+    v3_raise_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index]);
 
     return 0;
 }
 
 
 
-static int lower_pci_irq(struct vm_device * dev, struct pci_device * pci_dev) {
-    struct v3_southbridge * piix3 = (struct v3_southbridge *)(dev->private_data);
+static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data) {
+    struct v3_southbridge * piix3 = dev_data;
     struct pci_device * piix3_pci = piix3->southbridge_pci;
     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data);
     int intr_pin = pci_dev->config_header.intr_pin - 1;
     
     //    PrintError("Lowering PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]);
     
-    v3_lower_irq(dev->vm, piix3_cfg->pirq_rc[irq_index]);
+    v3_lower_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index]);
 
     return 0;
 }
 
 static struct v3_device_ops dev_ops = {
     .free = piix_free,
-    .reset = reset_piix3,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
 
-static int setup_pci(struct vm_device * dev) {
-    struct v3_southbridge * piix3 = (struct v3_southbridge *)(dev->private_data);
+static int setup_pci(struct v3_southbridge * piix3) {
     struct pci_device * pci_dev = NULL;
     struct v3_pci_bar bars[6];
     int i;
     pci_dev = v3_pci_register_device(piix3->pci_bus, PCI_MULTIFUNCTION, 
                                     bus_num, -1, 0, 
                                     "PIIX3", bars, 
-                                    NULL, NULL, NULL, dev);
+                                    NULL, NULL, NULL, piix3);
     if (pci_dev == NULL) {
        PrintError("Could not register PCI Device for PIIX3\n");
        return -1;
 
     piix3->southbridge_pci = pci_dev;
 
-    v3_pci_set_irq_bridge(piix3->pci_bus, bus_num, raise_pci_irq, lower_pci_irq, dev);
+    v3_pci_set_irq_bridge(piix3->pci_bus, bus_num, raise_pci_irq, lower_pci_irq, piix3);
 
-    reset_piix3(dev);
+    reset_piix3(piix3);
 
     return 0;
 }
 
     PrintDebug("Created PIIX3\n");
 
-    return setup_pci(dev);
+    return setup_pci(piix3);
 }
 
 
 
 
 static struct v3_device_ops dev_ops = {
     .free = disk_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
 };
 
 
 
     return length;
 }
 
-static int serial_deinit(struct vm_device * dev) {
+static int serial_free(struct vm_device * dev) {
     return 0;
 }
 
 
 
 static struct v3_device_ops dev_ops = {
-    //.init = serial_init,
-    .free = serial_deinit,
-    .reset = NULL,
+    .free = serial_free,
 };
 
 
 
 #include <palacios/vmm_socket.h>
 
 #include <devices/console.h>
-#if 0
-#include <devices/telnet_cons.h>
-#endif
+
 
 #define NUM_ROWS 25
 #define NUM_COLS 80
 
     v3_lock_t cons_lock;
 
+    v3_vm_info * vm;
+
     struct vm_device * frontend_dev;
 };
 
 
 
 
-static int deliver_scan_code(struct vm_device * dev, struct key_code * key) {
+static int deliver_scan_code(struct cons_state * state, struct key_code * key) {
     struct v3_keyboard_event key_event;
     struct v3_keyboard_event key_shift;
     uint_t cap = key->capital;
        key_shift.status = 0;
        key_shift.scan_code = (uint8_t)0x2A;
 
-       if (v3_deliver_keyboard_event(dev->vm, &key_shift) == -1) {
+       if (v3_deliver_keyboard_event(state->vm, &key_shift) == -1) {
            PrintError("Video: Error delivering key event\n");
            return -1;
        }
     }
 
     // Press
-    if (v3_deliver_keyboard_event(dev->vm, &key_event) == -1) {
+    if (v3_deliver_keyboard_event(state->vm, &key_event) == -1) {
        PrintError("Video: Error delivering key event\n");
        return -1;
     }
     // Release
     key_event.scan_code = key_event.scan_code | 0x80;
   
-    if (v3_deliver_keyboard_event(dev->vm, &key_event) == -1) {
+    if (v3_deliver_keyboard_event(state->vm, &key_event) == -1) {
        PrintError("Video: Error delivering key event\n");
        return -1;
     }
     if (cap) {
         key_shift.scan_code = 0x2A | 0x80;
 
-       if (v3_deliver_keyboard_event(dev->vm, &key_shift) == -1) {
+       if (v3_deliver_keyboard_event(state->vm, &key_shift) == -1) {
            PrintError("Video: Error delivering key event\n");
            return -1;
        }
     } while (0)
 
 
-static int send_update(struct vm_device * dev, uint8_t  x, uint8_t  y, uint8_t attrib, uint8_t val) {
-    struct cons_state * state = (struct cons_state *)dev->private_data;
+static int send_update(struct cons_state * state, uint8_t  x, uint8_t  y, uint8_t attrib, uint8_t val) {
     uint8_t fg_color = fg_color_map[(attrib & 0x0f) % 16];
     uint8_t bg_color = bg_color_map[(attrib & 0xf0) % 16];
     uint8_t buf[32];
 
 
 static int cursor_update(uint_t x, uint_t y, void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct cons_state * state = (struct cons_state *)dev->private_data;
+    struct cons_state * state = (struct cons_state *)private_data;
     uint8_t buf[16];
     int ret = 0;
     addr_t irq_state = 0;
 
 
 static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct cons_state * state = (struct cons_state *)dev->private_data;
+    struct cons_state * state = (struct cons_state *)private_data;
     uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
     uint8_t fb_buf[length];
     int i = 0;
 
        irq_state = v3_lock_irqsave(state->cons_lock);
 
-       if (send_update(dev, cur_x, cur_y, col[1], col[0]) == -1) {
+       if (send_update(state, cur_x, cur_y, col[1], col[0]) == -1) {
            PrintError("Could not send attribute to telnet session\n");
            ret = -1;
            break;
 }
 
 static int scroll(int rows, void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct cons_state * state = (struct cons_state *)dev->private_data;
+    struct cons_state * state = (struct cons_state *)private_data;
     addr_t irq_state = 0;
     int ret = 0;
 
     .scroll = scroll,
 };
 
+static int cons_free(struct vm_device * dev) {
+    return -1;
+}
+
 
 static struct v3_device_ops dev_ops = {
-    .free = NULL,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+    .free = cons_free,
 };
 
 
 
-static int key_handler(struct vm_device * dev, uint8_t ascii) {
-    struct cons_state * state = (struct cons_state *)dev->private_data;
-
+static int key_handler( struct cons_state * state, uint8_t ascii) {
     PrintDebug("Character recieved: 0x%x\n", ascii);
 
     // printable
     if (ascii < 0x80) {
        const struct key_code * key = &(ascii_to_key_code[ascii]);
 
-       if (deliver_scan_code(dev, (struct key_code *)key) == -1) {
+       if (deliver_scan_code(state, (struct key_code *)key) == -1) {
            PrintError("Could not deliver scan code to vm\n");
            return -1;
        }
 
        if (esc_seq[1] == 'A') {                // UP ARROW
            struct key_code up = { 0x48, 0 };
-           deliver_scan_code(dev, &up);
+           deliver_scan_code(state, &up);
        } else if (esc_seq[1] == 'B') {         // DOWN ARROW
            struct key_code down = { 0x50, 0 };
-           deliver_scan_code(dev, &down);
+           deliver_scan_code(state, &down);
        } else if (esc_seq[1] == 'C') {         // RIGHT ARROW
            struct key_code right = { 0x4D, 0 };
-           deliver_scan_code(dev, &right);
+           deliver_scan_code(state, &right);
        } else if (esc_seq[1] == 'D') {         // LEFT ARROW
            struct key_code left = { 0x4B, 0 };
-           deliver_scan_code(dev, &left);
+           deliver_scan_code(state, &left);
        }
     } else {
        PrintError("Invalid character received from network (%c) (code=%d)\n",
 }
 
 static int cons_server(void * arg) {
-    struct vm_device * dev = (struct vm_device *)arg;
-    struct cons_state * state = (struct cons_state *)dev->private_data;
+    struct cons_state * state = (struct cons_state *)arg;
     
     state->server_fd = V3_Create_TCP_Socket();
 
        PrintDebug("Accepted Telnet Console connection\n");
        state->connected = 1;
 
-       screen_update(0, 0, SCREEN_SIZE, dev);
+       screen_update(0, 0, SCREEN_SIZE, state);
 
        while (1) {
            recv = recv_all(state->client_fd, &ascii_code, sizeof(ascii_code));
                break;
            }
 
-           if (key_handler(dev, ascii_code) == -1) {
+           if (key_handler(state, ascii_code) == -1) {
                PrintError("Error in key handler\n");
                break;
            }
     struct vm_device * frontend = v3_find_dev(vm, v3_cfg_val(frontend_cfg, "tag"));
     char * dev_id = v3_cfg_val(cfg, "ID");
 
-
+    state->vm = vm;
     state->server_fd = 0;
     state->client_fd = 0;
     state->frontend_dev = frontend;
     }
 
 
-    v3_console_register_cga(frontend, &cons_ops, dev);
+    v3_console_register_cga(frontend, &cons_ops, state);
 
-    V3_CREATE_THREAD(cons_server, dev, "Telnet Console Network Server");
+    V3_CREATE_THREAD(cons_server, state, "Telnet Console Network Server");
 
     return 0;
 }
 
 
 static struct v3_device_ops dev_ops = {
     .free = blk_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 
 
 
 /* called by frontend, send pkt to VNET */
 static int vnet_nic_send(uint8_t * buf, uint32_t len, 
-                        void * private_data, 
-                        struct vm_device * dest_dev){
-    struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
+                        void * private_data) {
+    struct vnet_nic_state * vnetnic = (struct vnet_nic_state *)private_data;
 
     struct v3_vnet_pkt pkt;
     pkt.size = len;
 
 static struct v3_device_ops dev_ops = {
     .free = vnet_nic_free,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+
 };
 
 static struct v3_vnet_dev_ops vnet_dev_ops = {
 
     INIT_LIST_HEAD(&(mgr->blk_list));
     INIT_LIST_HEAD(&(mgr->net_list));
     INIT_LIST_HEAD(&(mgr->char_list));
-    INIT_LIST_HEAD(&(mgr->console_list));
+    INIT_LIST_HEAD(&(mgr->cons_list));
 
     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
-    mgr->console_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
+    mgr->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
     
     return 0;
 }
     v3_free_htable(mgr->blk_table, 0, 0);
     v3_free_htable(mgr->net_table, 0, 0);
     v3_free_htable(mgr->char_table, 0, 0);
-    v3_free_htable(mgr->console_table, 0, 0);
+    v3_free_htable(mgr->cons_table, 0, 0);
 
     v3_free_htable(mgr->dev_table, 0, 0);
 
 }
 
 
+struct cons_frontend {
+    int (*connect)(struct v3_vm_info * vm, 
+                  void * frontend_data, 
+                  struct v3_dev_console_ops * ops, 
+                  v3_cfg_tree_t * cfg, 
+                  void * priv_data);
+    
+
+    struct list_head cons_node;
+
+    void * priv_data;
+};
+
+int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
+                               char * name, 
+                               int (*connect)(struct v3_vm_info * vm, 
+                                              void * frontend_data, 
+                                              struct v3_dev_console_ops * ops, 
+                                              v3_cfg_tree_t * cfg, 
+                                              void * private_data), 
+                               void * priv_data)
+{
+    struct cons_frontend * frontend = NULL;
+
+    frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
+    memset(frontend, 0, sizeof(struct cons_frontend));
+    
+    frontend->connect = connect;
+    frontend->priv_data = priv_data;
+       
+    list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
+    v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
+
+    return 0;
+}
+
+
+int v3_dev_connect_console(struct v3_vm_info * vm, 
+                          char * frontend_name, 
+                          struct v3_dev_console_ops * ops, 
+                          v3_cfg_tree_t * cfg, 
+                          void * private_data)
+{
+    struct cons_frontend * frontend = NULL;
+
+    frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
+                                                       (addr_t)frontend_name);
+    
+    if (frontend == NULL) {
+       PrintError("Could not find frontend console device %s\n", frontend_name);
+       return 0;
+    }
+    
+    if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
+       PrintError("Error connecting to console frontend %s\n", frontend_name);
+       return -1;
+    }
+
+    return 0;
+}
+
 struct char_frontend {
     int (*connect)(struct v3_vm_info * vm, 
                   void * frontend_data, 
     void * priv_data;
 };
 
-
-
 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
                             char * name, 
                             int (*connect)(struct v3_vm_info * vm,