113a7760fSPekka Enberg #include "kvm/early_printk.h" 213a7760fSPekka Enberg 313a7760fSPekka Enberg #include "kvm/ioport.h" 446aa8d69SPekka Enberg #include "kvm/util.h" 513a7760fSPekka Enberg 646aa8d69SPekka Enberg #include <stdbool.h> 713a7760fSPekka Enberg 846aa8d69SPekka Enberg /* Transmitter holding register */ 946aa8d69SPekka Enberg #define THR 0 103f55f3acSPekka Enberg 1146aa8d69SPekka Enberg /* Receive buffer register */ 1246aa8d69SPekka Enberg #define RBR 0 133f55f3acSPekka Enberg 1446aa8d69SPekka Enberg /* Divisor latch low byte */ 1546aa8d69SPekka Enberg #define DLL 0 163f55f3acSPekka Enberg 1746aa8d69SPekka Enberg /* Divisor latch high byte */ 1846aa8d69SPekka Enberg #define DLM 1 1946aa8d69SPekka Enberg 2046aa8d69SPekka Enberg /* Interrupt enable register */ 2146aa8d69SPekka Enberg #define IER 1 2246aa8d69SPekka Enberg 2346aa8d69SPekka Enberg /* Interrupt identification register */ 2446aa8d69SPekka Enberg #define IIR 2 2546aa8d69SPekka Enberg 269a7428ddSPekka Enberg #define UART_IIR_NO_INT 0x01 27900d32c1SPekka Enberg #define UART_IIR_THRI 0x02 289a7428ddSPekka Enberg 2946aa8d69SPekka Enberg /* 16550 FIFO Control Register */ 3046aa8d69SPekka Enberg #define FCR 2 3146aa8d69SPekka Enberg 3246aa8d69SPekka Enberg /* Line control register */ 3346aa8d69SPekka Enberg #define LCR 3 349a7428ddSPekka Enberg 359a7428ddSPekka Enberg #define UART_LCR_DLAB 0x80 3646aa8d69SPekka Enberg 3746aa8d69SPekka Enberg /* Modem control register */ 3846aa8d69SPekka Enberg #define MCR 4 3946aa8d69SPekka Enberg 4046aa8d69SPekka Enberg /* Line status register */ 4146aa8d69SPekka Enberg #define LSR 5 4246aa8d69SPekka Enberg 439a7428ddSPekka Enberg #define UART_LSR_THRE 0x20 449a7428ddSPekka Enberg 4546aa8d69SPekka Enberg /* Modem status register */ 4646aa8d69SPekka Enberg #define MSR 6 4746aa8d69SPekka Enberg 489a7428ddSPekka Enberg #define UART_MSR_CTS 0x10 499a7428ddSPekka Enberg 5046aa8d69SPekka Enberg /* Scratch register */ 5146aa8d69SPekka Enberg #define SCR 7 5246aa8d69SPekka Enberg 5346aa8d69SPekka Enberg struct serial8250_device { 5446aa8d69SPekka Enberg uint16_t iobase; 5546aa8d69SPekka Enberg uint8_t dll; 5646aa8d69SPekka Enberg uint8_t dlm; 5746aa8d69SPekka Enberg uint8_t ier; 5846aa8d69SPekka Enberg uint8_t fcr; 5946aa8d69SPekka Enberg uint8_t lcr; 6046aa8d69SPekka Enberg uint8_t mcr; 6146aa8d69SPekka Enberg uint8_t scr; 6246aa8d69SPekka Enberg }; 6346aa8d69SPekka Enberg 6446aa8d69SPekka Enberg static struct serial8250_device device = { 6546aa8d69SPekka Enberg .iobase = 0x3f8, /* ttyS0 */ 6646aa8d69SPekka Enberg }; 6746aa8d69SPekka Enberg 68*8bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self) 69*8bb34e0dSPekka Enberg { 70*8bb34e0dSPekka Enberg /* TODO: inject 8250 interrupt for the guest */ 71*8bb34e0dSPekka Enberg } 72*8bb34e0dSPekka Enberg 7346aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 7413a7760fSPekka Enberg { 7546aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 7646aa8d69SPekka Enberg 779a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 7846aa8d69SPekka Enberg switch (offset) { 7946aa8d69SPekka Enberg case DLL: 8046aa8d69SPekka Enberg device.dll = ioport__read8(data); 8146aa8d69SPekka Enberg break; 8246aa8d69SPekka Enberg case DLM: 8346aa8d69SPekka Enberg device.dlm = ioport__read8(data); 8446aa8d69SPekka Enberg break; 8546aa8d69SPekka Enberg case FCR: 8646aa8d69SPekka Enberg device.fcr = ioport__read8(data); 8746aa8d69SPekka Enberg break; 8846aa8d69SPekka Enberg case LCR: 8946aa8d69SPekka Enberg device.lcr = ioport__read8(data); 9046aa8d69SPekka Enberg break; 9146aa8d69SPekka Enberg default: 9246aa8d69SPekka Enberg return false; 9346aa8d69SPekka Enberg } 9446aa8d69SPekka Enberg } else { 9546aa8d69SPekka Enberg switch (offset) { 9646aa8d69SPekka Enberg case THR: { 9713a7760fSPekka Enberg char *p = data; 98f2d8dc88SCyrill Gorcunov int i; 9913a7760fSPekka Enberg 100f2d8dc88SCyrill Gorcunov while (count--) { 101f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 102b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 1035b9d0b58SAsias He } 104b7475544SPekka Enberg fflush(stdout); 10546aa8d69SPekka Enberg break; 10646aa8d69SPekka Enberg } 10746aa8d69SPekka Enberg case IER: 10846aa8d69SPekka Enberg device.ier = ioport__read8(data); 10946aa8d69SPekka Enberg break; 11046aa8d69SPekka Enberg case FCR: 11146aa8d69SPekka Enberg device.fcr = ioport__read8(data); 11246aa8d69SPekka Enberg break; 11346aa8d69SPekka Enberg case LCR: 11446aa8d69SPekka Enberg device.lcr = ioport__read8(data); 11546aa8d69SPekka Enberg break; 11646aa8d69SPekka Enberg case MCR: 11746aa8d69SPekka Enberg device.mcr = ioport__read8(data); 11846aa8d69SPekka Enberg break; 11946aa8d69SPekka Enberg case SCR: 12046aa8d69SPekka Enberg device.scr = ioport__read8(data); 12146aa8d69SPekka Enberg break; 12246aa8d69SPekka Enberg default: 12346aa8d69SPekka Enberg return false; 12446aa8d69SPekka Enberg } 12546aa8d69SPekka Enberg } 12613a7760fSPekka Enberg 12713a7760fSPekka Enberg return true; 12813a7760fSPekka Enberg } 12913a7760fSPekka Enberg 13046aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 13125af6674SPekka Enberg { 13246aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 13346aa8d69SPekka Enberg 1349a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 13546aa8d69SPekka Enberg return false; 13646aa8d69SPekka Enberg 13746aa8d69SPekka Enberg switch (offset) { 13846aa8d69SPekka Enberg case THR: 139900d32c1SPekka Enberg /* TODO: input support */ 14046aa8d69SPekka Enberg break; 14146aa8d69SPekka Enberg case IER: 14246aa8d69SPekka Enberg ioport__write8(data, device.ier); 14346aa8d69SPekka Enberg break; 14446aa8d69SPekka Enberg case IIR: 145900d32c1SPekka Enberg ioport__write8(data, UART_IIR_NO_INT | UART_IIR_THRI); 14646aa8d69SPekka Enberg break; 14746aa8d69SPekka Enberg case LCR: 14846aa8d69SPekka Enberg ioport__write8(data, device.lcr); 14946aa8d69SPekka Enberg break; 15046aa8d69SPekka Enberg case MCR: 15146aa8d69SPekka Enberg ioport__write8(data, device.mcr); 15246aa8d69SPekka Enberg break; 15346aa8d69SPekka Enberg case LSR: 1549a7428ddSPekka Enberg ioport__write8(data, UART_LSR_THRE); 15546aa8d69SPekka Enberg break; 15646aa8d69SPekka Enberg case MSR: 1579a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 15846aa8d69SPekka Enberg break; 15946aa8d69SPekka Enberg case SCR: 16046aa8d69SPekka Enberg ioport__write8(data, device.scr); 16146aa8d69SPekka Enberg break; 16246aa8d69SPekka Enberg default: 16346aa8d69SPekka Enberg return false; 16425af6674SPekka Enberg } 16525af6674SPekka Enberg 16613a7760fSPekka Enberg return true; 16713a7760fSPekka Enberg } 16813a7760fSPekka Enberg 16946aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 17046aa8d69SPekka Enberg .io_in = serial8250_in, 17146aa8d69SPekka Enberg .io_out = serial8250_out, 172a93ec68bSPekka Enberg }; 173a93ec68bSPekka Enberg 17413a7760fSPekka Enberg void early_printk__init(void) 17513a7760fSPekka Enberg { 17646aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 17713a7760fSPekka Enberg } 178