From 363909a931bfe26de356435d3db3d85e4122d3d9 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sat, 8 Jan 2011 19:29:23 +0200 Subject: [PATCH] kvm: Improve 8250 serial console support Signed-off-by: Pekka Enberg --- tools/kvm/early_printk.c | 183 +++++++++++++++++++++++++++++++-------- 1 file changed, 145 insertions(+), 38 deletions(-) diff --git a/tools/kvm/early_printk.c b/tools/kvm/early_printk.c index 6087976a4093..ffc405fa86c6 100644 --- a/tools/kvm/early_printk.c +++ b/tools/kvm/early_printk.c @@ -1,66 +1,173 @@ #include "kvm/early_printk.h" #include "kvm/ioport.h" +#include "kvm/util.h" -#include +#include -static int early_serial_base = 0x3f8; /* ttyS0 */ +/* Transmitter holding register */ +#define THR 0 -#define XMTRDY 0x20 +/* Receive buffer register */ +#define RBR 0 -#define TXR 0 /* Transmit register (WRITE) */ -#define LSR 5 /* Line Status */ -#define MSR 6 /* Modem Status */ +/* Divisor latch low byte */ +#define DLL 0 -static bool early_serial_txr_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) -{ - char *p = data; - int i; +/* Divisor latch high byte */ +#define DLM 1 - while (count--) { - for (i = 0; i < size; i++) - fprintf(stdout, "%c", *p++); - } - fflush(stdout); +/* Interrupt enable register */ +#define IER 1 - return true; -} +/* Interrupt identification register */ +#define IIR 2 -static bool early_serial_rxr_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) -{ - return true; -} +/* 16550 FIFO Control Register */ +#define FCR 2 -static struct ioport_operations early_serial_txr_rxr_ops = { - .io_out = early_serial_txr_out, - .io_in = early_serial_rxr_in, +/* Line control register */ +#define LCR 3 +enum { + DLAB = 1 << 7, /* Divisor latch access bit (DLAB) */ + /* bit 7 - set break enable */ + PM2 = 1 << 5, + PM1 = 1 << 4, + PM0 = 1 << 3, + STB = 1 << 2, + WLS1 = 1 << 1, + WLS0 = 1 << 0, }; -static bool early_serial_lsr_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) -{ - uint8_t *p = data; +/* Modem control register */ +#define MCR 4 - *p = XMTRDY; +/* Line status register */ +#define LSR 5 - return true; -} +/* Modem status register */ +#define MSR 6 + +/* Scratch register */ +#define SCR 7 -static struct ioport_operations early_serial_lsr_ops = { - .io_in = early_serial_lsr_in, +struct serial8250_device { + uint16_t iobase; + uint8_t dll; + uint8_t dlm; + uint8_t ier; + uint8_t fcr; + uint8_t lcr; + uint8_t mcr; + uint8_t scr; }; -static bool early_serial_msr_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) +static struct serial8250_device device = { + .iobase = 0x3f8, /* ttyS0 */ +}; + +static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) +{ + uint16_t offset = port - device.iobase; + + if (device.lcr & DLAB) { + switch (offset) { + case DLL: + device.dll = ioport__read8(data); + break; + case DLM: + device.dlm = ioport__read8(data); + break; + case FCR: + device.fcr = ioport__read8(data); + break; + case LCR: + device.lcr = ioport__read8(data); + break; + default: + return false; + } + } else { + switch (offset) { + case THR: { + char *p = data; + int i; + + while (count--) { + for (i = 0; i < size; i++) + fprintf(stdout, "%c", *p++); + } + fflush(stdout); + break; + } + case IER: + device.ier = ioport__read8(data); + break; + case FCR: + device.fcr = ioport__read8(data); + break; + case LCR: + device.lcr = ioport__read8(data); + break; + case MCR: + device.mcr = ioport__read8(data); + break; + case SCR: + device.scr = ioport__read8(data); + break; + default: + return false; + } + } + + return true; +} + +static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) { + uint16_t offset = port - device.iobase; + + if (device.lcr & DLAB) + return false; + + switch (offset) { + case THR: + ioport__write8(data, 0x00); + break; + case IER: + ioport__write8(data, device.ier); + break; + case IIR: + ioport__write8(data, 0x01); /* no interrupt pending */ + break; + case LCR: + ioport__write8(data, device.lcr); + break; + case MCR: + ioport__write8(data, device.mcr); + break; + case LSR: + ioport__write8(data, 0x20); /* XMTRDY */ + break; + case MSR: + ioport__write8(data, 0x01); /* clear to send */ + break; + case SCR: + ioport__write8(data, device.scr); + break; + default: + return false; + } + return true; } -static struct ioport_operations early_serial_msr_ops = { - .io_in = early_serial_msr_in, +static struct ioport_operations serial8250_ops = { + .io_in = serial8250_in, + .io_out = serial8250_out, }; void early_printk__init(void) { - ioport__register(early_serial_base + TXR, &early_serial_txr_rxr_ops, 1); - ioport__register(early_serial_base + LSR, &early_serial_lsr_ops, 1); - ioport__register(early_serial_base + MSR, &early_serial_msr_ops, 1); + ioport__register(device.iobase, &serial8250_ops, 8); } -- 2.39.5