#include <devices/serial.h>
-#ifndef CONFIG_DEBUG_SERIAL
+#ifndef V3_CONFIG_DEBUG_SERIAL
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
struct dlm_register {
uint8_t data;
};
-#define SERIAL_BUF_LEN 16
+#define SERIAL_BUF_LEN 128
struct serial_buffer {
int head; // most recent data
} 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;
}
}
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);
} 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;
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;
}
com->lsr.thre = 0; //reset thre and temt bits.
com->lsr.temt = 0;
}
-
- updateIRQ(vm, com);
-
+
return 0;
}
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;
}
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;
}
/* 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);
}
}
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;
}
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;
}
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;
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;
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;
}
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;
}
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;
}
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;
}
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;
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;
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;
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;
}
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;
}
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;
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;
}
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;
}
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??
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_free(struct vm_device * dev) {
+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 = {
- .free = serial_free,
+ .free = (int (*)(void *))serial_free,
+#ifdef V3_CONFIG_CHECKPOINT
+ .save = serial_save,
+ .load = serial_load
+#endif
};
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;
queue_data(vm, com_port, &(com_port->rx_buffer), buf[i]);
}
+ updateIRQ(vm, com_port);
+
return len;
}
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;
}
com->ops = ops;
com->backend_data = private_data;
- com->ops->push = serial_input;
+ com->ops->input = serial_input;
*push_fn_arg = com;
return 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;
}
struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
if (dev == NULL) {
- PrintError("Could not attach device %s\n", dev_id);
+ PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
V3_Free(state);
return -1;
}
- PrintDebug("Serial device attached\n");
+ 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, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
if (ret != 0) {
- PrintError("Error hooking Serial IO ports\n");
+ PrintError(vm, VCORE_NONE, "Error hooking Serial IO ports\n");
v3_remove_device(dev);
return -1;
}
- 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;
}