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