[SeaBIOS] [PATCH] searialio: Support for mmap serial ports
Kevin O'Connor
kevin at koconnor.net
Tue Dec 20 17:48:11 CET 2016
On Tue, Dec 20, 2016 at 03:01:52PM +0100, Ricardo Ribalda Delgado wrote:
> Some chipsets have memory mapped serial ports. The protocol is the same
> as an standard uart, but with memory read/write instead of inb/outb.
Thanks. See my comments below.
[...]
> --- a/src/Kconfig
> +++ b/src/Kconfig
> @@ -532,6 +532,9 @@ menu "Debugging"
> default 0x3f8
> help
> Base port for serial - generally 0x3f8, 0x2f8, 0x3e8, or 0x2e8.
> + On some boards the serial port is memory mapped, in those cases
> + provide the 32 bit address. E.g. 0xFEDC6000 for the AMD Kern
> + (a.k.a Hudson UART).
Does this chipset hardcode the uart at that memory address or is that
address part of a PCI BAR? If it's on a PCI device it would be
preferable to do a pci scan and find the address.
>
> config DEBUG_IO
> depends on QEMU_HARDWARE && DEBUG_LEVEL != 0
> diff --git a/src/hw/serialio.c b/src/hw/serialio.c
> index 6486fc086b1c..d02ab65f6e9b 100644
> --- a/src/hw/serialio.c
> +++ b/src/hw/serialio.c
> @@ -17,6 +17,20 @@
>
> #define DEBUG_TIMEOUT 100000
>
> +static void
> +serial_outb(u8 val, u32 port, u8 offset){
> + if (port < 0x10000)
> + return outb(val, port + offset);
> + writeb((void *)port + 4*offset, val);
> +}
> +
> +static u8
> +serial_inb(u32 port, u8 offset){
> + if (port < 0x10000)
> + return inb(port + offset);
> + return readb((void *)port + 4*offset);
> +}
> +
> // Setup the debug serial port for output.
> void
> serial_debug_preinit(void)
> @@ -25,12 +39,12 @@ serial_debug_preinit(void)
> return;
> // setup for serial logging: 8N1
> u8 oldparam, newparam = 0x03;
> - oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
> - outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
> + oldparam = serial_inb(CONFIG_DEBUG_SERIAL_PORT, SEROFF_LCR);
> + serial_outb(newparam, CONFIG_DEBUG_SERIAL_PORT, SEROFF_LCR);
> // Disable irqs
> u8 oldier, newier = 0;
> - oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
> - outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
> + oldier = serial_inb(CONFIG_DEBUG_SERIAL_PORT, SEROFF_IER);
> + serial_outb(newier, CONFIG_DEBUG_SERIAL_PORT, SEROFF_IER);
>
> if (oldparam != newparam || oldier != newier)
> dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
> @@ -44,11 +58,11 @@ serial_debug(char c)
> if (!CONFIG_DEBUG_SERIAL)
> return;
> int timeout = DEBUG_TIMEOUT;
> - while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
> + while ((serial_inb(CONFIG_DEBUG_SERIAL_PORT, SEROFF_LSR) & 0x20) != 0x20)
> if (!timeout--)
> // Ran out of time.
> return;
> - outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
> + serial_outb(c, CONFIG_DEBUG_SERIAL_PORT, SEROFF_DATA);
> }
The above code (along with serial_debug_flush() ) can be called in
16bit mode and writing to a 32bit memory address there can cause
failures (crashes or memory corruption). Simplest solution is
probably to only write to memory if !MODE_SEGMENT - thus providing
debug support only in 32bit mode (init and boot phases).
>
> void
> @@ -66,7 +80,7 @@ serial_debug_flush(void)
> if (!CONFIG_DEBUG_SERIAL)
> return;
> int timeout = DEBUG_TIMEOUT;
> - while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
> + while ((serial_inb(CONFIG_DEBUG_SERIAL_PORT, SEROFF_LSR) & 0x60) != 0x60)
> if (!timeout--)
> // Ran out of time.
> return;
> diff --git a/src/serial.c b/src/serial.c
> index 88349c8a9267..27710cb19af9 100644
> --- a/src/serial.c
> +++ b/src/serial.c
> @@ -21,7 +21,7 @@
> static u16
> detect_serial(u16 port, u8 timeout, u8 count)
> {
> - if (CONFIG_DEBUG_SERIAL && port == CONFIG_DEBUG_SERIAL_PORT
> + if (CONFIG_DEBUG_SERIAL && port == (u16) CONFIG_DEBUG_SERIAL_PORT
> && !romfile_loadint("etc/advertise-serial-debug-port", 1))
> return 0;
> outb(0x02, port+SEROFF_IER);
-Kevin
More information about the SeaBIOS
mailing list