1 #include "kvm/8250-serial.h" 2 3 #include "kvm/ioport.h" 4 #include "kvm/util.h" 5 #include "kvm/kvm.h" 6 7 #include <linux/serial_reg.h> 8 9 #include <stdbool.h> 10 #include <poll.h> 11 12 struct serial8250_device { 13 uint16_t iobase; 14 uint8_t irq; 15 16 uint8_t thr; 17 uint8_t dll; 18 uint8_t dlm; 19 uint8_t iir; 20 uint8_t ier; 21 uint8_t fcr; 22 uint8_t lcr; 23 uint8_t mcr; 24 uint8_t lsr; 25 uint8_t scr; 26 }; 27 28 static struct serial8250_device device = { 29 .iobase = 0x3f8, /* ttyS0 */ 30 .irq = 4, 31 32 .lsr = UART_LSR_TEMT | UART_LSR_THRE, 33 }; 34 35 static int read_char(int fd) 36 { 37 int c; 38 39 if (read(fd, &c, 1) < 0) 40 return -1; 41 42 return c; 43 } 44 45 static bool is_readable(int fd) 46 { 47 struct pollfd pollfd = (struct pollfd) { 48 .fd = fd, 49 .events = POLLIN, 50 }; 51 52 return poll(&pollfd, 1, 0) > 0; 53 } 54 55 void serial8250__interrupt(struct kvm *self) 56 { 57 uint8_t new_iir; 58 59 device.iir = UART_IIR_NO_INT; 60 61 /* No interrupts enabled. Exit... */ 62 if (!(device.ier & (UART_IER_THRI|UART_IER_RDI))) 63 return; 64 65 new_iir = 0; 66 67 /* We're always good for guest sending data. */ 68 if (device.ier & UART_IER_THRI) 69 new_iir |= UART_IIR_THRI; 70 71 /* Is there input in stdin to send to the guest? */ 72 if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 73 int c; 74 75 c = read_char(fileno(stdin)); 76 if (c >= 0) { 77 device.thr = c; 78 device.lsr |= UART_LSR_DR; 79 new_iir |= UART_IIR_RDI; 80 } 81 } 82 83 /* Only send an IRQ if there's work to do. */ 84 if (new_iir) { 85 device.iir = new_iir; 86 kvm__irq_line(self, device.irq, 0); 87 kvm__irq_line(self, device.irq, 1); 88 } 89 } 90 91 static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 92 { 93 uint16_t offset = port - device.iobase; 94 95 if (device.lcr & UART_LCR_DLAB) { 96 switch (offset) { 97 case UART_DLL: 98 device.dll = ioport__read8(data); 99 break; 100 case UART_DLM: 101 device.dlm = ioport__read8(data); 102 break; 103 case UART_FCR: 104 device.fcr = ioport__read8(data); 105 break; 106 case UART_LCR: 107 device.lcr = ioport__read8(data); 108 break; 109 default: 110 return false; 111 } 112 } else { 113 switch (offset) { 114 case UART_TX: { 115 char *p = data; 116 int i; 117 118 while (count--) { 119 for (i = 0; i < size; i++) 120 fprintf(stdout, "%c", *p++); 121 } 122 fflush(stdout); 123 124 break; 125 } 126 case UART_IER: 127 device.ier = ioport__read8(data); 128 break; 129 case UART_FCR: 130 device.fcr = ioport__read8(data); 131 break; 132 case UART_LCR: 133 device.lcr = ioport__read8(data); 134 break; 135 case UART_MCR: 136 device.mcr = ioport__read8(data); 137 break; 138 case UART_SCR: 139 device.scr = ioport__read8(data); 140 break; 141 default: 142 return false; 143 } 144 } 145 146 return true; 147 } 148 149 static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 150 { 151 uint16_t offset = port - device.iobase; 152 153 if (device.lcr & UART_LCR_DLAB) 154 return false; 155 156 switch (offset) { 157 case UART_TX: 158 if (device.lsr & UART_LSR_DR) { 159 device.lsr &= ~UART_LSR_DR; 160 ioport__write8(data, device.thr); 161 } 162 break; 163 case UART_IER: 164 ioport__write8(data, device.ier); 165 break; 166 case UART_IIR: 167 ioport__write8(data, device.iir); 168 break; 169 case UART_LCR: 170 ioport__write8(data, device.lcr); 171 break; 172 case UART_MCR: 173 ioport__write8(data, device.mcr); 174 break; 175 case UART_LSR: 176 ioport__write8(data, device.lsr); 177 break; 178 case UART_MSR: 179 ioport__write8(data, UART_MSR_CTS); 180 break; 181 case UART_SCR: 182 ioport__write8(data, device.scr); 183 break; 184 default: 185 return false; 186 } 187 188 return true; 189 } 190 191 static struct ioport_operations serial8250_ops = { 192 .io_in = serial8250_in, 193 .io_out = serial8250_out, 194 }; 195 196 void serial8250__init(void) 197 { 198 ioport__register(device.iobase, &serial8250_ops, 8); 199 } 200