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 26*9a7428ddSPekka Enberg #define UART_IIR_NO_INT 0x01 27*9a7428ddSPekka Enberg 2846aa8d69SPekka Enberg /* 16550 FIFO Control Register */ 2946aa8d69SPekka Enberg #define FCR 2 3046aa8d69SPekka Enberg 3146aa8d69SPekka Enberg /* Line control register */ 3246aa8d69SPekka Enberg #define LCR 3 33*9a7428ddSPekka Enberg 34*9a7428ddSPekka Enberg #define UART_LCR_DLAB 0x80 3546aa8d69SPekka Enberg 3646aa8d69SPekka Enberg /* Modem control register */ 3746aa8d69SPekka Enberg #define MCR 4 3846aa8d69SPekka Enberg 3946aa8d69SPekka Enberg /* Line status register */ 4046aa8d69SPekka Enberg #define LSR 5 4146aa8d69SPekka Enberg 42*9a7428ddSPekka Enberg #define UART_LSR_THRE 0x20 43*9a7428ddSPekka Enberg 4446aa8d69SPekka Enberg /* Modem status register */ 4546aa8d69SPekka Enberg #define MSR 6 4646aa8d69SPekka Enberg 47*9a7428ddSPekka Enberg #define UART_MSR_CTS 0x10 48*9a7428ddSPekka Enberg 4946aa8d69SPekka Enberg /* Scratch register */ 5046aa8d69SPekka Enberg #define SCR 7 5146aa8d69SPekka Enberg 5246aa8d69SPekka Enberg struct serial8250_device { 5346aa8d69SPekka Enberg uint16_t iobase; 5446aa8d69SPekka Enberg uint8_t dll; 5546aa8d69SPekka Enberg uint8_t dlm; 5646aa8d69SPekka Enberg uint8_t ier; 5746aa8d69SPekka Enberg uint8_t fcr; 5846aa8d69SPekka Enberg uint8_t lcr; 5946aa8d69SPekka Enberg uint8_t mcr; 6046aa8d69SPekka Enberg uint8_t scr; 6146aa8d69SPekka Enberg }; 6246aa8d69SPekka Enberg 6346aa8d69SPekka Enberg static struct serial8250_device device = { 6446aa8d69SPekka Enberg .iobase = 0x3f8, /* ttyS0 */ 6546aa8d69SPekka Enberg }; 6646aa8d69SPekka Enberg 6746aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 6813a7760fSPekka Enberg { 6946aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 7046aa8d69SPekka Enberg 71*9a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 7246aa8d69SPekka Enberg switch (offset) { 7346aa8d69SPekka Enberg case DLL: 7446aa8d69SPekka Enberg device.dll = ioport__read8(data); 7546aa8d69SPekka Enberg break; 7646aa8d69SPekka Enberg case DLM: 7746aa8d69SPekka Enberg device.dlm = ioport__read8(data); 7846aa8d69SPekka Enberg break; 7946aa8d69SPekka Enberg case FCR: 8046aa8d69SPekka Enberg device.fcr = ioport__read8(data); 8146aa8d69SPekka Enberg break; 8246aa8d69SPekka Enberg case LCR: 8346aa8d69SPekka Enberg device.lcr = ioport__read8(data); 8446aa8d69SPekka Enberg break; 8546aa8d69SPekka Enberg default: 8646aa8d69SPekka Enberg return false; 8746aa8d69SPekka Enberg } 8846aa8d69SPekka Enberg } else { 8946aa8d69SPekka Enberg switch (offset) { 9046aa8d69SPekka Enberg case THR: { 9113a7760fSPekka Enberg char *p = data; 92f2d8dc88SCyrill Gorcunov int i; 9313a7760fSPekka Enberg 94f2d8dc88SCyrill Gorcunov while (count--) { 95f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 96b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 975b9d0b58SAsias He } 98b7475544SPekka Enberg fflush(stdout); 9946aa8d69SPekka Enberg break; 10046aa8d69SPekka Enberg } 10146aa8d69SPekka Enberg case IER: 10246aa8d69SPekka Enberg device.ier = ioport__read8(data); 10346aa8d69SPekka Enberg break; 10446aa8d69SPekka Enberg case FCR: 10546aa8d69SPekka Enberg device.fcr = ioport__read8(data); 10646aa8d69SPekka Enberg break; 10746aa8d69SPekka Enberg case LCR: 10846aa8d69SPekka Enberg device.lcr = ioport__read8(data); 10946aa8d69SPekka Enberg break; 11046aa8d69SPekka Enberg case MCR: 11146aa8d69SPekka Enberg device.mcr = ioport__read8(data); 11246aa8d69SPekka Enberg break; 11346aa8d69SPekka Enberg case SCR: 11446aa8d69SPekka Enberg device.scr = ioport__read8(data); 11546aa8d69SPekka Enberg break; 11646aa8d69SPekka Enberg default: 11746aa8d69SPekka Enberg return false; 11846aa8d69SPekka Enberg } 11946aa8d69SPekka Enberg } 12013a7760fSPekka Enberg 12113a7760fSPekka Enberg return true; 12213a7760fSPekka Enberg } 12313a7760fSPekka Enberg 12446aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 12525af6674SPekka Enberg { 12646aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 12746aa8d69SPekka Enberg 128*9a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 12946aa8d69SPekka Enberg return false; 13046aa8d69SPekka Enberg 13146aa8d69SPekka Enberg switch (offset) { 13246aa8d69SPekka Enberg case THR: 13346aa8d69SPekka Enberg ioport__write8(data, 0x00); 13446aa8d69SPekka Enberg break; 13546aa8d69SPekka Enberg case IER: 13646aa8d69SPekka Enberg ioport__write8(data, device.ier); 13746aa8d69SPekka Enberg break; 13846aa8d69SPekka Enberg case IIR: 139*9a7428ddSPekka Enberg ioport__write8(data, UART_IIR_NO_INT); 14046aa8d69SPekka Enberg break; 14146aa8d69SPekka Enberg case LCR: 14246aa8d69SPekka Enberg ioport__write8(data, device.lcr); 14346aa8d69SPekka Enberg break; 14446aa8d69SPekka Enberg case MCR: 14546aa8d69SPekka Enberg ioport__write8(data, device.mcr); 14646aa8d69SPekka Enberg break; 14746aa8d69SPekka Enberg case LSR: 148*9a7428ddSPekka Enberg ioport__write8(data, UART_LSR_THRE); 14946aa8d69SPekka Enberg break; 15046aa8d69SPekka Enberg case MSR: 151*9a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 15246aa8d69SPekka Enberg break; 15346aa8d69SPekka Enberg case SCR: 15446aa8d69SPekka Enberg ioport__write8(data, device.scr); 15546aa8d69SPekka Enberg break; 15646aa8d69SPekka Enberg default: 15746aa8d69SPekka Enberg return false; 15825af6674SPekka Enberg } 15925af6674SPekka Enberg 16013a7760fSPekka Enberg return true; 16113a7760fSPekka Enberg } 16213a7760fSPekka Enberg 16346aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 16446aa8d69SPekka Enberg .io_in = serial8250_in, 16546aa8d69SPekka Enberg .io_out = serial8250_out, 166a93ec68bSPekka Enberg }; 167a93ec68bSPekka Enberg 16813a7760fSPekka Enberg void early_printk__init(void) 16913a7760fSPekka Enberg { 17046aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 17113a7760fSPekka Enberg } 172