-/* Northwestern University */
-/* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2010, Rumou Duan <duanrumou@gmail.com>
+ * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Rumou Duan <duanrumou@gmail.com>
+ * Lei Xia <lxia@northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
-#include <devices/serial.h>
#include <palacios/vmm.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vmm_types.h>
+
+#include <palacios/vmm_ringbuffer.h>
+#include <palacios/vmm_lock.h>
+#include <palacios/vmm_intr.h>
+#include <palacios/vm_guest.h>
+
+#include <devices/serial.h>
+
+
+#ifndef CONFIG_DEBUG_SERIAL
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
#define COM1_DATA_PORT 0x3f8
#define COM4_SCRATCH_PORT 0x2ef
-
-struct irq_enable_reg {
- uint_t erbfi : 1; // Enable Receiver Buffer full interrupt
- uint_t etbei : 1; // Enable Transmit buffer empty interrupt
- uint_t elsi : 1; // Enable Line Status Interrupt
- uint_t edssi : 1; // Enable Delta Status signals interrupt
- uint_t rsvd : 4; // MBZ
-};
-
-
-
// Interrupt IDs (in priority order, highest is first)
#define STATUS_IRQ_LSR_OE_SET 0x3
#define STATUS_IRQ_LSR_PE_SET 0x3
#define TX_IRQ_THRE 0x1
#define MODEL_IRQ_DELTA_SET 0x0
-struct irq_id_reg {
- uint_t pending : 1; // Interrupt pending (0=interrupt pending)
- uint_t iid : 3; // Interrupt Identification
- uint_t rsvd : 2; // MBZ
- uint_t fifo_en : 2; // FIFO enable
-};
+//COMs IRQ ID
+#define COM1_IRQ 0x4
+#define COM2_IRQ 0x3
+#define COM3_IRQ 0x4
+#define COM4_IRQ 0x3
+
+#define RX_BUFFER 0x1
+#define TX_BUFFER 0x2
+
+//initial value for registers
+
+#define IER_INIT_VAL 0x3
+//receive data available interrupt and THRE interrupt are enabled
+#define IIR_INIT_VAL 0x1
+//No Pending Interrupt bit is set.
+#define FCR_INIT_VAL 0xc0
+//fifo control register is set to 0
+#define LCR_INIT_VAL 0x3
+#define MCR_INIT_VAL 0x0
+#define LSR_INIT_VAL 0x60
+#define MSR_INIT_VAL 0x0
+#define DLL_INIT_VAL 0x1
+#define DLM_INIT_VAL 0x0
+
+
-struct fifo_ctrl_reg {
- uint_t enable : 1; // enable fifo
- uint_t rfres : 1; // RX FIFO reset
- uint_t xfres : 1; // TX FIFO reset
- uint_t dma_sel : 1; // DMA mode select
- uint_t rsvd : 2; // MBZ
- uint_t rx_trigger: 2; // RX FIFO trigger level select
+//receiver buffer register
+struct rbr_register {
+ uint8_t data;
};
-struct line_ctrl_reg {
- uint_t word_len : 2; // word length select
- uint_t stop_bits : 1; // Stop Bit select
- uint_t parity_enable : 1; // Enable parity
- uint_t even_sel : 1; // Even Parity Select
- uint_t stick_parity : 1; // Stick Parity Select
- uint_t sbr : 1; // Set Break
- uint_t dlab : 1; // Divisor latch access bit
+// transmitter holding register
+struct thr_register {
+ uint8_t data;
};
+//interrupt enable register
+struct ier_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t erbfi : 1; // Enable Receiver Buffer full interrupt
+ uint8_t etbei : 1; // Enable Transmit buffer empty interrupt
+ uint8_t elsi : 1; // Enable Line Status Interrupt
+ uint8_t edssi : 1; // Enable Delta Status signals interrupt
+ uint8_t rsvd : 4; // MBZ
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+//interrupt identification register
+struct iir_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t pending : 1; // Interrupt pending (0=interrupt pending)
+ uint8_t iid : 3; // Interrupt Identification
+ uint8_t rsvd : 2; // MBZ
+ uint8_t fifo_en : 2; // FIFO enable
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+//FIFO control register
+struct fcr_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t enable : 1; // enable fifo
+ uint8_t rfres : 1; // RX FIFO reset
+ uint8_t xfres : 1; // TX FIFO reset
+ uint8_t dma_sel : 1; // DMA mode select
+ uint8_t rsvd : 2; // MBZ
+ uint8_t rx_trigger: 2; // RX FIFO trigger level select
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+//line control register
+struct lcr_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t word_len : 2; // word length select
+ uint8_t stop_bits : 1; // Stop Bit select
+ uint8_t parity_enable : 1; // Enable parity
+ uint8_t even_sel : 1; // Even Parity Select
+ uint8_t stick_parity : 1; // Stick Parity Select
+ uint8_t sbr : 1; // Set Break
+ uint8_t dlab : 1; // Divisor latch access bit
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+//modem control register
+struct mcr_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t dtr : 1;
+ uint8_t rts : 1;
+ uint8_t out1 : 1;
+ uint8_t out2 : 1;
+ uint8_t loop : 1; // loopback mode
+ uint8_t rsvd : 3; // MBZ
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+//line status register
+struct lsr_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t dr : 1; // data ready
+ uint8_t oe : 1; // Overrun error
+ uint8_t pe : 1; // Parity Error
+ uint8_t fe : 1; // Framing Error
+ uint8_t brk : 1; // broken line detected
+ uint8_t thre : 1; // Transmitter holding register empty
+ uint8_t temt : 1; // Transmitter Empty
+ uint8_t fifo_err : 1; // at least one error is pending in the RX FIFO chain
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct msr_register {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t dcts : 1; // Delta Clear To Send
+ uint8_t ddsr : 1; // Delta Data Set Ready
+ uint8_t teri : 1; // Trailing Edge Ring Indicator
+ uint8_t ddcd : 1; // Delta Data Carrier Detect
+ uint8_t cts : 1; // Clear to Send
+ uint8_t dsr : 1; // Data Set Ready
+ uint8_t ri : 1; // Ring Indicator
+ uint8_t dcd : 1; // Data Carrier Detect
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+//scratch register
+struct scr_register {
+ uint8_t data;
+};
-struct modem_ctrl_reg {
- uint_t dtr : 1;
- uint_t rts : 1;
- uint_t out1 : 1;
- uint_t out2 : 1;
- uint_t loop : 1; // loopback mode
- uint_t rsvd : 3; // MBZ
+//divisor latch LSB
+struct dll_register {
+ uint8_t data;
};
+//divisor latch MSB
+struct dlm_register {
+ uint8_t data;
+};
+#define SERIAL_BUF_LEN 16
-struct line_status_reg {
- uint_t rbf : 1; // Receiver Buffer Full
- uint_t oe : 1; // Overrun error
- uint_t pe : 1; // Parity Error
- uint_t fe : 1; // Framing Error
- uint_t brk : 1; // broken line detected
- uint_t thre : 1; // Transmitter holding register empty
- uint_t temt : 1; // Transmitter Empty
- uint_t fifo_err : 1; // at least one error is pending in the RX FIFO chain
+struct serial_buffer {
+ int head; // most recent data
+ int tail; // oldest char
+ int full;
+ uint8_t buffer[SERIAL_BUF_LEN];
};
+struct serial_port {
+ struct rbr_register rbr;
+ struct thr_register thr;
+ struct ier_register ier;
+ struct iir_register iir;
+ struct fcr_register fcr;
+ struct lcr_register lcr;
+ struct mcr_register mcr;
+ struct lsr_register lsr;
+ struct msr_register msr;
+ struct scr_register scr;
+ struct dll_register dll;
+ struct dlm_register dlm;
+
+
+ struct serial_buffer tx_buffer;
+ struct serial_buffer rx_buffer;
+ uint_t irq_number;
+
+
+ void * backend_data;
+ struct v3_dev_char_ops * ops;
-struct modem_status_reg {
- uint_t dcts : 1; // Delta Clear To Send
- uint_t ddsr : 1; // Delta Data Set Ready
- uint_t teri : 1; // Trailing Edge Ring Indicator
- uint_t ddcd : 1; // Delta Data Carrier Detect
- uint_t cts : 1; // Clear to Send
- uint_t dsr : 1; // Data Set Ready
- uint_t ri : 1; // Ring Indicator
- uint_t dcd : 1; // Data Carrier Detect
};
-#define SERIAL_BUF_LEN 256
+struct serial_state {
+ struct serial_port coms[4];
-struct serial_buffer {
- uint_t head; // most recent data
- uint_t tail; // oldest char
- char buffer[SERIAL_BUF_LEN];
};
-int queue_data(struct serial_buffer * buf, char data) {
- int next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
- if (next_loc == buf->tail) {
- return -1;
- }
- buf->buffer[next_loc] = data;
- buf->head = next_loc;
+static struct serial_port * get_com_from_port(struct serial_state * serial, uint16_t port) {
+ if ((port >= COM1_DATA_PORT) && (port <= COM1_SCRATCH_PORT)) {
+ return &(serial->coms[0]);
+ } else if ((port >= COM2_DATA_PORT) && (port <= COM2_SCRATCH_PORT)) {
+ return &(serial->coms[1]);
+ } else if ((port >= COM3_DATA_PORT) && (port <= COM3_SCRATCH_PORT)) {
+ return &(serial->coms[2]);
+ } 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);
+ return NULL;
+ }
+}
+
+static inline bool receive_buffer_trigger(int number, int trigger_number) {
+
+ switch (trigger_number) {
+ case 0:
+ return (number >= 1);
+ case 1:
+ return (number >= 4);
+ case 2:
+ return (number >= 8);
+ case 3:
+ return (number >= 14);
+ }
- return 0;
+ return false;
}
-int dequeue_data(struct serial_buffer * buf, char * data) {
- int next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
+static int getNumber(struct serial_buffer * buf) {
+ int number = buf->head - buf->tail;
+
+ if (buf->full == 1) {
+ return SERIAL_BUF_LEN;
+ } else if (number >= 0) {
+ return number;
+ } else {
+ return SERIAL_BUF_LEN + number;
+ }
+}
- if (buf->head == buf->tail) {
- return -1;
- }
+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)) ) {
- *data = buf->buffer[buf->tail];
- buf->tail = next_tail;
+ PrintDebug("UART: receive buffer interrupt(trigger level reached)\n");
- return 0;
-}
+ com->iir.iid = RX_IRQ_TRIGGER_LEVEL;
+ v3_raise_irq(vm, com->irq_number);
+ }
+
+ if ( (com->iir.iid == RX_IRQ_TRIGGER_LEVEL) &&
+ (!(receive_buffer_trigger( getNumber(&(com->rx_buffer)), com->fcr.rx_trigger))) ) {
+ com->iir.iid = 0x0; //reset interrupt identification register
+ com->iir.pending = 0x1;
+ }
+
+ if ( (com->iir.iid == TX_IRQ_THRE) &&
+ (getNumber(&(com->tx_buffer)) == SERIAL_BUF_LEN)) {
-struct serial_port {
- char ier;
- char iir;
- char fcr;
- char lcr;
- char mcr;
- char lsr;
- char msr;
-
- struct serial_buffer tx_buffer;
- struct serial_buffer rx_buffer;
-};
+ com->iir.iid = 0x0; //reset interrupt identification register
+ com->iir.pending = 0x1;
+ } else if ( (com->ier.etbei == 0x1) &&
+ (getNumber(&(com->tx_buffer)) != SERIAL_BUF_LEN )) {
+
+ PrintDebug("UART: transmit buffer interrupt(buffer not full)\n");
-struct serial_state {
- struct serial_port com1;
- struct serial_port com2;
- struct serial_port com3;
- struct serial_port com4;
-};
+ com->iir.iid = TX_IRQ_THRE;
+ com->iir.pending = 0;
+ v3_raise_irq(vm, com->irq_number);
+ }
-int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- struct serial_state * state = (struct serial_state *)dev->private_data;
- char * val = (char *)src;
- PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *(char*)src);
-
- if (length != 1) {
- PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
- return -1;
- }
-
- switch (port) {
- case COM1_DATA_PORT:
- queue_data(&(state->com1.tx_buffer), *val);
- break;
- case COM2_DATA_PORT:
- queue_data(&(state->com2.tx_buffer), *val);
- break;
- case COM3_DATA_PORT:
- queue_data(&(state->com3.tx_buffer), *val);
- break;
- case COM4_DATA_PORT:
- queue_data(&(state->com4.tx_buffer), *val);
- break;
- default:
- return -1;
- }
-
+ return 1;
+}
+
+
+static int queue_data(struct v3_vm_info * vm, struct serial_port * com,
+ struct serial_buffer * buf, uint8_t data) {
+ int next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
+
+ if (buf->full == 1) {
+ PrintDebug("Buffer is full!\n");
+
+ if (buf == &(com->rx_buffer)) {
+ com->lsr.oe = 1; //overrun error bit set
+ }
- return length;
+ return 0;
+ }
+
+ buf->buffer[next_loc] = data;
+ buf->head = next_loc;
+
+ if (buf->head == buf->tail) {
+ buf->full = 1;
+ }
+
+ if (buf == &(com->rx_buffer)) {
+ com->lsr.dr = 1; //as soon as new data arrives at receive buffer, set data ready bit in lsr.
+ }
+
+ if (buf == &(com->tx_buffer)) {
+ com->lsr.thre = 0; //reset thre and temt bits.
+ com->lsr.temt = 0;
+ }
+
+ updateIRQ(vm, com);
+
+ return 0;
}
+static int dequeue_data(struct v3_vm_info * vm, struct serial_port * com,
+ struct serial_buffer * buf, uint8_t * data) {
+ int next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
-int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
- struct serial_state * state = (struct serial_state *)dev->private_data;
- char * val = (char *)dst;
- PrintDebug("Read from Data Port 0x%x\n", port);
-
- if (length != 1) {
- PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
- return -1;
- }
-
- switch (port) {
- case COM1_DATA_PORT:
- dequeue_data(&(state->com1.tx_buffer), val);
- break;
- case COM2_DATA_PORT:
- dequeue_data(&(state->com2.tx_buffer), val);
- break;
- case COM3_DATA_PORT:
- dequeue_data(&(state->com3.tx_buffer), val);
- break;
- case COM4_DATA_PORT:
- dequeue_data(&(state->com4.tx_buffer), val);
- break;
- default:
- return -1;
- }
-
- return length;
+ if ( (buf->head == buf->tail) && (buf->full != 1) ) {
+ PrintDebug("no data to delete!\n");
+ return -1;
+ }
+
+ if (buf->full == 1) {
+ buf->full = 0;
+ }
+
+
+ *data = buf->buffer[next_tail];
+ buf->buffer[next_tail] = 0;
+ buf->tail = next_tail;
+
+ if ( (buf == &(com->rx_buffer)) && (getNumber(&(com->rx_buffer)) == 0) ) {
+ com->lsr.dr = 0;
+ }
+
+ if ((buf == &(com->tx_buffer)) && (getNumber(&(com->tx_buffer)) == 0)) {
+ com->lsr.thre = 1;
+ com->lsr.temt = 1;
+ }
+
+ updateIRQ(vm, com);
+
+ return 0;
}
+static int write_data_port(struct guest_info * core, uint16_t port,
+ 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);
+
+ if (length != 1) {
+ PrintError("Invalid length(%d) in write to 0x%x\n", length, port);
+ return -1;
+ }
-int handle_ier_write(struct serial_port * com, struct irq_enable_reg * ier) {
-
+ 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);
+ return -1;
+ }
+
+ com_port = get_com_from_port(state, port);
+
+ if (com_port == NULL) {
+ PrintError("UART:read from NOBODY\n");
+ return -1;
+ }
+
- return -1;
+ // dlab is always checked first
+ if (com_port->lcr.dlab == 1) {
+ com_port->dll.data = *val;
+ } else {
+
+
+ /* JRL: Some buffering would probably be a good idea here.... */
+ if (com_port->ops) {
+ com_port->ops->write(val, 1, com_port->backend_data);
+ } else {
+ queue_data(core->vm_info, com_port, &(com_port->tx_buffer), *val);
+ }
+ }
+
+ return length;
}
-int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- struct serial_state * state = (struct serial_state *)dev->private_data;
- char * val = (char *)src;
- PrintDebug("Write to Control Port (val=%x)\n", *(char *)src);
- if (length != 1) {
- PrintDebug("Invalid Write length to control port\n", port, port);
- return -1;
- }
+static int read_data_port(struct guest_info * core, uint16_t port,
+ 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;
- switch (port) {
- case COM1_IRQ_ENABLE_PORT:
- if (handle_ier_write(&(state->com1), (struct irq_enable_reg *)val) == -1) {
- return -1;
+ PrintDebug("Read from Data Port 0x%x\n", port);
+
+ if (length != 1) {
+ PrintError("Invalid length(%d) in write to 0x%x\n", length, port);
+ return -1;
}
- break;
- case COM2_IRQ_ENABLE_PORT:
- if (handle_ier_write(&(state->com2), (struct irq_enable_reg *)val) == -1) {
- 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);
+ return -1;
}
- break;
- case COM3_IRQ_ENABLE_PORT:
- if (handle_ier_write(&(state->com3), (struct irq_enable_reg *)val) == -1) {
- return -1;
+
+ com_port = get_com_from_port(state, port);
+
+ if (com_port == NULL) {
+ PrintError("UART:read from NOBODY\n");
+ return -1;
}
- break;
- case COM4_IRQ_ENABLE_PORT:
- if (handle_ier_write(&(state->com4), (struct irq_enable_reg *)val) == -1) {
- return -1;
+
+ if (com_port->lcr.dlab == 1) {
+ *val = com_port->dll.data;
+ } else {
+ dequeue_data(core->vm_info, com_port, &(com_port->rx_buffer), val);
+ }
+
+ return length;
+}
+
+
+
+static int handle_fcr_write(struct serial_port * com, uint8_t value) {
+
+ com->fcr.enable = value & 0x1;
+
+ if (com->fcr.enable == 0x1) {
+ com->fcr.val = value;
+
+ com->fcr.enable = 1; // Do we need to set this??
+
+ //if rfres set, clear receive buffer.
+ if (com->fcr.rfres == 0x1) {
+ com->rx_buffer.head = 0;
+ com->rx_buffer.tail = 0;
+ com->rx_buffer.full = 0;
+ memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN);
+ com->fcr.rfres = 0;
+ }
+
+ //if xfres set, clear transmit buffer.
+ if (com->fcr.xfres == 0x1) {
+ com->tx_buffer.head = 0;
+ com->tx_buffer.tail = 0;
+ com->tx_buffer.full = 0;
+ memset(com->tx_buffer.buffer, 0, SERIAL_BUF_LEN);
+ com->fcr.xfres = 0;
+ }
+ } else {
+ //clear both buffers.
+ com->tx_buffer.head = 0;
+ com->tx_buffer.tail = 0;
+ com->tx_buffer.full = 0;
+ com->rx_buffer.head = 0;
+ com->rx_buffer.tail = 0;
+ com->rx_buffer.full = 0;
+
+ memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN);
+ memset(com->tx_buffer.buffer, 0, SERIAL_BUF_LEN);
}
- break;
+
+ return 1;
+}
+
- case COM1_FIFO_CTRL_PORT:
- case COM2_FIFO_CTRL_PORT:
- case COM3_FIFO_CTRL_PORT:
- case COM4_FIFO_CTRL_PORT:
- case COM1_LINE_CTRL_PORT:
- case COM2_LINE_CTRL_PORT:
- case COM3_LINE_CTRL_PORT:
- case COM4_LINE_CTRL_PORT:
- case COM1_MODEM_CTRL_PORT:
- case COM2_MODEM_CTRL_PORT:
- case COM3_MODEM_CTRL_PORT:
- case COM4_MODEM_CTRL_PORT:
+
+static int write_ctrl_port(struct guest_info * core, uint16_t port, 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("UART:Write to Control Port (val=%x)\n", val);
+ if (length != 1) {
+ PrintError("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);
+ return -1;
+ }
+
+ //always check dlab first
+ switch (port) {
+ case COM1_IRQ_ENABLE_PORT:
+ 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);
+
+ if (com_port->lcr.dlab == 1) {
+ com_port->dlm.data = val;
+ } else {
+ com_port->ier.val = val;
+ }
+
+ break;
+ }
+ case COM1_FIFO_CTRL_PORT:
+ case COM2_FIFO_CTRL_PORT:
+ case COM3_FIFO_CTRL_PORT:
+ case COM4_FIFO_CTRL_PORT: {
+ PrintDebug("UART:Write to FCR\n");
+
+ if (handle_fcr_write(com_port, val) == -1) {
+ return -1;
+ }
+
+ break;
+ }
+ case COM1_LINE_CTRL_PORT:
+ case COM2_LINE_CTRL_PORT:
+ case COM3_LINE_CTRL_PORT:
+ case COM4_LINE_CTRL_PORT: {
+ PrintDebug("UART:Write to LCR\n");
+ com_port->lcr.val = val;
+ break;
+ }
+ case COM1_MODEM_CTRL_PORT:
+ case COM2_MODEM_CTRL_PORT:
+ case COM3_MODEM_CTRL_PORT:
+ case COM4_MODEM_CTRL_PORT: {
+ PrintDebug("UART:Write to MCR\n");
+ com_port->mcr.val = val;
+ break;
+ }
+ case COM1_SCRATCH_PORT:
+ case COM2_SCRATCH_PORT:
+ case COM3_SCRATCH_PORT:
+ case COM4_SCRATCH_PORT: {
+ PrintDebug("UART:Write to SCRATCH\n");
+ com_port->scr.data = val;
+ break;
+ }
+ default:
+ PrintError("UART:Write to NOBODY, ERROR\n");
+ return -1;
+ }
+
+
+ return length;
+}
+
+
+
+
+static int read_ctrl_port(struct guest_info * core, uint16_t port, 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 Control Port\n");
+
+ if (length != 1) {
+ PrintError("Invalid Read length to control port\n");
+ return -1;
+ }
- default:
- 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);
+ return -1;
+ }
+
+ //always check dlab first
+ switch (port) {
+ case COM1_IRQ_ENABLE_PORT:
+ case COM2_IRQ_ENABLE_PORT:
+ case COM3_IRQ_ENABLE_PORT:
+ case COM4_IRQ_ENABLE_PORT: {
+ PrintDebug("UART:read from IER\n");
+
+ if (com_port->lcr.dlab == 1) {
+ *val = com_port->dlm.data;
+ } else {
+ *val = com_port->ier.val;
+ }
+ break;
+ }
+
+ case COM1_IIR_PORT:
+ case COM2_IIR_PORT:
+ case COM3_IIR_PORT:
+ case COM4_IIR_PORT:
+ PrintDebug("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\n");
+ *val = com_port->lcr.val;
+ break;
+
+ case COM1_MODEM_CTRL_PORT:
+ case COM2_MODEM_CTRL_PORT:
+ case COM3_MODEM_CTRL_PORT:
+ case COM4_MODEM_CTRL_PORT:
+ PrintDebug("UART:read from MCR\n");
+ *val = com_port->mcr.val;
+ break;
+
+ case COM1_SCRATCH_PORT:
+ case COM2_SCRATCH_PORT:
+ case COM3_SCRATCH_PORT:
+ case COM4_SCRATCH_PORT:
+ PrintDebug("UART:read from SCRATCH\n");
+ *val = com_port->scr.data;
+ break;
+
+ default:
+ PrintError("UART:read from NOBODY\n");
+ return -1;
+ }
- return -1;
+ return length;
}
+static int write_status_port(struct guest_info * core, uint16_t port, 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 Status Port (val=%x)\n", val);
+
+ if (length != 1) {
+ PrintError("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);
+ return -1;
+ }
+ switch (port) {
+ case COM1_LINE_STATUS_PORT:
+ case COM2_LINE_STATUS_PORT:
+ case COM3_LINE_STATUS_PORT:
+ case COM4_LINE_STATUS_PORT:
+ PrintDebug("UART:write to LSR\n");
+ com_port->lsr.val = val;
+ break;
+
+ case COM1_MODEM_STATUS_PORT:
+ case COM2_MODEM_STATUS_PORT:
+ case COM3_MODEM_STATUS_PORT:
+ case COM4_MODEM_STATUS_PORT:
+ PrintDebug("UART:write to MSR\n");
+ com_port->msr.val = val;
+ break;
+
+ default:
+ PrintError("UART:write to NOBODY\n");
+ return -1;
+ }
-int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
- struct serial_state * state = (struct serial_state *)dev->private_data;
- char * val = (char *)dst;
- PrintDebug("Read from Control Port\n");
-
- if (length != 1) {
- PrintDebug("Invalid Read length to control port\n");
- return -1;
- }
-
- switch (port) {
- case COM1_IRQ_ENABLE_PORT:
- *val = state->com1.ier;
- break;
- case COM2_IRQ_ENABLE_PORT:
- *val = state->com2.ier;
- break;
- case COM3_IRQ_ENABLE_PORT:
- *val = state->com3.ier;
- break;
- case COM4_IRQ_ENABLE_PORT:
- *val = state->com4.ier;
- break;
-
- case COM1_FIFO_CTRL_PORT:
- *val = state->com1.fcr;
- break;
- case COM2_FIFO_CTRL_PORT:
- *val = state->com2.fcr;
- break;
- case COM3_FIFO_CTRL_PORT:
- *val = state->com3.fcr;
- break;
- case COM4_FIFO_CTRL_PORT:
- *val = state->com4.fcr;
- break;
-
- case COM1_LINE_CTRL_PORT:
- *val = state->com1.lcr;
- break;
- case COM2_LINE_CTRL_PORT:
- *val = state->com2.lcr;
- break;
- case COM3_LINE_CTRL_PORT:
- *val = state->com3.lcr;
- break;
- case COM4_LINE_CTRL_PORT:
- *val = state->com4.lcr;
- break;
-
- case COM1_MODEM_CTRL_PORT:
- *val = state->com1.mcr;
- break;
- case COM2_MODEM_CTRL_PORT:
- *val = state->com2.mcr;
- break;
- case COM3_MODEM_CTRL_PORT:
- *val = state->com3.mcr;
- break;
- case COM4_MODEM_CTRL_PORT:
- *val = state->com4.mcr;
- break;
-
- default:
- return -1;
- }
-
- return length;
+ return length;
}
+static int read_status_port(struct guest_info * core, uint16_t port, 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 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);
+ return -1;
+ }
+
+ switch (port) {
+ case COM1_LINE_STATUS_PORT:
+ case COM2_LINE_STATUS_PORT:
+ case COM3_LINE_STATUS_PORT:
+ case COM4_LINE_STATUS_PORT:
+
+ if (length != 1) {
+ PrintError("Invalid Read length to control port\n");
+ return -1;
+ }
+
+ PrintDebug("UART:read from LSR\n");
+
+ *val = com_port->lsr.val;
+ com_port->lsr.oe = 0; // Why do we clear this??
+
+ break;
+
+ case COM1_MODEM_STATUS_PORT:
+ case COM2_MODEM_STATUS_PORT:
+ case COM3_MODEM_STATUS_PORT:
+ case COM4_MODEM_STATUS_PORT:
+ PrintDebug("UART:read from COM4 MSR (length = %d)\n", length);
+
+ if (length > 2) {
+ PrintError("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("Error reading control port for word size read of Status register\n");
+ return -1;
+ }
+ }
-int write_status_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- PrintDebug("Write to Status Port 0x%x (val=%x)\n", port, *(char *)src);
+ // always read low byte...
+
+ *val = com_port->msr.val;
+ break;
- return -1;
+ default:
+ PrintError("UART:read from NOBODY (length = %d)\n", length);
+ return -1;
+ }
+
+ return length;
}
-int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
- struct serial_state * state = (struct serial_state *)dev->private_data;
- char * val = (char *)dst;
- PrintDebug("Read from Status Port 0x%x\n", port);
-
- if (length != 1) {
- PrintDebug("Invalid Read length to control port\n");
- return -1;
- }
-
- switch (port) {
- case COM1_LINE_STATUS_PORT:
- *val = state->com1.lsr;
- break;
- case COM2_LINE_STATUS_PORT:
- *val = state->com2.lsr;
- break;
- case COM3_LINE_STATUS_PORT:
- *val = state->com3.lsr;
- break;
- case COM4_LINE_STATUS_PORT:
- *val = state->com4.lsr;
- break;
-
- case COM1_MODEM_STATUS_PORT:
- *val = state->com1.msr;
- break;
- case COM2_MODEM_STATUS_PORT:
- *val = state->com2.msr;
- break;
- case COM3_MODEM_STATUS_PORT:
- *val = state->com3.msr;
- break;
- case COM4_MODEM_STATUS_PORT:
- *val = state->com4.msr;
- break;
-
- default:
- return -1;
- }
-
-
-
- return length;
+static int serial_free(struct serial_state * state) {
+
+ V3_Free(state);
+ return 0;
}
+static struct v3_device_ops dev_ops = {
+ .free = (int (*)(void *))serial_free,
+};
+
+
static int init_serial_port(struct serial_port * com) {
- //struct irq_enable_reg * ier = (struct irq_enable_reg *)&(com->ier);
- //struct irq_id_reg * iir = (struct irq_id_reg *)&(com->iir);
- //struct fifo_ctrl_reg * fcr = (struct fifo_ctrl_reg *)&(com->fcr);
- //struct line_ctrl_reg * lcr = (struct line_ctrl_reg *)&(com->lcr);
- //struct modem_ctrl_reg * mcr = (struct modem_ctrl_reg *)&(com->mcr);
- //struct line_status_reg * lsr = (struct line_status_reg *)&(com->lsr);
- //struct modem_status_reg * msr = (struct modem_status_reg *)&(com->msr);
-
- com->ier = 0x00;
- com->iir = 0x01;
- com->fcr = 0x00;
- com->lcr = 0x00;
- com->mcr = 0x00;
- com->lsr = 0x60;
- com->msr = 0x00;
-
- return 0;
+
+ com->ier.val = IER_INIT_VAL;
+ com->iir.val = IIR_INIT_VAL;
+ com->fcr.val = FCR_INIT_VAL;
+ com->lcr.val = LCR_INIT_VAL;
+ com->mcr.val = MCR_INIT_VAL;
+ com->lsr.val = LSR_INIT_VAL;
+ com->msr.val = MSR_INIT_VAL;
+
+ com->dll.data = DLL_INIT_VAL;
+ com->dlm.data = DLM_INIT_VAL;
+
+ com->tx_buffer.head = 0;
+ com->tx_buffer.tail = 0;
+ com->tx_buffer.full = 0;
+ memset(com->tx_buffer.buffer, 0, SERIAL_BUF_LEN);
+
+ com->rx_buffer.head = 0;
+ com->rx_buffer.tail = 0;
+ com->rx_buffer.full = 0;
+ memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN);
+
+ com->ops = NULL;
+ com->backend_data = NULL;
+
+ return 0;
}
-int serial_init(struct vm_device * dev) {
- struct serial_state * state = (struct serial_state *)dev->private_data;
-
-
- init_serial_port(&(state->com1));
- init_serial_port(&(state->com2));
- init_serial_port(&(state->com3));
- init_serial_port(&(state->com4));
-
- dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
- dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
- dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
- dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
- dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
- dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
- dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
- dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
- dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
- dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
- return 0;
+static int 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;
+
+ for(i = 0; i < len; i++){
+ queue_data(vm, com_port, &(com_port->rx_buffer), buf[i]);
+ }
+
+ return len;
}
-int serial_deinit(struct vm_device * dev) {
-
-
- dev_unhook_io(dev, COM1_DATA_PORT);
- dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
- dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
- dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
- dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
- dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
- dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
- dev_unhook_io(dev, COM1_SCRATCH_PORT);
-
- dev_unhook_io(dev, COM2_DATA_PORT);
- dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
- dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
- dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
- dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
- dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
- dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
- dev_unhook_io(dev, COM2_SCRATCH_PORT);
-
- dev_unhook_io(dev, COM3_DATA_PORT);
- dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
- dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
- dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
- dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
- dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
- dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
- dev_unhook_io(dev, COM3_SCRATCH_PORT);
-
- dev_unhook_io(dev, COM4_DATA_PORT);
- dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
- dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
- dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
- dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
- dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
- dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
- dev_unhook_io(dev, COM4_SCRATCH_PORT);
-
- return 0;
+static int connect_fn(struct v3_vm_info * vm,
+ void * frontend_data,
+ struct v3_dev_char_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data,
+ void ** push_fn_arg) {
+
+ struct serial_state * serial = (struct serial_state *)frontend_data;
+ struct serial_port * com = NULL;
+ char * com_port = v3_cfg_val(cfg, "com_port");
+ int com_idx = 0;
+
+ if (com_port == NULL) {
+ PrintError("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);
+ return -1;
+ }
+
+ com = &(serial->coms[com_idx]);
+
+ com->ops = ops;
+ com->backend_data = private_data;
+
+ com->ops->push = serial_input;
+ *push_fn_arg = com;
+
+ return 0;
}
+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");
+ return -1;
+ }
+
+ memset(state, 0, sizeof(struct serial_state));
-static struct vm_device_ops dev_ops = {
- .init = serial_init,
- .deinit = serial_deinit,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
-};
+ init_serial_port(&(state->coms[0]));
+ init_serial_port(&(state->coms[1]));
+ init_serial_port(&(state->coms[2]));
+ init_serial_port(&(state->coms[3]));
+
+ state->coms[0].irq_number = COM1_IRQ;
+ state->coms[1].irq_number = COM2_IRQ;
+ state->coms[2].irq_number = COM3_IRQ;
+ state->coms[3].irq_number = COM4_IRQ;
+
+
+ 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);
+ V3_Free(state);
+ return -1;
+ }
+
+ PrintDebug("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("Error hooking Serial IO ports\n");
+ v3_remove_device(dev);
+ return -1;
+ }
+ PrintDebug("Serial ports hooked\n");
-struct vm_device * create_serial(int num_ports) {
- struct serial_state * state = NULL;
- state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
- V3_ASSERT(state != NULL);
- struct vm_device * device = create_device("Serial UART", &dev_ops, state);
- return device;
+ if (v3_dev_add_char_frontend(vm, dev_id, connect_fn, (void *)state) == -1) {
+ PrintError("Could not register %s as frontend\n", dev_id);
+ v3_remove_device(dev);
+ return -1;
+ }
+
+
+ return 0;
}
+
+
+
+
+
+device_register("SERIAL", serial_init)