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 .iir = UART_IIR_NO_INT, 33 .lsr = UART_LSR_TEMT | UART_LSR_THRE, 34 }; 35 36 static int read_char(int fd) 37 { 38 int c; 39 40 if (read(fd, &c, 1) < 0) 41 return -1; 42 43 return c; 44 } 45 46 static bool is_readable(int fd) 47 { 48 struct pollfd pollfd = (struct pollfd) { 49 .fd = fd, 50 .events = POLLIN, 51 }; 52 53 return poll(&pollfd, 1, 0) > 0; 54 } 55 56 void serial8250__interrupt(struct kvm *self) 57 { 58 if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 59 int c; 60 61 c = read_char(fileno(stdin)); 62 if (c >= 0) { 63 device.thr = c; 64 device.lsr |= UART_LSR_DR; 65 } 66 } 67 68 if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) { 69 device.iir &= ~UART_IIR_NO_INT; 70 kvm__irq_line(self, device.irq, 1); 71 } 72 } 73 74 static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 75 { 76 uint16_t offset = port - device.iobase; 77 78 if (device.lcr & UART_LCR_DLAB) { 79 switch (offset) { 80 case UART_DLL: 81 device.dll = ioport__read8(data); 82 break; 83 case UART_DLM: 84 device.dlm = ioport__read8(data); 85 break; 86 case UART_FCR: 87 device.fcr = ioport__read8(data); 88 break; 89 case UART_LCR: 90 device.lcr = ioport__read8(data); 91 break; 92 default: 93 return false; 94 } 95 } else { 96 switch (offset) { 97 case UART_TX: { 98 char *p = data; 99 int i; 100 101 while (count--) { 102 for (i = 0; i < size; i++) 103 fprintf(stdout, "%c", *p++); 104 } 105 fflush(stdout); 106 107 device.iir |= UART_IIR_NO_INT; 108 kvm__irq_line(self, device.irq, 0); 109 110 break; 111 } 112 case UART_IER: 113 device.ier = ioport__read8(data); 114 break; 115 case UART_FCR: 116 device.fcr = ioport__read8(data); 117 break; 118 case UART_LCR: 119 device.lcr = ioport__read8(data); 120 break; 121 case UART_MCR: 122 device.mcr = ioport__read8(data); 123 break; 124 case UART_SCR: 125 device.scr = ioport__read8(data); 126 break; 127 default: 128 return false; 129 } 130 } 131 132 return true; 133 } 134 135 static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 136 { 137 uint16_t offset = port - device.iobase; 138 139 if (device.lcr & UART_LCR_DLAB) 140 return false; 141 142 switch (offset) { 143 case UART_TX: 144 if (device.lsr & UART_LSR_DR) { 145 device.lsr &= ~UART_LSR_DR; 146 ioport__write8(data, device.thr); 147 148 device.iir |= UART_IIR_NO_INT; 149 kvm__irq_line(self, device.irq, 0); 150 } 151 break; 152 case UART_IER: 153 ioport__write8(data, device.ier); 154 break; 155 case UART_IIR: 156 ioport__write8(data, device.iir); 157 break; 158 case UART_LCR: 159 ioport__write8(data, device.lcr); 160 break; 161 case UART_MCR: 162 ioport__write8(data, device.mcr); 163 break; 164 case UART_LSR: 165 ioport__write8(data, device.lsr); 166 break; 167 case UART_MSR: 168 ioport__write8(data, UART_MSR_CTS); 169 break; 170 case UART_SCR: 171 ioport__write8(data, device.scr); 172 break; 173 default: 174 return false; 175 } 176 177 return true; 178 } 179 180 static struct ioport_operations serial8250_ops = { 181 .io_in = serial8250_in, 182 .io_out = serial8250_out, 183 }; 184 185 void serial8250__init(void) 186 { 187 ioport__register(device.iobase, &serial8250_ops, 8); 188 } 189