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 = (struct pollfd) { 96 .fd = fd, 97 .events = POLLIN, 98 }; 99 100 return poll(&pollfd, 1, 0) > 0; 101 } 102 103 void serial8250__interrupt(struct kvm *self) 104 { 105 if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 106 int c; 107 108 c = read_char(fileno(stdin)); 109 if (c >= 0) { 110 device.thr = c; 111 device.lsr |= UART_LSR_DR; 112 } 113 } 114 115 if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) { 116 device.iir &= ~UART_IIR_NO_INT; 117 kvm__irq_line(self, device.irq, 1); 118 } 119 } 120 121 static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 122 { 123 uint16_t offset = port - device.iobase; 124 125 if (device.lcr & UART_LCR_DLAB) { 126 switch (offset) { 127 case DLL: 128 device.dll = ioport__read8(data); 129 break; 130 case DLM: 131 device.dlm = ioport__read8(data); 132 break; 133 case FCR: 134 device.fcr = ioport__read8(data); 135 break; 136 case LCR: 137 device.lcr = ioport__read8(data); 138 break; 139 default: 140 return false; 141 } 142 } else { 143 switch (offset) { 144 case THR: { 145 char *p = data; 146 int i; 147 148 while (count--) { 149 for (i = 0; i < size; i++) 150 fprintf(stdout, "%c", *p++); 151 } 152 fflush(stdout); 153 154 device.iir |= UART_IIR_NO_INT; 155 kvm__irq_line(self, device.irq, 0); 156 157 break; 158 } 159 case IER: 160 device.ier = ioport__read8(data); 161 break; 162 case FCR: 163 device.fcr = ioport__read8(data); 164 break; 165 case LCR: 166 device.lcr = ioport__read8(data); 167 break; 168 case MCR: 169 device.mcr = ioport__read8(data); 170 break; 171 case SCR: 172 device.scr = ioport__read8(data); 173 break; 174 default: 175 return false; 176 } 177 } 178 179 return true; 180 } 181 182 static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 183 { 184 uint16_t offset = port - device.iobase; 185 186 if (device.lcr & UART_LCR_DLAB) 187 return false; 188 189 switch (offset) { 190 case THR: 191 if (device.lsr & UART_LSR_DR) { 192 device.lsr &= ~UART_LSR_DR; 193 ioport__write8(data, device.thr); 194 195 device.iir |= UART_IIR_NO_INT; 196 kvm__irq_line(self, device.irq, 0); 197 } 198 break; 199 case IER: 200 ioport__write8(data, device.ier); 201 break; 202 case IIR: 203 ioport__write8(data, device.iir); 204 break; 205 case LCR: 206 ioport__write8(data, device.lcr); 207 break; 208 case MCR: 209 ioport__write8(data, device.mcr); 210 break; 211 case LSR: 212 ioport__write8(data, device.lsr); 213 break; 214 case MSR: 215 ioport__write8(data, UART_MSR_CTS); 216 break; 217 case SCR: 218 ioport__write8(data, device.scr); 219 break; 220 default: 221 return false; 222 } 223 224 return true; 225 } 226 227 static struct ioport_operations serial8250_ops = { 228 .io_in = serial8250_in, 229 .io_out = serial8250_out, 230 }; 231 232 void serial8250__init(void) 233 { 234 ioport__register(device.iobase, &serial8250_ops, 8); 235 } 236