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 74e49b05bSCyrill Gorcunov #include <linux/serial_reg.h> 84e49b05bSCyrill Gorcunov 946aa8d69SPekka Enberg #include <stdbool.h> 1076b4a122SPekka Enberg #include <poll.h> 1113a7760fSPekka Enberg 1246aa8d69SPekka Enberg struct serial8250_device { 1346aa8d69SPekka Enberg uint16_t iobase; 14e557eef9SPekka Enberg uint8_t irq; 1576b4a122SPekka Enberg 1676b4a122SPekka Enberg uint8_t thr; 1746aa8d69SPekka Enberg uint8_t dll; 1846aa8d69SPekka Enberg uint8_t dlm; 19e557eef9SPekka Enberg uint8_t iir; 2046aa8d69SPekka Enberg uint8_t ier; 2146aa8d69SPekka Enberg uint8_t fcr; 2246aa8d69SPekka Enberg uint8_t lcr; 2346aa8d69SPekka Enberg uint8_t mcr; 2476b4a122SPekka Enberg uint8_t lsr; 2546aa8d69SPekka Enberg uint8_t scr; 2646aa8d69SPekka Enberg }; 2746aa8d69SPekka Enberg 2846aa8d69SPekka Enberg static struct serial8250_device device = { 2946aa8d69SPekka Enberg .iobase = 0x3f8, /* ttyS0 */ 30e557eef9SPekka Enberg .irq = 4, 31e557eef9SPekka Enberg 326d620acbSCyrill Gorcunov .lsr = UART_LSR_TEMT | UART_LSR_THRE, 3346aa8d69SPekka Enberg }; 3446aa8d69SPekka Enberg 3576b4a122SPekka Enberg static int read_char(int fd) 3676b4a122SPekka Enberg { 3776b4a122SPekka Enberg int c; 3876b4a122SPekka Enberg 3976b4a122SPekka Enberg if (read(fd, &c, 1) < 0) 4076b4a122SPekka Enberg return -1; 4176b4a122SPekka Enberg 4276b4a122SPekka Enberg return c; 4376b4a122SPekka Enberg } 4476b4a122SPekka Enberg 4576b4a122SPekka Enberg static bool is_readable(int fd) 4676b4a122SPekka Enberg { 476d54df74SCyrill Gorcunov struct pollfd pollfd = (struct pollfd) { 4876b4a122SPekka Enberg .fd = fd, 4976b4a122SPekka Enberg .events = POLLIN, 5076b4a122SPekka Enberg }; 5176b4a122SPekka Enberg 526d54df74SCyrill Gorcunov return poll(&pollfd, 1, 0) > 0; 5376b4a122SPekka Enberg } 5476b4a122SPekka Enberg 558bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self) 568bb34e0dSPekka Enberg { 57*934c193bSPekka Enberg uint8_t new_iir; 58*934c193bSPekka Enberg 59*934c193bSPekka Enberg device.iir = UART_IIR_NO_INT; 60*934c193bSPekka Enberg 61*934c193bSPekka Enberg /* No interrupts enabled. Exit... */ 62*934c193bSPekka Enberg if (!(device.ier & (UART_IER_THRI|UART_IER_RDI))) 63*934c193bSPekka Enberg return; 64*934c193bSPekka Enberg 65*934c193bSPekka Enberg new_iir = 0; 66*934c193bSPekka Enberg 67*934c193bSPekka Enberg /* We're always good for guest sending data. */ 68*934c193bSPekka Enberg if (device.ier & UART_IER_THRI) 69*934c193bSPekka Enberg new_iir |= UART_IIR_THRI; 70*934c193bSPekka Enberg 71*934c193bSPekka Enberg /* Is there input in stdin to send to the guest? */ 7276b4a122SPekka Enberg if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 7376b4a122SPekka Enberg int c; 7476b4a122SPekka Enberg 7576b4a122SPekka Enberg c = read_char(fileno(stdin)); 7676b4a122SPekka Enberg if (c >= 0) { 7776b4a122SPekka Enberg device.thr = c; 7876b4a122SPekka Enberg device.lsr |= UART_LSR_DR; 79*934c193bSPekka Enberg new_iir |= UART_IIR_RDI; 8076b4a122SPekka Enberg } 8176b4a122SPekka Enberg } 8276b4a122SPekka Enberg 83*934c193bSPekka Enberg /* Only send an IRQ if there's work to do. */ 84*934c193bSPekka Enberg if (new_iir) { 85*934c193bSPekka Enberg device.iir = new_iir; 86*934c193bSPekka Enberg kvm__irq_line(self, device.irq, 0); 87e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 1); 88e557eef9SPekka Enberg } 898bb34e0dSPekka Enberg } 908bb34e0dSPekka Enberg 9146aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 9213a7760fSPekka Enberg { 9346aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 9446aa8d69SPekka Enberg 959a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 9646aa8d69SPekka Enberg switch (offset) { 974e49b05bSCyrill Gorcunov case UART_DLL: 9846aa8d69SPekka Enberg device.dll = ioport__read8(data); 9946aa8d69SPekka Enberg break; 1004e49b05bSCyrill Gorcunov case UART_DLM: 10146aa8d69SPekka Enberg device.dlm = ioport__read8(data); 10246aa8d69SPekka Enberg break; 1034e49b05bSCyrill Gorcunov case UART_FCR: 10446aa8d69SPekka Enberg device.fcr = ioport__read8(data); 10546aa8d69SPekka Enberg break; 1064e49b05bSCyrill Gorcunov case UART_LCR: 10746aa8d69SPekka Enberg device.lcr = ioport__read8(data); 10846aa8d69SPekka Enberg break; 10946aa8d69SPekka Enberg default: 11046aa8d69SPekka Enberg return false; 11146aa8d69SPekka Enberg } 11246aa8d69SPekka Enberg } else { 11346aa8d69SPekka Enberg switch (offset) { 1144e49b05bSCyrill Gorcunov case UART_TX: { 11513a7760fSPekka Enberg char *p = data; 116f2d8dc88SCyrill Gorcunov int i; 11713a7760fSPekka Enberg 118f2d8dc88SCyrill Gorcunov while (count--) { 119f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 120b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 1215b9d0b58SAsias He } 122b7475544SPekka Enberg fflush(stdout); 123e557eef9SPekka Enberg 12446aa8d69SPekka Enberg break; 12546aa8d69SPekka Enberg } 1264e49b05bSCyrill Gorcunov case UART_IER: 12746aa8d69SPekka Enberg device.ier = ioport__read8(data); 12846aa8d69SPekka Enberg break; 1294e49b05bSCyrill Gorcunov case UART_FCR: 13046aa8d69SPekka Enberg device.fcr = ioport__read8(data); 13146aa8d69SPekka Enberg break; 1324e49b05bSCyrill Gorcunov case UART_LCR: 13346aa8d69SPekka Enberg device.lcr = ioport__read8(data); 13446aa8d69SPekka Enberg break; 1354e49b05bSCyrill Gorcunov case UART_MCR: 13646aa8d69SPekka Enberg device.mcr = ioport__read8(data); 13746aa8d69SPekka Enberg break; 1384e49b05bSCyrill Gorcunov case UART_SCR: 13946aa8d69SPekka Enberg device.scr = ioport__read8(data); 14046aa8d69SPekka Enberg break; 14146aa8d69SPekka Enberg default: 14246aa8d69SPekka Enberg return false; 14346aa8d69SPekka Enberg } 14446aa8d69SPekka Enberg } 14513a7760fSPekka Enberg 14613a7760fSPekka Enberg return true; 14713a7760fSPekka Enberg } 14813a7760fSPekka Enberg 14946aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 15025af6674SPekka Enberg { 15146aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 15246aa8d69SPekka Enberg 1539a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 15446aa8d69SPekka Enberg return false; 15546aa8d69SPekka Enberg 15646aa8d69SPekka Enberg switch (offset) { 1574e49b05bSCyrill Gorcunov case UART_TX: 15876b4a122SPekka Enberg if (device.lsr & UART_LSR_DR) { 15976b4a122SPekka Enberg device.lsr &= ~UART_LSR_DR; 16076b4a122SPekka Enberg ioport__write8(data, device.thr); 16176b4a122SPekka Enberg } 16246aa8d69SPekka Enberg break; 1634e49b05bSCyrill Gorcunov case UART_IER: 16446aa8d69SPekka Enberg ioport__write8(data, device.ier); 16546aa8d69SPekka Enberg break; 1664e49b05bSCyrill Gorcunov case UART_IIR: 167e557eef9SPekka Enberg ioport__write8(data, device.iir); 16846aa8d69SPekka Enberg break; 1694e49b05bSCyrill Gorcunov case UART_LCR: 17046aa8d69SPekka Enberg ioport__write8(data, device.lcr); 17146aa8d69SPekka Enberg break; 1724e49b05bSCyrill Gorcunov case UART_MCR: 17346aa8d69SPekka Enberg ioport__write8(data, device.mcr); 17446aa8d69SPekka Enberg break; 1754e49b05bSCyrill Gorcunov case UART_LSR: 17676b4a122SPekka Enberg ioport__write8(data, device.lsr); 17746aa8d69SPekka Enberg break; 1784e49b05bSCyrill Gorcunov case UART_MSR: 1799a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 18046aa8d69SPekka Enberg break; 1814e49b05bSCyrill Gorcunov case UART_SCR: 18246aa8d69SPekka Enberg ioport__write8(data, device.scr); 18346aa8d69SPekka Enberg break; 18446aa8d69SPekka Enberg default: 18546aa8d69SPekka Enberg return false; 18625af6674SPekka Enberg } 18725af6674SPekka Enberg 18813a7760fSPekka Enberg return true; 18913a7760fSPekka Enberg } 19013a7760fSPekka Enberg 19146aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 19246aa8d69SPekka Enberg .io_in = serial8250_in, 19346aa8d69SPekka Enberg .io_out = serial8250_out, 194a93ec68bSPekka Enberg }; 195a93ec68bSPekka Enberg 196899fe063SPekka Enberg void serial8250__init(void) 19713a7760fSPekka Enberg { 19846aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 19913a7760fSPekka Enberg } 200