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 <stdbool.h> 8 #include <poll.h> 9 10 /* Transmitter holding register */ 11 #define THR 0 12 13 /* Receive buffer register */ 14 #define RBR 0 15 16 /* Divisor latch low byte */ 17 #define DLL 0 18 19 /* Divisor latch high byte */ 20 #define DLM 1 21 22 /* Interrupt enable register */ 23 #define IER 1 24 25 #define UART_IER_RDI 0x01 26 #define UART_IER_THRI 0x02 27 28 /* Interrupt identification register */ 29 #define IIR 2 30 31 #define UART_IIR_NO_INT 0x01 32 #define UART_IIR_THRI 0x02 33 34 /* 16550 FIFO Control Register */ 35 #define FCR 2 36 37 /* Line control register */ 38 #define LCR 3 39 40 #define UART_LCR_DLAB 0x80 41 42 /* Modem control register */ 43 #define MCR 4 44 45 /* Line status register */ 46 #define LSR 5 47 48 #define UART_LSR_DR 0x01 49 #define UART_LSR_THRE 0x20 50 51 /* Modem status register */ 52 #define MSR 6 53 54 #define UART_MSR_CTS 0x10 55 56 /* Scratch register */ 57 #define SCR 7 58 59 struct serial8250_device { 60 uint16_t iobase; 61 uint8_t irq; 62 63 uint8_t thr; 64 uint8_t dll; 65 uint8_t dlm; 66 uint8_t iir; 67 uint8_t ier; 68 uint8_t fcr; 69 uint8_t lcr; 70 uint8_t mcr; 71 uint8_t lsr; 72 uint8_t scr; 73 }; 74 75 static struct serial8250_device device = { 76 .iobase = 0x3f8, /* ttyS0 */ 77 .irq = 4, 78 79 .iir = UART_IIR_NO_INT, 80 .lsr = UART_LSR_THRE, 81 }; 82 83 static int read_char(int fd) 84 { 85 int c; 86 87 if (read(fd, &c, 1) < 0) 88 return -1; 89 90 return c; 91 } 92 93 static bool is_readable(int fd) 94 { 95 struct pollfd pollfd; 96 int err; 97 98 pollfd = (struct pollfd) { 99 .fd = fd, 100 .events = POLLIN, 101 }; 102 103 err = poll(&pollfd, 1, 0); 104 return err > 0; 105 } 106 107 void serial8250__interrupt(struct kvm *self) 108 { 109 if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 110 int c; 111 112 c = read_char(fileno(stdin)); 113 if (c >= 0) { 114 device.thr = c; 115 device.lsr |= UART_LSR_DR; 116 } 117 } 118 119 if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) { 120 device.iir &= ~UART_IIR_NO_INT; 121 kvm__irq_line(self, device.irq, 1); 122 } 123 } 124 125 static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 126 { 127 uint16_t offset = port - device.iobase; 128 129 if (device.lcr & UART_LCR_DLAB) { 130 switch (offset) { 131 case DLL: 132 device.dll = ioport__read8(data); 133 break; 134 case DLM: 135 device.dlm = ioport__read8(data); 136 break; 137 case FCR: 138 device.fcr = ioport__read8(data); 139 break; 140 case LCR: 141 device.lcr = ioport__read8(data); 142 break; 143 default: 144 return false; 145 } 146 } else { 147 switch (offset) { 148 case THR: { 149 char *p = data; 150 int i; 151 152 while (count--) { 153 for (i = 0; i < size; i++) 154 fprintf(stdout, "%c", *p++); 155 } 156 fflush(stdout); 157 158 device.iir |= UART_IIR_NO_INT; 159 kvm__irq_line(self, device.irq, 0); 160 161 break; 162 } 163 case IER: 164 device.ier = ioport__read8(data); 165 break; 166 case FCR: 167 device.fcr = ioport__read8(data); 168 break; 169 case LCR: 170 device.lcr = ioport__read8(data); 171 break; 172 case MCR: 173 device.mcr = ioport__read8(data); 174 break; 175 case SCR: 176 device.scr = ioport__read8(data); 177 break; 178 default: 179 return false; 180 } 181 } 182 183 return true; 184 } 185 186 static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 187 { 188 uint16_t offset = port - device.iobase; 189 190 if (device.lcr & UART_LCR_DLAB) 191 return false; 192 193 switch (offset) { 194 case THR: 195 if (device.lsr & UART_LSR_DR) { 196 device.lsr &= ~UART_LSR_DR; 197 ioport__write8(data, device.thr); 198 199 device.iir |= UART_IIR_NO_INT; 200 kvm__irq_line(self, device.irq, 0); 201 } 202 break; 203 case IER: 204 ioport__write8(data, device.ier); 205 break; 206 case IIR: 207 ioport__write8(data, device.iir); 208 break; 209 case LCR: 210 ioport__write8(data, device.lcr); 211 break; 212 case MCR: 213 ioport__write8(data, device.mcr); 214 break; 215 case LSR: 216 ioport__write8(data, device.lsr); 217 break; 218 case MSR: 219 ioport__write8(data, UART_MSR_CTS); 220 break; 221 case SCR: 222 ioport__write8(data, device.scr); 223 break; 224 default: 225 return false; 226 } 227 228 return true; 229 } 230 231 static struct ioport_operations serial8250_ops = { 232 .io_in = serial8250_in, 233 .io_out = serial8250_out, 234 }; 235 236 void serial8250__init(void) 237 { 238 ioport__register(device.iobase, &serial8250_ops, 8); 239 } 240