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.


Context-based output infrastructure (V3_Print, etc) and modifications to use it
[palacios.releases.git] / palacios / src / devices / serial.c
index 5151ec2..208bf0e 100644 (file)
@@ -31,7 +31,7 @@
 #include <devices/serial.h>
 
 
-#ifndef CONFIG_DEBUG_SERIAL
+#ifndef V3_CONFIG_DEBUG_SERIAL
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
@@ -258,7 +258,7 @@ struct dll_register {
 struct dlm_register {
     uint8_t data;
 };
-#define SERIAL_BUF_LEN 16
+#define SERIAL_BUF_LEN 128
 
 struct serial_buffer {
     int head; // most recent data
@@ -310,7 +310,7 @@ static struct serial_port * get_com_from_port(struct serial_state * serial, uint
     } else if ((port >= COM4_DATA_PORT) && (port <= COM4_SCRATCH_PORT)) {
        return &(serial->coms[3]);
     } else {
-       PrintError("Error: Could not find serial port associated with IO port %d\n", port);
+       PrintError(VM_NONE, VCORE_NONE, "Error: Could not find serial port associated with IO port %d\n", port);
        return NULL;
     }
 }
@@ -348,7 +348,7 @@ static int updateIRQ(struct v3_vm_info * vm, struct serial_port * com) {
     if ( (com->ier.erbfi == 0x1) && 
         (receive_buffer_trigger( getNumber(&(com->rx_buffer)), com->fcr.rx_trigger)) ) {
 
-       PrintDebug("UART: receive buffer interrupt(trigger level reached)");
+       PrintDebug(vm, VCORE_NONE, "UART: receive buffer interrupt(trigger level reached)\n");
 
        com->iir.iid = RX_IRQ_TRIGGER_LEVEL;
        v3_raise_irq(vm, com->irq_number);
@@ -370,7 +370,7 @@ static int updateIRQ(struct v3_vm_info * vm, struct serial_port * com) {
     } else if ( (com->ier.etbei == 0x1) && 
                (getNumber(&(com->tx_buffer)) != SERIAL_BUF_LEN )) {
        
-       PrintDebug("UART: transmit buffer interrupt(buffer not full)");
+       PrintDebug(vm, VCORE_NONE, "UART: transmit buffer interrupt(buffer not full)\n");
 
        com->iir.iid = TX_IRQ_THRE;
        com->iir.pending = 0;
@@ -387,12 +387,14 @@ static int queue_data(struct v3_vm_info * vm, struct serial_port * com,
     int next_loc = (buf->head + 1) % SERIAL_BUF_LEN;    
 
     if (buf->full == 1) {
-       PrintDebug("Buffer is full!\n");
+       PrintDebug(vm, VCORE_NONE, "Buffer is full!\n");
 
        if (buf == &(com->rx_buffer)) {
            com->lsr.oe = 1; //overrun error bit set
        }
 
+       updateIRQ(vm, com);
+
        return 0;
     }
     
@@ -411,9 +413,7 @@ static int queue_data(struct v3_vm_info * vm, struct serial_port * com,
        com->lsr.thre = 0; //reset thre and temt bits.
        com->lsr.temt = 0;
     }
-    
-    updateIRQ(vm, com);
-    
+        
     return 0;
 }
 
@@ -424,7 +424,7 @@ static int dequeue_data(struct v3_vm_info * vm, struct serial_port * com,
 
 
     if ( (buf->head == buf->tail) && (buf->full != 1) ) {
-       PrintDebug("no data to delete!\n");
+       PrintDebug(vm, VCORE_NONE, "no data to delete!\n");
        return -1;
     }
     
@@ -452,28 +452,28 @@ static int dequeue_data(struct v3_vm_info * vm, struct serial_port * com,
 }
 
 static int write_data_port(struct guest_info * core, uint16_t port, 
-                          void * src, uint_t length, struct vm_device * dev) {
-    struct serial_state * state = (struct serial_state *)dev->private_data;
+                          void * src, uint_t length, void * priv_data) {
+    struct serial_state * state = priv_data;
     uint8_t * val = (uint8_t *)src;
     struct serial_port * com_port = NULL;
 
-    PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *val);
+    PrintDebug(core->vm_info, core, "Write to Data Port 0x%x (val=%x)\n", port, *val);
     
     if (length != 1) {
-       PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
+       PrintError(core->vm_info, core, "Invalid length(%d) in write to 0x%x\n", length, port);
        return -1;
     }
 
     if ((port != COM1_DATA_PORT) && (port != COM2_DATA_PORT) && 
        (port != COM3_DATA_PORT) && (port != COM4_DATA_PORT)) {
-       PrintError("Serial Read data port for illegal port Number (%d)\n", port);
+       PrintError(core->vm_info, core, "Serial Read data port for illegal port Number (%d)\n", port);
        return -1;
     }
 
     com_port = get_com_from_port(state, port);
 
     if (com_port == NULL) {
-       PrintDebug("UART:read from NOBODY");
+       PrintError(core->vm_info, core, "UART:read from NOBODY\n");
        return -1;
     }
     
@@ -486,9 +486,10 @@ static int write_data_port(struct guest_info * core, uint16_t port,
 
        /* JRL: Some buffering would probably be a good idea here.... */
        if (com_port->ops) {
-           com_port->ops->write(val, 1, com_port->backend_data);
+           com_port->ops->output(val, 1, com_port->backend_data);
        } else {
            queue_data(core->vm_info, com_port, &(com_port->tx_buffer), *val);
+           updateIRQ(core->vm_info, com_port);
        }
     }
     
@@ -498,28 +499,28 @@ static int write_data_port(struct guest_info * core, uint16_t port,
 
 
 static int read_data_port(struct guest_info * core, uint16_t port, 
-                         void * dst, uint_t length, struct vm_device * dev) {
-    struct serial_state * state = (struct serial_state *)dev->private_data;
+                         void * dst, uint_t length, void * priv_data) {
+    struct serial_state * state = priv_data;
     uint8_t * val = (uint8_t *)dst;
     struct serial_port * com_port = NULL;
 
-    PrintDebug("Read from Data Port 0x%x\n", port);
+    PrintDebug(core->vm_info, core, "Read from Data Port 0x%x\n", port);
     
     if (length != 1) {
-       PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
+       PrintError(core->vm_info, core, "Invalid length(%d) in write to 0x%x\n", length, port);
        return -1;
     }
     
     if ((port != COM1_DATA_PORT) && (port != COM2_DATA_PORT) && 
        (port != COM3_DATA_PORT) && (port != COM4_DATA_PORT)) {
-       PrintError("Serial Read data port for illegal port Number (%d)\n", port);
+       PrintError(core->vm_info, core, "Serial Read data port for illegal port Number (%d)\n", port);
        return -1;
     }
 
     com_port = get_com_from_port(state, port);
 
     if (com_port == NULL) {
-       PrintDebug("UART:read from NOBODY");
+       PrintError(core->vm_info, core, "UART:read from NOBODY\n");
        return -1;
     }
     
@@ -581,22 +582,22 @@ static int handle_fcr_write(struct serial_port * com, uint8_t value) {
 
 
 static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, 
-                          uint_t length, struct vm_device * dev) {
-    struct serial_state * state = (struct serial_state *)dev->private_data;
+                          uint_t length, void * priv_data) {
+    struct serial_state * state = priv_data;
     uint8_t val = *(uint8_t *)src;
     struct serial_port * com_port = NULL;
 
-    PrintDebug("UART:Write to Control Port (val=%x)\n", val);
+    PrintDebug(core->vm_info, core, "UART:Write to Control Port (val=%x)\n", val);
     
     if (length != 1) {
-       PrintDebug("UART:Invalid Write length to control port%d\n", port);
+       PrintError(core->vm_info, core, "UART:Invalid Write length to control port%d\n", port);
        return -1;
     }
 
     com_port = get_com_from_port(state, port);
 
     if (com_port == NULL) {
-       PrintError("Could not find serial port corresponding to IO port %d\n", port);
+       PrintError(core->vm_info, core, "Could not find serial port corresponding to IO port %d\n", port);
        return -1;
     }
     
@@ -606,7 +607,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src,
        case COM2_IRQ_ENABLE_PORT:
        case COM3_IRQ_ENABLE_PORT:
        case COM4_IRQ_ENABLE_PORT: {
-           PrintDebug("UART:Write to IER/LATCH port: dlab is %x\n", com_port->lcr.dlab);
+           PrintDebug(core->vm_info, core, "UART:Write to IER/LATCH port: dlab is %x\n", com_port->lcr.dlab);
 
            if (com_port->lcr.dlab == 1) {
                com_port->dlm.data = val;
@@ -620,7 +621,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src,
        case COM2_FIFO_CTRL_PORT:
        case COM3_FIFO_CTRL_PORT:
        case COM4_FIFO_CTRL_PORT: {
-           PrintDebug("UART:Write to FCR");
+           PrintDebug(core->vm_info, core, "UART:Write to FCR\n");
 
            if (handle_fcr_write(com_port, val) == -1) {
                return -1;
@@ -632,7 +633,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src,
        case COM2_LINE_CTRL_PORT:
        case COM3_LINE_CTRL_PORT:
        case COM4_LINE_CTRL_PORT: {
-           PrintDebug("UART:Write to LCR");
+           PrintDebug(core->vm_info, core, "UART:Write to LCR\n");
            com_port->lcr.val = val;
            break;
        }
@@ -640,7 +641,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src,
        case COM2_MODEM_CTRL_PORT:
        case COM3_MODEM_CTRL_PORT:
        case COM4_MODEM_CTRL_PORT: {
-           PrintDebug("UART:Write to MCR");
+           PrintDebug(core->vm_info, core, "UART:Write to MCR\n");
            com_port->mcr.val = val;
            break;
        }
@@ -648,12 +649,12 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src,
        case COM2_SCRATCH_PORT:
        case COM3_SCRATCH_PORT:
        case COM4_SCRATCH_PORT: {
-           PrintDebug("UART:Write to SCRATCH");
+           PrintDebug(core->vm_info, core, "UART:Write to SCRATCH\n");
            com_port->scr.data = val;
            break;
        }
        default:
-           PrintDebug("UART:Write to NOBODY, ERROR");
+           PrintError(core->vm_info, core, "UART:Write to NOBODY, ERROR\n");
            return -1;
     }
     
@@ -665,22 +666,22 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src,
 
 
 static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, 
-                         uint_t length, struct vm_device * dev) {
-    struct serial_state * state = (struct serial_state *)dev->private_data;
+                         uint_t length, void * priv_data) {
+    struct serial_state * state = priv_data;
     uint8_t * val = (uint8_t *)dst;
     struct serial_port * com_port = NULL;
 
-    PrintDebug("Read from Control Port\n");
+    PrintDebug(core->vm_info, core, "Read from Control Port\n");
     
     if (length != 1) {
-       PrintDebug("Invalid Read length to control port\n");
+       PrintError(core->vm_info, core, "Invalid Read length to control port\n");
        return -1;
     }
 
     com_port = get_com_from_port(state, port);
 
     if (com_port == NULL) {
-       PrintError("Could not find serial port corresponding to IO port %d\n", port);
+       PrintError(core->vm_info, core, "Could not find serial port corresponding to IO port %d\n", port);
        return -1;
     }
     
@@ -690,7 +691,7 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst,
        case COM2_IRQ_ENABLE_PORT:
        case COM3_IRQ_ENABLE_PORT:
        case COM4_IRQ_ENABLE_PORT: {
-           PrintDebug("UART:read from IER");
+           PrintDebug(core->vm_info, core, "UART:read from IER\n");
 
            if (com_port->lcr.dlab == 1) {
                *val = com_port->dlm.data;
@@ -700,19 +701,19 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst,
            break;
        }
 
-       case COM1_FIFO_CTRL_PORT:
-       case COM2_FIFO_CTRL_PORT:
-       case COM3_FIFO_CTRL_PORT:
-       case COM4_FIFO_CTRL_PORT:
-           PrintDebug("UART:read from FCR");
-           *val = com_port->fcr.val;
+       case COM1_IIR_PORT:
+       case COM2_IIR_PORT:
+       case COM3_IIR_PORT:
+       case COM4_IIR_PORT:
+           PrintDebug(core->vm_info, core, "UART:read from IIR\n");
+           *val = com_port->iir.val;
            break;
 
        case COM1_LINE_CTRL_PORT:
        case COM2_LINE_CTRL_PORT:
        case COM3_LINE_CTRL_PORT:
        case COM4_LINE_CTRL_PORT:
-           PrintDebug("UART:read from LCR");
+           PrintDebug(core->vm_info, core, "UART:read from LCR\n");
            *val = com_port->lcr.val;
            break;
 
@@ -720,7 +721,7 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst,
        case COM2_MODEM_CTRL_PORT:
        case COM3_MODEM_CTRL_PORT:
        case COM4_MODEM_CTRL_PORT:
-           PrintDebug("UART:read from MCR");
+           PrintDebug(core->vm_info, core, "UART:read from MCR\n");
            *val = com_port->mcr.val;
            break;
 
@@ -728,12 +729,12 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst,
        case COM2_SCRATCH_PORT:
        case COM3_SCRATCH_PORT:
        case COM4_SCRATCH_PORT:
-           PrintDebug("UART:read from SCRATCH");
+           PrintDebug(core->vm_info, core, "UART:read from SCRATCH\n");
            *val = com_port->scr.data;
            break;
 
        default:
-           PrintDebug("UART:read from NOBODY");
+           PrintError(core->vm_info, core, "UART:read from NOBODY\n");
            return -1;
     }
 
@@ -742,22 +743,22 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst,
 
 
 static int write_status_port(struct guest_info * core, uint16_t port, void * src, 
-                            uint_t length, struct vm_device * dev) {
-    struct serial_state * state = (struct serial_state *)dev->private_data;
+                            uint_t length, void * priv_data) {
+    struct serial_state * state = priv_data;
     uint8_t val = *(uint8_t *)src;
     struct serial_port * com_port = NULL;
 
-    PrintDebug("Write to Status Port (val=%x)\n", val);
+    PrintDebug(core->vm_info, core, "Write to Status Port (val=%x)\n", val);
 
     if (length != 1) {
-       PrintDebug("Invalid Write length to status port %d\n", port);
+       PrintError(core->vm_info, core, "Invalid Write length to status port %d\n", port);
        return -1;
     }
 
     com_port = get_com_from_port(state, port);
 
     if (com_port == NULL) {
-       PrintError("Could not find serial port corresponding to IO port %d\n", port);
+       PrintError(core->vm_info, core, "Could not find serial port corresponding to IO port %d\n", port);
        return -1;
     }
 
@@ -766,7 +767,7 @@ static int write_status_port(struct guest_info * core, uint16_t port, void * src
        case COM2_LINE_STATUS_PORT:
        case COM3_LINE_STATUS_PORT:
        case COM4_LINE_STATUS_PORT:
-           PrintDebug("UART:write to LSR");
+           PrintDebug(core->vm_info, core, "UART:write to LSR\n");
            com_port->lsr.val = val;
            break;
 
@@ -774,12 +775,12 @@ static int write_status_port(struct guest_info * core, uint16_t port, void * src
        case COM2_MODEM_STATUS_PORT:
        case COM3_MODEM_STATUS_PORT:
        case COM4_MODEM_STATUS_PORT:
-           PrintDebug("UART:write to MSR");
+           PrintDebug(core->vm_info, core, "UART:write to MSR\n");
            com_port->msr.val = val;
            break;
 
        default:
-           PrintDebug("UART:write to NOBODY");
+           PrintError(core->vm_info, core, "UART:write to NOBODY\n");
            return -1;
     }
 
@@ -787,22 +788,17 @@ static int write_status_port(struct guest_info * core, uint16_t port, void * src
 }
 
 static int read_status_port(struct guest_info * core, uint16_t port, void * dst, 
-                           uint_t length, struct vm_device * dev) {
-    struct serial_state * state = (struct serial_state *)dev->private_data;
+                           uint_t length, void * priv_data) {
+    struct serial_state * state = priv_data;
     uint8_t * val = (uint8_t *)dst;
     struct serial_port * com_port = NULL;
 
-    PrintDebug("Read from Status Port 0x%x\n", port);
-
-    if (length != 1) {
-       PrintDebug("Invalid Read length to control port\n");
-       return -1;
-    }
+    PrintDebug(core->vm_info, core, "Read from Status Port 0x%x\n", port);
 
     com_port = get_com_from_port(state, port);
 
     if (com_port == NULL) {
-       PrintError("Could not find serial port corresponding to IO port %d\n", port);
+       PrintError(core->vm_info, core, "Could not find serial port corresponding to IO port %d\n", port);
        return -1;
     }
 
@@ -811,7 +807,13 @@ static int read_status_port(struct guest_info * core, uint16_t port, void * dst,
        case COM2_LINE_STATUS_PORT:
        case COM3_LINE_STATUS_PORT:
        case COM4_LINE_STATUS_PORT:
-           PrintDebug("UART:read from LSR");
+
+           if (length != 1) {
+               PrintError(core->vm_info, core, "Invalid Read length to control port\n");
+               return -1;
+           }
+
+           PrintDebug(core->vm_info, core, "UART:read from LSR\n");
 
            *val = com_port->lsr.val;
            com_port->lsr.oe = 0;     // Why do we clear this??
@@ -822,69 +824,204 @@ static int read_status_port(struct guest_info * core, uint16_t port, void * dst,
        case COM2_MODEM_STATUS_PORT:
        case COM3_MODEM_STATUS_PORT:
        case COM4_MODEM_STATUS_PORT:
-           PrintDebug("UART:read from COM4 MSR");
+           PrintDebug(core->vm_info, core, "UART:read from COM4 MSR (length = %d)\n", length);
+
+           if (length > 2) {
+               PrintError(core->vm_info, core, "Invalid Read length to MSR port\n");
+               return -1;
+           }
+
+           if (length == 2) {
+               /* Windows XP expects to be able to read this register and the next in one go */
+
+               if (read_ctrl_port(core, port + 1, val + 1, 1, priv_data) < 0) {
+                   PrintError(core->vm_info, core, "Error reading control port for word size read of Status register\n");
+                   return -1;
+               }
+           }
+
+           // always read low byte...
+           
            *val = com_port->msr.val;
            break;
 
        default:
-           PrintDebug("UART:read from NOBODY");
+           PrintError(core->vm_info, core, "UART:read from NOBODY (length = %d)\n", length);
            return -1;
     }
 
     return length;
 }
 
-static int serial_deinit(struct vm_device * dev) {
-
-
-    v3_dev_unhook_io(dev, COM1_DATA_PORT);
-    v3_dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
-    v3_dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM1_SCRATCH_PORT);
-
-    v3_dev_unhook_io(dev, COM2_DATA_PORT);
-    v3_dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
-    v3_dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM2_SCRATCH_PORT);
-
-    v3_dev_unhook_io(dev, COM3_DATA_PORT);
-    v3_dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
-    v3_dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM3_SCRATCH_PORT);
-
-    v3_dev_unhook_io(dev, COM4_DATA_PORT);
-    v3_dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
-    v3_dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
-    v3_dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
-    v3_dev_unhook_io(dev, COM4_SCRATCH_PORT);
+static int serial_free(struct serial_state * state) {
 
+    V3_Free(state);
     return 0;
 }
 
 
 
+#ifdef V3_CONFIG_CHECKPOINT
+
+#include <palacios/vmm_sprintf.h>
+
+static int serial_buffer_save(struct v3_chkpt_ctx * ctx, int port, struct serial_buffer *sb) {
+  
+  char keyname[128];
+  
+  snprintf(keyname,128,"COM%d_SB_HEAD", port);
+  V3_CHKPT_SAVE(ctx,keyname,sb->head,failout);
+  snprintf(keyname,128,"COM%d_SB_TAIL", port);
+  V3_CHKPT_SAVE(ctx,keyname,sb->tail,failout);
+  snprintf(keyname,128,"COM%d_SB_FULL", port);
+  V3_CHKPT_SAVE(ctx,keyname,sb->full,failout);
+  snprintf(keyname,128,"COM%d_SB_DATA", port);
+  V3_CHKPT_SAVE(ctx,keyname,sb->buffer,failout);
+  
+  return 0;
+  
+ failout:
+  PrintError(VM_NONE, VCORE_NONE, "Failed to save serial buffer\n");
+  return -1;
+}
+
+static int serial_buffer_load(struct v3_chkpt_ctx * ctx, int port,  struct serial_buffer *sb) {
+
+  char keyname[128];
+
+  snprintf(keyname,128,"COM%d_SB_HEAD", port);
+  V3_CHKPT_LOAD(ctx,keyname,sb->head,failout);
+  snprintf(keyname,128,"COM%d_SB_TAIL", port);
+  V3_CHKPT_LOAD(ctx,keyname,sb->tail,failout);
+  snprintf(keyname,128,"COM%d_SB_FULL", port);
+  V3_CHKPT_LOAD(ctx,keyname,sb->full,failout);
+  snprintf(keyname,128,"COM%d_SB_DATA", port);
+  V3_CHKPT_LOAD(ctx,keyname,sb->buffer,failout);
+  
+  return 0;
+  
+ failout:
+  PrintError(VM_NONE, VCORE_NONE, "Failed to load serial buffer\n");
+  return -1;
+}
+static int serial_save(struct v3_chkpt_ctx * ctx, void * private_data) {
+  struct serial_state *state = (struct serial_state *)private_data;
+  struct serial_port *serial;
+  char keyname[128];
+  int i;
+  
+  for (i=0;i<4;i++) { 
+    serial = &(state->coms[i]);
+    snprintf(keyname, 128,"COM%d_RBR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->rbr.data,failout);
+    snprintf(keyname, 128,"COM%d_THR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->thr.data,failout);
+    snprintf(keyname, 128,"COM%d_IER",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->ier.val,failout);
+    snprintf(keyname, 128,"COM%d_IIR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->iir.val,failout);
+    snprintf(keyname, 128,"COM%d_FCR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->fcr.val,failout);
+    snprintf(keyname, 128,"COM%d_LCR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->lcr.val,failout);
+    snprintf(keyname, 128,"COM%d_MCR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->mcr.val,failout);
+    snprintf(keyname, 128,"COM%d_LSR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->lsr.val,failout);
+    snprintf(keyname, 128,"COM%d_MSR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->msr.val,failout);
+    snprintf(keyname, 128,"COM%d_SCR",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->scr.data,failout);
+    snprintf(keyname, 128,"COM%d_DLL",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->dll.data,failout);
+    snprintf(keyname, 128,"COM%d_DLM",i);
+    V3_CHKPT_SAVE(ctx, keyname, serial->dlm.data,failout);
+    
+    if (serial_buffer_save(ctx, i, &(serial->tx_buffer))) { 
+      PrintError(VM_NONE, VCORE_NONE, "Failed to save serial tx buffer %d\n",i);
+      goto failout;
+    }
+    
+    if (serial_buffer_save(ctx, i, &(serial->rx_buffer))) { 
+      PrintError(VM_NONE, VCORE_NONE, "Failed to save serial rx buffer %d\n",i);
+      goto failout;
+    }
+    
+    V3_CHKPT_SAVE(ctx, keyname, serial->irq_number,failout);
+  }
+
+  return 0;
+
+ failout:
+  PrintError(VM_NONE, VCORE_NONE, "Failed to save serial device\n");
+  return -1;
+  
+}
+static int serial_load(struct v3_chkpt_ctx * ctx, void * private_data) {
+  struct serial_state *state = (struct serial_state *)private_data;
+  struct serial_port *serial;
+  char keyname[128];
+  int i;
+  
+  for (i=0;i<4;i++) { 
+    serial = &(state->coms[i]);
+    snprintf(keyname, 128,"COM%d_RBR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->rbr.data,failout);
+    snprintf(keyname, 128,"COM%d_THR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->thr.data,failout);
+    snprintf(keyname, 128,"COM%d_IER",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->ier.val,failout);
+    snprintf(keyname, 128,"COM%d_IIR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->iir.val,failout);
+    snprintf(keyname, 128,"COM%d_FCR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->fcr.val,failout);
+    snprintf(keyname, 128,"COM%d_LCR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->lcr.val,failout);
+    snprintf(keyname, 128,"COM%d_MCR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->mcr.val,failout);
+    snprintf(keyname, 128,"COM%d_LSR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->lsr.val,failout);
+    snprintf(keyname, 128,"COM%d_MSR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->msr.val,failout);
+    snprintf(keyname, 128,"COM%d_SCR",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->scr.data,failout);
+    snprintf(keyname, 128,"COM%d_DLL",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->dll.data,failout);
+    snprintf(keyname, 128,"COM%d_DLM",i);
+    V3_CHKPT_LOAD(ctx, keyname, serial->dlm.data,failout);
+    
+    if (serial_buffer_load(ctx, i, &(serial->tx_buffer))) { 
+      PrintError(VM_NONE, VCORE_NONE, "Failed to load serial tx buffer %d\n",i);
+      goto failout;
+    }
+    
+    if (serial_buffer_load(ctx, i, &(serial->rx_buffer))) { 
+      PrintError(VM_NONE, VCORE_NONE, "Failed to load serial rx buffer %d\n",i);
+      goto failout;
+    }
+    
+    V3_CHKPT_LOAD(ctx, keyname, serial->irq_number,failout);
+  }
+
+  return 0;
+
+ failout:
+  PrintError(VM_NONE, VCORE_NONE,"Failed to load serial device\n");
+  return -1;
+  
+}
+
+#endif
 
 static struct v3_device_ops dev_ops = {
-    //.init = serial_init,
-    .free = serial_deinit,
-    .reset = NULL,
-    .start = NULL,
-    .stop = NULL,
+    .free = (int (*)(void *))serial_free,
+#ifdef V3_CONFIG_CHECKPOINT
+    .save = serial_save, 
+    .load = serial_load
+#endif
 };
 
 
@@ -918,7 +1055,7 @@ static int init_serial_port(struct serial_port * com) {
     return 0;
 }
 
-static int serial_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * priv_data){
+static uint64_t serial_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * priv_data){
     struct serial_port * com_port = (struct serial_port *)priv_data;
     int i;
 
@@ -926,6 +1063,8 @@ static int serial_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, voi
        queue_data(vm, com_port, &(com_port->rx_buffer), buf[i]);
     }
 
+    updateIRQ(vm, com_port);
+
     return len;
 }
 
@@ -943,14 +1082,14 @@ static int connect_fn(struct v3_vm_info * vm,
     int com_idx = 0;
 
     if (com_port == NULL) {
-       PrintError("Invalid Serial frontend config: missing \"com_port\"\n");
+        PrintError(vm, VCORE_NONE, "Invalid Serial frontend config: missing \"com_port\"\n");
        return -1;
     }
     
     com_idx = atoi(com_port) - 1;
 
     if ((com_idx > 3) || (com_idx < 0)) {
-       PrintError("Invalid Com port (%s) \n", com_port);
+      PrintError(vm, VCORE_NONE, "Invalid Com port (%s) \n", com_port);
        return -1;
     }
 
@@ -959,7 +1098,7 @@ static int connect_fn(struct v3_vm_info * vm,
     com->ops = ops;
     com->backend_data = private_data;
 
-    com->ops->push = serial_input;
+    com->ops->input = serial_input;
     *push_fn_arg = com;
 
     return 0;
@@ -968,18 +1107,17 @@ static int connect_fn(struct v3_vm_info * vm,
 static int serial_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     struct serial_state * state = NULL;
     char * dev_id = v3_cfg_val(cfg, "ID");
+    int ret = 0;
 
     state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
     
     if (state == NULL) {
-       PrintError("Could not allocate Serial Device\n");
+        PrintError(vm,VCORE_NONE, "Could not allocate Serial Device\n");
        return -1;
     }
     
     memset(state, 0, sizeof(struct serial_state));
 
-
-
     init_serial_port(&(state->coms[0]));
     init_serial_port(&(state->coms[1]));
     init_serial_port(&(state->coms[2]));
@@ -991,57 +1129,65 @@ static int serial_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     state->coms[3].irq_number = COM4_IRQ;
 
 
-    struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, state);
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
+
+    if (dev == NULL) {
+       PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
+       V3_Free(state);
+       return -1;
+    }
 
-    if (v3_attach_device(vm, dev) == -1) {
-       PrintError("Could not attach device %s\n", dev_id);
+    PrintDebug(vm, VCORE_NONE, "Serial device attached\n");
+
+    ret |= v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
+    ret |= v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+    ret |= v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
+    ret |= v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+    ret |= v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
+    ret |= v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+    ret |= v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
+    ret |= v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+    ret |= v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+    ret |= v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+    if (ret != 0) {
+       PrintError(vm, VCORE_NONE, "Error hooking Serial IO ports\n");
+       v3_remove_device(dev);
        return -1;
     }
 
-    PrintDebug("Serial device attached\n");
-
-    v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
-    v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-    v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
-    v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-    v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
-    v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-    v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
-    v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-    v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-    v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-    PrintDebug("Serial ports hooked\n");
+    PrintDebug(vm, VCORE_NONE, "Serial ports hooked\n");
 
 
 
     if (v3_dev_add_char_frontend(vm, dev_id, connect_fn, (void *)state) == -1) {
-       PrintError("Could not register %s as frontend\n", dev_id);
+       PrintError(vm, VCORE_NONE, "Could not register %s as frontend\n", dev_id);
+       v3_remove_device(dev);
        return -1;
     }