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 27*900d32c1SPekka 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 6846aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 6913a7760fSPekka Enberg { 7046aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 7146aa8d69SPekka Enberg 729a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 7346aa8d69SPekka Enberg switch (offset) { 7446aa8d69SPekka Enberg case DLL: 7546aa8d69SPekka Enberg device.dll = ioport__read8(data); 7646aa8d69SPekka Enberg break; 7746aa8d69SPekka Enberg case DLM: 7846aa8d69SPekka Enberg device.dlm = ioport__read8(data); 7946aa8d69SPekka Enberg break; 8046aa8d69SPekka Enberg case FCR: 8146aa8d69SPekka Enberg device.fcr = ioport__read8(data); 8246aa8d69SPekka Enberg break; 8346aa8d69SPekka Enberg case LCR: 8446aa8d69SPekka Enberg device.lcr = ioport__read8(data); 8546aa8d69SPekka Enberg break; 8646aa8d69SPekka Enberg default: 8746aa8d69SPekka Enberg return false; 8846aa8d69SPekka Enberg } 8946aa8d69SPekka Enberg } else { 9046aa8d69SPekka Enberg switch (offset) { 9146aa8d69SPekka Enberg case THR: { 9213a7760fSPekka Enberg char *p = data; 93f2d8dc88SCyrill Gorcunov int i; 9413a7760fSPekka Enberg 95f2d8dc88SCyrill Gorcunov while (count--) { 96f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 97b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 985b9d0b58SAsias He } 99b7475544SPekka Enberg fflush(stdout); 10046aa8d69SPekka Enberg break; 10146aa8d69SPekka Enberg } 10246aa8d69SPekka Enberg case IER: 10346aa8d69SPekka Enberg device.ier = ioport__read8(data); 10446aa8d69SPekka Enberg break; 10546aa8d69SPekka Enberg case FCR: 10646aa8d69SPekka Enberg device.fcr = ioport__read8(data); 10746aa8d69SPekka Enberg break; 10846aa8d69SPekka Enberg case LCR: 10946aa8d69SPekka Enberg device.lcr = ioport__read8(data); 11046aa8d69SPekka Enberg break; 11146aa8d69SPekka Enberg case MCR: 11246aa8d69SPekka Enberg device.mcr = ioport__read8(data); 11346aa8d69SPekka Enberg break; 11446aa8d69SPekka Enberg case SCR: 11546aa8d69SPekka Enberg device.scr = ioport__read8(data); 11646aa8d69SPekka Enberg break; 11746aa8d69SPekka Enberg default: 11846aa8d69SPekka Enberg return false; 11946aa8d69SPekka Enberg } 12046aa8d69SPekka Enberg } 12113a7760fSPekka Enberg 12213a7760fSPekka Enberg return true; 12313a7760fSPekka Enberg } 12413a7760fSPekka Enberg 12546aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 12625af6674SPekka Enberg { 12746aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 12846aa8d69SPekka Enberg 1299a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 13046aa8d69SPekka Enberg return false; 13146aa8d69SPekka Enberg 13246aa8d69SPekka Enberg switch (offset) { 13346aa8d69SPekka Enberg case THR: 134*900d32c1SPekka Enberg /* TODO: input support */ 13546aa8d69SPekka Enberg break; 13646aa8d69SPekka Enberg case IER: 13746aa8d69SPekka Enberg ioport__write8(data, device.ier); 13846aa8d69SPekka Enberg break; 13946aa8d69SPekka Enberg case IIR: 140*900d32c1SPekka Enberg ioport__write8(data, UART_IIR_NO_INT | UART_IIR_THRI); 14146aa8d69SPekka Enberg break; 14246aa8d69SPekka Enberg case LCR: 14346aa8d69SPekka Enberg ioport__write8(data, device.lcr); 14446aa8d69SPekka Enberg break; 14546aa8d69SPekka Enberg case MCR: 14646aa8d69SPekka Enberg ioport__write8(data, device.mcr); 14746aa8d69SPekka Enberg break; 14846aa8d69SPekka Enberg case LSR: 1499a7428ddSPekka Enberg ioport__write8(data, UART_LSR_THRE); 15046aa8d69SPekka Enberg break; 15146aa8d69SPekka Enberg case MSR: 1529a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 15346aa8d69SPekka Enberg break; 15446aa8d69SPekka Enberg case SCR: 15546aa8d69SPekka Enberg ioport__write8(data, device.scr); 15646aa8d69SPekka Enberg break; 15746aa8d69SPekka Enberg default: 15846aa8d69SPekka Enberg return false; 15925af6674SPekka Enberg } 16025af6674SPekka Enberg 16113a7760fSPekka Enberg return true; 16213a7760fSPekka Enberg } 16313a7760fSPekka Enberg 16446aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 16546aa8d69SPekka Enberg .io_in = serial8250_in, 16646aa8d69SPekka Enberg .io_out = serial8250_out, 167a93ec68bSPekka Enberg }; 168a93ec68bSPekka Enberg 16913a7760fSPekka Enberg void early_printk__init(void) 17013a7760fSPekka Enberg { 17146aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 17213a7760fSPekka Enberg } 173