113a7760fSPekka Enberg #include "kvm/early_printk.h" 213a7760fSPekka Enberg 313a7760fSPekka Enberg #include "kvm/ioport.h" 4*46aa8d69SPekka Enberg #include "kvm/util.h" 513a7760fSPekka Enberg 6*46aa8d69SPekka Enberg #include <stdbool.h> 713a7760fSPekka Enberg 8*46aa8d69SPekka Enberg /* Transmitter holding register */ 9*46aa8d69SPekka Enberg #define THR 0 103f55f3acSPekka Enberg 11*46aa8d69SPekka Enberg /* Receive buffer register */ 12*46aa8d69SPekka Enberg #define RBR 0 133f55f3acSPekka Enberg 14*46aa8d69SPekka Enberg /* Divisor latch low byte */ 15*46aa8d69SPekka Enberg #define DLL 0 163f55f3acSPekka Enberg 17*46aa8d69SPekka Enberg /* Divisor latch high byte */ 18*46aa8d69SPekka Enberg #define DLM 1 19*46aa8d69SPekka Enberg 20*46aa8d69SPekka Enberg /* Interrupt enable register */ 21*46aa8d69SPekka Enberg #define IER 1 22*46aa8d69SPekka Enberg 23*46aa8d69SPekka Enberg /* Interrupt identification register */ 24*46aa8d69SPekka Enberg #define IIR 2 25*46aa8d69SPekka Enberg 26*46aa8d69SPekka Enberg /* 16550 FIFO Control Register */ 27*46aa8d69SPekka Enberg #define FCR 2 28*46aa8d69SPekka Enberg 29*46aa8d69SPekka Enberg /* Line control register */ 30*46aa8d69SPekka Enberg #define LCR 3 31*46aa8d69SPekka Enberg enum { 32*46aa8d69SPekka Enberg DLAB = 1 << 7, /* Divisor latch access bit (DLAB) */ 33*46aa8d69SPekka Enberg /* bit 7 - set break enable */ 34*46aa8d69SPekka Enberg PM2 = 1 << 5, 35*46aa8d69SPekka Enberg PM1 = 1 << 4, 36*46aa8d69SPekka Enberg PM0 = 1 << 3, 37*46aa8d69SPekka Enberg STB = 1 << 2, 38*46aa8d69SPekka Enberg WLS1 = 1 << 1, 39*46aa8d69SPekka Enberg WLS0 = 1 << 0, 40*46aa8d69SPekka Enberg }; 41*46aa8d69SPekka Enberg 42*46aa8d69SPekka Enberg /* Modem control register */ 43*46aa8d69SPekka Enberg #define MCR 4 44*46aa8d69SPekka Enberg 45*46aa8d69SPekka Enberg /* Line status register */ 46*46aa8d69SPekka Enberg #define LSR 5 47*46aa8d69SPekka Enberg 48*46aa8d69SPekka Enberg /* Modem status register */ 49*46aa8d69SPekka Enberg #define MSR 6 50*46aa8d69SPekka Enberg 51*46aa8d69SPekka Enberg /* Scratch register */ 52*46aa8d69SPekka Enberg #define SCR 7 53*46aa8d69SPekka Enberg 54*46aa8d69SPekka Enberg struct serial8250_device { 55*46aa8d69SPekka Enberg uint16_t iobase; 56*46aa8d69SPekka Enberg uint8_t dll; 57*46aa8d69SPekka Enberg uint8_t dlm; 58*46aa8d69SPekka Enberg uint8_t ier; 59*46aa8d69SPekka Enberg uint8_t fcr; 60*46aa8d69SPekka Enberg uint8_t lcr; 61*46aa8d69SPekka Enberg uint8_t mcr; 62*46aa8d69SPekka Enberg uint8_t scr; 63*46aa8d69SPekka Enberg }; 64*46aa8d69SPekka Enberg 65*46aa8d69SPekka Enberg static struct serial8250_device device = { 66*46aa8d69SPekka Enberg .iobase = 0x3f8, /* ttyS0 */ 67*46aa8d69SPekka Enberg }; 68*46aa8d69SPekka Enberg 69*46aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 7013a7760fSPekka Enberg { 71*46aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 72*46aa8d69SPekka Enberg 73*46aa8d69SPekka Enberg if (device.lcr & DLAB) { 74*46aa8d69SPekka Enberg switch (offset) { 75*46aa8d69SPekka Enberg case DLL: 76*46aa8d69SPekka Enberg device.dll = ioport__read8(data); 77*46aa8d69SPekka Enberg break; 78*46aa8d69SPekka Enberg case DLM: 79*46aa8d69SPekka Enberg device.dlm = ioport__read8(data); 80*46aa8d69SPekka Enberg break; 81*46aa8d69SPekka Enberg case FCR: 82*46aa8d69SPekka Enberg device.fcr = ioport__read8(data); 83*46aa8d69SPekka Enberg break; 84*46aa8d69SPekka Enberg case LCR: 85*46aa8d69SPekka Enberg device.lcr = ioport__read8(data); 86*46aa8d69SPekka Enberg break; 87*46aa8d69SPekka Enberg default: 88*46aa8d69SPekka Enberg return false; 89*46aa8d69SPekka Enberg } 90*46aa8d69SPekka Enberg } else { 91*46aa8d69SPekka Enberg switch (offset) { 92*46aa8d69SPekka Enberg case THR: { 9313a7760fSPekka Enberg char *p = data; 94f2d8dc88SCyrill Gorcunov int i; 9513a7760fSPekka Enberg 96f2d8dc88SCyrill Gorcunov while (count--) { 97f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 98b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 995b9d0b58SAsias He } 100b7475544SPekka Enberg fflush(stdout); 101*46aa8d69SPekka Enberg break; 102*46aa8d69SPekka Enberg } 103*46aa8d69SPekka Enberg case IER: 104*46aa8d69SPekka Enberg device.ier = ioport__read8(data); 105*46aa8d69SPekka Enberg break; 106*46aa8d69SPekka Enberg case FCR: 107*46aa8d69SPekka Enberg device.fcr = ioport__read8(data); 108*46aa8d69SPekka Enberg break; 109*46aa8d69SPekka Enberg case LCR: 110*46aa8d69SPekka Enberg device.lcr = ioport__read8(data); 111*46aa8d69SPekka Enberg break; 112*46aa8d69SPekka Enberg case MCR: 113*46aa8d69SPekka Enberg device.mcr = ioport__read8(data); 114*46aa8d69SPekka Enberg break; 115*46aa8d69SPekka Enberg case SCR: 116*46aa8d69SPekka Enberg device.scr = ioport__read8(data); 117*46aa8d69SPekka Enberg break; 118*46aa8d69SPekka Enberg default: 119*46aa8d69SPekka Enberg return false; 120*46aa8d69SPekka Enberg } 121*46aa8d69SPekka Enberg } 12213a7760fSPekka Enberg 12313a7760fSPekka Enberg return true; 12413a7760fSPekka Enberg } 12513a7760fSPekka Enberg 126*46aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 12725af6674SPekka Enberg { 128*46aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 129*46aa8d69SPekka Enberg 130*46aa8d69SPekka Enberg if (device.lcr & DLAB) 131*46aa8d69SPekka Enberg return false; 132*46aa8d69SPekka Enberg 133*46aa8d69SPekka Enberg switch (offset) { 134*46aa8d69SPekka Enberg case THR: 135*46aa8d69SPekka Enberg ioport__write8(data, 0x00); 136*46aa8d69SPekka Enberg break; 137*46aa8d69SPekka Enberg case IER: 138*46aa8d69SPekka Enberg ioport__write8(data, device.ier); 139*46aa8d69SPekka Enberg break; 140*46aa8d69SPekka Enberg case IIR: 141*46aa8d69SPekka Enberg ioport__write8(data, 0x01); /* no interrupt pending */ 142*46aa8d69SPekka Enberg break; 143*46aa8d69SPekka Enberg case LCR: 144*46aa8d69SPekka Enberg ioport__write8(data, device.lcr); 145*46aa8d69SPekka Enberg break; 146*46aa8d69SPekka Enberg case MCR: 147*46aa8d69SPekka Enberg ioport__write8(data, device.mcr); 148*46aa8d69SPekka Enberg break; 149*46aa8d69SPekka Enberg case LSR: 150*46aa8d69SPekka Enberg ioport__write8(data, 0x20); /* XMTRDY */ 151*46aa8d69SPekka Enberg break; 152*46aa8d69SPekka Enberg case MSR: 153*46aa8d69SPekka Enberg ioport__write8(data, 0x01); /* clear to send */ 154*46aa8d69SPekka Enberg break; 155*46aa8d69SPekka Enberg case SCR: 156*46aa8d69SPekka Enberg ioport__write8(data, device.scr); 157*46aa8d69SPekka Enberg break; 158*46aa8d69SPekka Enberg default: 159*46aa8d69SPekka Enberg return false; 16025af6674SPekka Enberg } 16125af6674SPekka Enberg 16213a7760fSPekka Enberg return true; 16313a7760fSPekka Enberg } 16413a7760fSPekka Enberg 165*46aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 166*46aa8d69SPekka Enberg .io_in = serial8250_in, 167*46aa8d69SPekka Enberg .io_out = serial8250_out, 168a93ec68bSPekka Enberg }; 169a93ec68bSPekka Enberg 17013a7760fSPekka Enberg void early_printk__init(void) 17113a7760fSPekka Enberg { 172*46aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 17313a7760fSPekka Enberg } 174