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> 8*76b4a122SPekka 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 25*76b4a122SPekka 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 48*76b4a122SPekka 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; 62*76b4a122SPekka Enberg 63*76b4a122SPekka 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; 71*76b4a122SPekka 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 79*76b4a122SPekka Enberg .iir = UART_IIR_NO_INT, 80*76b4a122SPekka Enberg .lsr = UART_LSR_THRE, 8146aa8d69SPekka Enberg }; 8246aa8d69SPekka Enberg 83*76b4a122SPekka Enberg static int read_char(int fd) 84*76b4a122SPekka Enberg { 85*76b4a122SPekka Enberg int c; 86*76b4a122SPekka Enberg 87*76b4a122SPekka Enberg if (read(fd, &c, 1) < 0) 88*76b4a122SPekka Enberg return -1; 89*76b4a122SPekka Enberg 90*76b4a122SPekka Enberg return c; 91*76b4a122SPekka Enberg } 92*76b4a122SPekka Enberg 93*76b4a122SPekka Enberg static bool is_readable(int fd) 94*76b4a122SPekka Enberg { 95*76b4a122SPekka Enberg struct pollfd pollfd; 96*76b4a122SPekka Enberg int err; 97*76b4a122SPekka Enberg 98*76b4a122SPekka Enberg pollfd = (struct pollfd) { 99*76b4a122SPekka Enberg .fd = fd, 100*76b4a122SPekka Enberg .events = POLLIN, 101*76b4a122SPekka Enberg }; 102*76b4a122SPekka Enberg 103*76b4a122SPekka Enberg err = poll(&pollfd, 1, 0); 104*76b4a122SPekka Enberg return err > 0; 105*76b4a122SPekka Enberg } 106*76b4a122SPekka Enberg 1078bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self) 1088bb34e0dSPekka Enberg { 109*76b4a122SPekka Enberg if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 110*76b4a122SPekka Enberg int c; 111*76b4a122SPekka Enberg 112*76b4a122SPekka Enberg c = read_char(fileno(stdin)); 113*76b4a122SPekka Enberg if (c >= 0) { 114*76b4a122SPekka Enberg device.thr = c; 115*76b4a122SPekka Enberg device.lsr |= UART_LSR_DR; 116*76b4a122SPekka Enberg } 117*76b4a122SPekka Enberg } 118*76b4a122SPekka Enberg 119*76b4a122SPekka Enberg if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) { 120e557eef9SPekka Enberg device.iir &= ~UART_IIR_NO_INT; 121e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 1); 122e557eef9SPekka Enberg } 1238bb34e0dSPekka Enberg } 1248bb34e0dSPekka Enberg 12546aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 12613a7760fSPekka Enberg { 12746aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 12846aa8d69SPekka Enberg 1299a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 13046aa8d69SPekka Enberg switch (offset) { 13146aa8d69SPekka Enberg case DLL: 13246aa8d69SPekka Enberg device.dll = ioport__read8(data); 13346aa8d69SPekka Enberg break; 13446aa8d69SPekka Enberg case DLM: 13546aa8d69SPekka Enberg device.dlm = ioport__read8(data); 13646aa8d69SPekka Enberg break; 13746aa8d69SPekka Enberg case FCR: 13846aa8d69SPekka Enberg device.fcr = ioport__read8(data); 13946aa8d69SPekka Enberg break; 14046aa8d69SPekka Enberg case LCR: 14146aa8d69SPekka Enberg device.lcr = ioport__read8(data); 14246aa8d69SPekka Enberg break; 14346aa8d69SPekka Enberg default: 14446aa8d69SPekka Enberg return false; 14546aa8d69SPekka Enberg } 14646aa8d69SPekka Enberg } else { 14746aa8d69SPekka Enberg switch (offset) { 14846aa8d69SPekka Enberg case THR: { 14913a7760fSPekka Enberg char *p = data; 150f2d8dc88SCyrill Gorcunov int i; 15113a7760fSPekka Enberg 152f2d8dc88SCyrill Gorcunov while (count--) { 153f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 154b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 1555b9d0b58SAsias He } 156b7475544SPekka Enberg fflush(stdout); 157e557eef9SPekka Enberg 158e557eef9SPekka Enberg device.iir |= UART_IIR_NO_INT; 159e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 0); 160e557eef9SPekka Enberg 16146aa8d69SPekka Enberg break; 16246aa8d69SPekka Enberg } 16346aa8d69SPekka Enberg case IER: 16446aa8d69SPekka Enberg device.ier = ioport__read8(data); 16546aa8d69SPekka Enberg break; 16646aa8d69SPekka Enberg case FCR: 16746aa8d69SPekka Enberg device.fcr = ioport__read8(data); 16846aa8d69SPekka Enberg break; 16946aa8d69SPekka Enberg case LCR: 17046aa8d69SPekka Enberg device.lcr = ioport__read8(data); 17146aa8d69SPekka Enberg break; 17246aa8d69SPekka Enberg case MCR: 17346aa8d69SPekka Enberg device.mcr = ioport__read8(data); 17446aa8d69SPekka Enberg break; 17546aa8d69SPekka Enberg case SCR: 17646aa8d69SPekka Enberg device.scr = ioport__read8(data); 17746aa8d69SPekka Enberg break; 17846aa8d69SPekka Enberg default: 17946aa8d69SPekka Enberg return false; 18046aa8d69SPekka Enberg } 18146aa8d69SPekka Enberg } 18213a7760fSPekka Enberg 18313a7760fSPekka Enberg return true; 18413a7760fSPekka Enberg } 18513a7760fSPekka Enberg 18646aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 18725af6674SPekka Enberg { 18846aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 18946aa8d69SPekka Enberg 1909a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 19146aa8d69SPekka Enberg return false; 19246aa8d69SPekka Enberg 19346aa8d69SPekka Enberg switch (offset) { 19446aa8d69SPekka Enberg case THR: 195*76b4a122SPekka Enberg if (device.lsr & UART_LSR_DR) { 196*76b4a122SPekka Enberg device.lsr &= ~UART_LSR_DR; 197*76b4a122SPekka Enberg ioport__write8(data, device.thr); 198*76b4a122SPekka Enberg 199*76b4a122SPekka Enberg device.iir |= UART_IIR_NO_INT; 200*76b4a122SPekka Enberg kvm__irq_line(self, device.irq, 0); 201*76b4a122SPekka Enberg } 20246aa8d69SPekka Enberg break; 20346aa8d69SPekka Enberg case IER: 20446aa8d69SPekka Enberg ioport__write8(data, device.ier); 20546aa8d69SPekka Enberg break; 20646aa8d69SPekka Enberg case IIR: 207e557eef9SPekka Enberg ioport__write8(data, device.iir); 20846aa8d69SPekka Enberg break; 20946aa8d69SPekka Enberg case LCR: 21046aa8d69SPekka Enberg ioport__write8(data, device.lcr); 21146aa8d69SPekka Enberg break; 21246aa8d69SPekka Enberg case MCR: 21346aa8d69SPekka Enberg ioport__write8(data, device.mcr); 21446aa8d69SPekka Enberg break; 21546aa8d69SPekka Enberg case LSR: 216*76b4a122SPekka Enberg ioport__write8(data, device.lsr); 21746aa8d69SPekka Enberg break; 21846aa8d69SPekka Enberg case MSR: 2199a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 22046aa8d69SPekka Enberg break; 22146aa8d69SPekka Enberg case SCR: 22246aa8d69SPekka Enberg ioport__write8(data, device.scr); 22346aa8d69SPekka Enberg break; 22446aa8d69SPekka Enberg default: 22546aa8d69SPekka Enberg return false; 22625af6674SPekka Enberg } 22725af6674SPekka Enberg 22813a7760fSPekka Enberg return true; 22913a7760fSPekka Enberg } 23013a7760fSPekka Enberg 23146aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 23246aa8d69SPekka Enberg .io_in = serial8250_in, 23346aa8d69SPekka Enberg .io_out = serial8250_out, 234a93ec68bSPekka Enberg }; 235a93ec68bSPekka Enberg 236899fe063SPekka Enberg void serial8250__init(void) 23713a7760fSPekka Enberg { 23846aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 23913a7760fSPekka Enberg } 240