1899fe063SPekka Enberg #include "kvm/8250-serial.h" 213a7760fSPekka Enberg 313a7760fSPekka Enberg #include "kvm/ioport.h" 446aa8d69SPekka Enberg #include "kvm/util.h" 5e557eef9SPekka Enberg #include "kvm/kvm.h" 613a7760fSPekka Enberg 746aa8d69SPekka Enberg #include <stdbool.h> 876b4a122SPekka Enberg #include <poll.h> 913a7760fSPekka Enberg 1046aa8d69SPekka Enberg /* Transmitter holding register */ 1146aa8d69SPekka Enberg #define THR 0 123f55f3acSPekka Enberg 1346aa8d69SPekka Enberg /* Receive buffer register */ 1446aa8d69SPekka Enberg #define RBR 0 153f55f3acSPekka Enberg 1646aa8d69SPekka Enberg /* Divisor latch low byte */ 1746aa8d69SPekka Enberg #define DLL 0 183f55f3acSPekka Enberg 1946aa8d69SPekka Enberg /* Divisor latch high byte */ 2046aa8d69SPekka Enberg #define DLM 1 2146aa8d69SPekka Enberg 2246aa8d69SPekka Enberg /* Interrupt enable register */ 2346aa8d69SPekka Enberg #define IER 1 2446aa8d69SPekka Enberg 2576b4a122SPekka Enberg #define UART_IER_RDI 0x01 26e557eef9SPekka Enberg #define UART_IER_THRI 0x02 27e557eef9SPekka Enberg 2846aa8d69SPekka Enberg /* Interrupt identification register */ 2946aa8d69SPekka Enberg #define IIR 2 3046aa8d69SPekka Enberg 319a7428ddSPekka Enberg #define UART_IIR_NO_INT 0x01 32900d32c1SPekka Enberg #define UART_IIR_THRI 0x02 339a7428ddSPekka Enberg 3446aa8d69SPekka Enberg /* 16550 FIFO Control Register */ 3546aa8d69SPekka Enberg #define FCR 2 3646aa8d69SPekka Enberg 3746aa8d69SPekka Enberg /* Line control register */ 3846aa8d69SPekka Enberg #define LCR 3 399a7428ddSPekka Enberg 409a7428ddSPekka Enberg #define UART_LCR_DLAB 0x80 4146aa8d69SPekka Enberg 4246aa8d69SPekka Enberg /* Modem control register */ 4346aa8d69SPekka Enberg #define MCR 4 4446aa8d69SPekka Enberg 4546aa8d69SPekka Enberg /* Line status register */ 4646aa8d69SPekka Enberg #define LSR 5 4746aa8d69SPekka Enberg 4876b4a122SPekka Enberg #define UART_LSR_DR 0x01 499a7428ddSPekka Enberg #define UART_LSR_THRE 0x20 509a7428ddSPekka Enberg 5146aa8d69SPekka Enberg /* Modem status register */ 5246aa8d69SPekka Enberg #define MSR 6 5346aa8d69SPekka Enberg 549a7428ddSPekka Enberg #define UART_MSR_CTS 0x10 559a7428ddSPekka Enberg 5646aa8d69SPekka Enberg /* Scratch register */ 5746aa8d69SPekka Enberg #define SCR 7 5846aa8d69SPekka Enberg 5946aa8d69SPekka Enberg struct serial8250_device { 6046aa8d69SPekka Enberg uint16_t iobase; 61e557eef9SPekka Enberg uint8_t irq; 6276b4a122SPekka Enberg 6376b4a122SPekka Enberg uint8_t thr; 6446aa8d69SPekka Enberg uint8_t dll; 6546aa8d69SPekka Enberg uint8_t dlm; 66e557eef9SPekka Enberg uint8_t iir; 6746aa8d69SPekka Enberg uint8_t ier; 6846aa8d69SPekka Enberg uint8_t fcr; 6946aa8d69SPekka Enberg uint8_t lcr; 7046aa8d69SPekka Enberg uint8_t mcr; 7176b4a122SPekka Enberg uint8_t lsr; 7246aa8d69SPekka Enberg uint8_t scr; 7346aa8d69SPekka Enberg }; 7446aa8d69SPekka Enberg 7546aa8d69SPekka Enberg static struct serial8250_device device = { 7646aa8d69SPekka Enberg .iobase = 0x3f8, /* ttyS0 */ 77e557eef9SPekka Enberg .irq = 4, 78e557eef9SPekka Enberg 7976b4a122SPekka Enberg .iir = UART_IIR_NO_INT, 8076b4a122SPekka Enberg .lsr = UART_LSR_THRE, 8146aa8d69SPekka Enberg }; 8246aa8d69SPekka Enberg 8376b4a122SPekka Enberg static int read_char(int fd) 8476b4a122SPekka Enberg { 8576b4a122SPekka Enberg int c; 8676b4a122SPekka Enberg 8776b4a122SPekka Enberg if (read(fd, &c, 1) < 0) 8876b4a122SPekka Enberg return -1; 8976b4a122SPekka Enberg 9076b4a122SPekka Enberg return c; 9176b4a122SPekka Enberg } 9276b4a122SPekka Enberg 9376b4a122SPekka Enberg static bool is_readable(int fd) 9476b4a122SPekka Enberg { 95*6d54df74SCyrill Gorcunov struct pollfd pollfd = (struct pollfd) { 9676b4a122SPekka Enberg .fd = fd, 9776b4a122SPekka Enberg .events = POLLIN, 9876b4a122SPekka Enberg }; 9976b4a122SPekka Enberg 100*6d54df74SCyrill Gorcunov return poll(&pollfd, 1, 0) > 0; 10176b4a122SPekka Enberg } 10276b4a122SPekka Enberg 1038bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self) 1048bb34e0dSPekka Enberg { 10576b4a122SPekka Enberg if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 10676b4a122SPekka Enberg int c; 10776b4a122SPekka Enberg 10876b4a122SPekka Enberg c = read_char(fileno(stdin)); 10976b4a122SPekka Enberg if (c >= 0) { 11076b4a122SPekka Enberg device.thr = c; 11176b4a122SPekka Enberg device.lsr |= UART_LSR_DR; 11276b4a122SPekka Enberg } 11376b4a122SPekka Enberg } 11476b4a122SPekka Enberg 11576b4a122SPekka Enberg if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) { 116e557eef9SPekka Enberg device.iir &= ~UART_IIR_NO_INT; 117e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 1); 118e557eef9SPekka Enberg } 1198bb34e0dSPekka Enberg } 1208bb34e0dSPekka Enberg 12146aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 12213a7760fSPekka Enberg { 12346aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 12446aa8d69SPekka Enberg 1259a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 12646aa8d69SPekka Enberg switch (offset) { 12746aa8d69SPekka Enberg case DLL: 12846aa8d69SPekka Enberg device.dll = ioport__read8(data); 12946aa8d69SPekka Enberg break; 13046aa8d69SPekka Enberg case DLM: 13146aa8d69SPekka Enberg device.dlm = ioport__read8(data); 13246aa8d69SPekka Enberg break; 13346aa8d69SPekka Enberg case FCR: 13446aa8d69SPekka Enberg device.fcr = ioport__read8(data); 13546aa8d69SPekka Enberg break; 13646aa8d69SPekka Enberg case LCR: 13746aa8d69SPekka Enberg device.lcr = ioport__read8(data); 13846aa8d69SPekka Enberg break; 13946aa8d69SPekka Enberg default: 14046aa8d69SPekka Enberg return false; 14146aa8d69SPekka Enberg } 14246aa8d69SPekka Enberg } else { 14346aa8d69SPekka Enberg switch (offset) { 14446aa8d69SPekka Enberg case THR: { 14513a7760fSPekka Enberg char *p = data; 146f2d8dc88SCyrill Gorcunov int i; 14713a7760fSPekka Enberg 148f2d8dc88SCyrill Gorcunov while (count--) { 149f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 150b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 1515b9d0b58SAsias He } 152b7475544SPekka Enberg fflush(stdout); 153e557eef9SPekka Enberg 154e557eef9SPekka Enberg device.iir |= UART_IIR_NO_INT; 155e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 0); 156e557eef9SPekka Enberg 15746aa8d69SPekka Enberg break; 15846aa8d69SPekka Enberg } 15946aa8d69SPekka Enberg case IER: 16046aa8d69SPekka Enberg device.ier = ioport__read8(data); 16146aa8d69SPekka Enberg break; 16246aa8d69SPekka Enberg case FCR: 16346aa8d69SPekka Enberg device.fcr = ioport__read8(data); 16446aa8d69SPekka Enberg break; 16546aa8d69SPekka Enberg case LCR: 16646aa8d69SPekka Enberg device.lcr = ioport__read8(data); 16746aa8d69SPekka Enberg break; 16846aa8d69SPekka Enberg case MCR: 16946aa8d69SPekka Enberg device.mcr = ioport__read8(data); 17046aa8d69SPekka Enberg break; 17146aa8d69SPekka Enberg case SCR: 17246aa8d69SPekka Enberg device.scr = ioport__read8(data); 17346aa8d69SPekka Enberg break; 17446aa8d69SPekka Enberg default: 17546aa8d69SPekka Enberg return false; 17646aa8d69SPekka Enberg } 17746aa8d69SPekka Enberg } 17813a7760fSPekka Enberg 17913a7760fSPekka Enberg return true; 18013a7760fSPekka Enberg } 18113a7760fSPekka Enberg 18246aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 18325af6674SPekka Enberg { 18446aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 18546aa8d69SPekka Enberg 1869a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 18746aa8d69SPekka Enberg return false; 18846aa8d69SPekka Enberg 18946aa8d69SPekka Enberg switch (offset) { 19046aa8d69SPekka Enberg case THR: 19176b4a122SPekka Enberg if (device.lsr & UART_LSR_DR) { 19276b4a122SPekka Enberg device.lsr &= ~UART_LSR_DR; 19376b4a122SPekka Enberg ioport__write8(data, device.thr); 19476b4a122SPekka Enberg 19576b4a122SPekka Enberg device.iir |= UART_IIR_NO_INT; 19676b4a122SPekka Enberg kvm__irq_line(self, device.irq, 0); 19776b4a122SPekka Enberg } 19846aa8d69SPekka Enberg break; 19946aa8d69SPekka Enberg case IER: 20046aa8d69SPekka Enberg ioport__write8(data, device.ier); 20146aa8d69SPekka Enberg break; 20246aa8d69SPekka Enberg case IIR: 203e557eef9SPekka Enberg ioport__write8(data, device.iir); 20446aa8d69SPekka Enberg break; 20546aa8d69SPekka Enberg case LCR: 20646aa8d69SPekka Enberg ioport__write8(data, device.lcr); 20746aa8d69SPekka Enberg break; 20846aa8d69SPekka Enberg case MCR: 20946aa8d69SPekka Enberg ioport__write8(data, device.mcr); 21046aa8d69SPekka Enberg break; 21146aa8d69SPekka Enberg case LSR: 21276b4a122SPekka Enberg ioport__write8(data, device.lsr); 21346aa8d69SPekka Enberg break; 21446aa8d69SPekka Enberg case MSR: 2159a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 21646aa8d69SPekka Enberg break; 21746aa8d69SPekka Enberg case SCR: 21846aa8d69SPekka Enberg ioport__write8(data, device.scr); 21946aa8d69SPekka Enberg break; 22046aa8d69SPekka Enberg default: 22146aa8d69SPekka Enberg return false; 22225af6674SPekka Enberg } 22325af6674SPekka Enberg 22413a7760fSPekka Enberg return true; 22513a7760fSPekka Enberg } 22613a7760fSPekka Enberg 22746aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 22846aa8d69SPekka Enberg .io_in = serial8250_in, 22946aa8d69SPekka Enberg .io_out = serial8250_out, 230a93ec68bSPekka Enberg }; 231a93ec68bSPekka Enberg 232899fe063SPekka Enberg void serial8250__init(void) 23313a7760fSPekka Enberg { 23446aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 23513a7760fSPekka Enberg } 236