[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