This provides basic debug output on the Quark system, assuming that *something* (i.e. coreboot or UEFI) has set it up in advance for us.
Signed-off-by: David Woodhouse David.Woodhouse@intel.com --- I looked briefly at making this part of the CONFIG_DEBUG_SERIAL code, and making that generic enough to handle I/O access *or* MMIO access depending on what's present... but in fact that's probably overkill.
This isn't really limited to Quark; it would work with any 16550 device wired up as MMIO32. But we can expand it as required, I think. No point in starting off with the same functionality as the 5000-odd lines of the Linux kernel's 8250_pci.c.
What do I need to do if called in 32-bit segmented mode? I'm guessing that's not going to work right now...
src/Kconfig | 5 +++++ src/fw/csm.c | 2 ++ src/output.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+)
diff --git a/src/Kconfig b/src/Kconfig index a42ab2d..bdc2602 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -472,6 +472,11 @@ menu "Debugging"
Set to zero to disable debugging.
+ config DEBUG_QUARK_UART + depends on DEBUG_LEVEL != 0 + bool "Debug to Quark UART #1" + default n + config DEBUG_SERIAL depends on DEBUG_LEVEL != 0 bool "Serial port debugging" diff --git a/src/fw/csm.c b/src/fw/csm.c index dfb0d12..afd7ffe 100644 --- a/src/fw/csm.c +++ b/src/fw/csm.c @@ -280,6 +280,8 @@ handle_csm(struct bregs *regs) if (!CONFIG_CSM) return;
+ debug_serial_preinit(); + dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
pic_irqmask_write(PICMask); diff --git a/src/output.c b/src/output.c index b47625f..a90d350 100644 --- a/src/output.c +++ b/src/output.c @@ -17,6 +17,8 @@ #include "stacks.h" // call16_int #include "string.h" // memset #include "util.h" // ScreenAndDebug +#include "hw/pci_regs.h" // PCI_VENDOR_ID, PCI_BASE_ADDRESS_0 +#include "hw/pci.h" // pci_config_readl
struct putcinfo { void (*func)(struct putcinfo *info, char c); @@ -31,9 +33,59 @@ struct putcinfo {
u16 DebugOutputPort VARFSEG = 0x402;
+static volatile u32 *quark_uart_addr = 0; + +extern void _cfunc32flat_quark_uart_preinit(void); +extern void _cfunc32flat_quark_uart_putc(void); +extern void _cfunc32flat_quark_uart_flush(void); + +void quark_uart_preinit(void) +{ + // debug port is bus 0, device 0x14, function 5. + u16 uart_bdf = pci_to_bdf(0, 0x14, 5); + + // If it isn't a Quark UART... + if (pci_config_readl(uart_bdf, PCI_VENDOR_ID) != 0x09368086) + return; + + u32 bar0 = pci_config_readl(uart_bdf, PCI_BASE_ADDRESS_0); + if (!(bar0 & 0xf)) + quark_uart_addr = (void *)bar0; +} + +void quark_uart_putc(char c) +{ + if (!quark_uart_addr) + return; + + int timeout = DEBUG_TIMEOUT; + while ((quark_uart_addr[SEROFF_LSR] & 0x20) != 0x20) + if (!timeout--) + // Ran out of time. + return; + quark_uart_addr[SEROFF_DATA] = c; +} + +void quark_uart_flush(void) +{ + if (!quark_uart_addr) + return; + int timeout = DEBUG_TIMEOUT; + while ((quark_uart_addr[SEROFF_LSR] & 0x60) != 0x60) + if (!timeout--) + // Ran out of time. + return; +} + void debug_serial_preinit(void) { + if (CONFIG_DEBUG_QUARK_UART) { + if (MODE16) + call32(_cfunc32flat_quark_uart_preinit, 0, 0); + else + quark_uart_preinit(); + } if (!CONFIG_DEBUG_SERIAL) return; // setup for serial logging: 8N1 @@ -54,6 +106,12 @@ debug_serial_preinit(void) static void debug_serial(char c) { + if (CONFIG_DEBUG_QUARK_UART) { + if (MODE16) + call32(_cfunc32flat_quark_uart_putc, c, 0); + else + quark_uart_putc(c); + } if (!CONFIG_DEBUG_SERIAL) return; int timeout = DEBUG_TIMEOUT; @@ -68,6 +126,12 @@ debug_serial(char c) static void debug_serial_flush(void) { + if (CONFIG_DEBUG_QUARK_UART) { + if (MODE16) + call32(_cfunc32flat_quark_uart_flush, 0, 0); + else + quark_uart_flush(); + } if (!CONFIG_DEBUG_SERIAL) return; int timeout = DEBUG_TIMEOUT;
On Fri, Nov 29, 2013 at 02:02:02PM +0000, David Woodhouse wrote:
This provides basic debug output on the Quark system, assuming that *something* (i.e. coreboot or UEFI) has set it up in advance for us.
Signed-off-by: David Woodhouse David.Woodhouse@intel.com
I looked briefly at making this part of the CONFIG_DEBUG_SERIAL code, and making that generic enough to handle I/O access *or* MMIO access depending on what's present... but in fact that's probably overkill.
This isn't really limited to Quark; it would work with any 16550 device wired up as MMIO32. But we can expand it as required, I think. No point in starting off with the same functionality as the 5000-odd lines of the Linux kernel's 8250_pci.c.
What do I need to do if called in 32-bit segmented mode? I'm guessing that's not going to work right now...
Do you need debug output from 16bit mode or 32bit segmented mode? The post and boot phases are all 32bit code so typical boot time debugging shouldn't be impacted. Gerd's cbmem debugging code uses this approach.
Using call32() in 16bit mode is always risky because it trashes the "hidden" segment registers.
I think we need to move the low-level serial code out of output.c. I'll put together a patch that does that.
-Kevin
On Fri, 2013-11-29 at 11:40 -0500, Kevin O'Connor wrote:
On Fri, Nov 29, 2013 at 02:02:02PM +0000, David Woodhouse wrote:
This provides basic debug output on the Quark system, assuming that *something* (i.e. coreboot or UEFI) has set it up in advance for us.
Signed-off-by: David Woodhouse David.Woodhouse@intel.com
I looked briefly at making this part of the CONFIG_DEBUG_SERIAL code, and making that generic enough to handle I/O access *or* MMIO access depending on what's present... but in fact that's probably overkill.
This isn't really limited to Quark; it would work with any 16550 device wired up as MMIO32. But we can expand it as required, I think. No point in starting off with the same functionality as the 5000-odd lines of the Linux kernel's 8250_pci.c.
What do I need to do if called in 32-bit segmented mode? I'm guessing that's not going to work right now...
Do you need debug output from 16bit mode or 32bit segmented mode? The post and boot phases are all 32bit code so typical boot time debugging shouldn't be impacted. Gerd's cbmem debugging code uses this approach.
I can live with that. Perhaps I should make it work in 16-bit mode but *only* if the appropriate BAR has been put in a memory hole below 1MiB.
Now I've got the Quark running... has anyone ever looked at sdhci support... ? :)
On Fri, Nov 29, 2013 at 04:59:32PM +0000, David Woodhouse wrote:
On Fri, 2013-11-29 at 11:40 -0500, Kevin O'Connor wrote:
On Fri, Nov 29, 2013 at 02:02:02PM +0000, David Woodhouse wrote:
This provides basic debug output on the Quark system, assuming that *something* (i.e. coreboot or UEFI) has set it up in advance for us.
Signed-off-by: David Woodhouse David.Woodhouse@intel.com
I looked briefly at making this part of the CONFIG_DEBUG_SERIAL code, and making that generic enough to handle I/O access *or* MMIO access depending on what's present... but in fact that's probably overkill.
This isn't really limited to Quark; it would work with any 16550 device wired up as MMIO32. But we can expand it as required, I think. No point in starting off with the same functionality as the 5000-odd lines of the Linux kernel's 8250_pci.c.
What do I need to do if called in 32-bit segmented mode? I'm guessing that's not going to work right now...
Do you need debug output from 16bit mode or 32bit segmented mode? The post and boot phases are all 32bit code so typical boot time debugging shouldn't be impacted. Gerd's cbmem debugging code uses this approach.
I can live with that. Perhaps I should make it work in 16-bit mode but *only* if the appropriate BAR has been put in a memory hole below 1MiB.
That should be okay, but would it ever actually be mapped below 1Meg? Where would it be mapped to: 0xa0000-0xc0000?
BTW, how does this "Quark" support compare with the PCI Oxford serial code that Google has been maintaining? http://git.chromium.org/gitweb/?p=chromiumos/third_party/seabios.git;a=commi...
-Kevin
On Fri, 2013-11-29 at 12:44 -0500, Kevin O'Connor wrote:
That should be okay, but would it ever actually be mapped below 1Meg? Where would it be mapped to: 0xa0000-0xc0000?
Somewhere down there. Or 0xc0000 even. There's no video here.
BTW, how does this "Quark" support compare with the PCI Oxford serial code that Google has been maintaining? http://git.chromium.org/gitweb/?p=chromiumos/third_party/seabios.git;a=commi...
Hm, close.
Mine is mmio32 not mmio8. So IER is at 0x4 in the BAR, IIR at 0x8 etc. And I need to specify the PCI B/D/F because I really need to use the one at 0000:14:5 not the other port at 0000:14.1.
But those are easy enough to solve.
On Fri, 2013-11-29 at 12:44 -0500, Kevin O'Connor wrote:
Do you need debug output from 16bit mode or 32bit segmented mode? The post and boot phases are all 32bit code so typical boot time debugging shouldn't be impacted. Gerd's cbmem debugging code uses this approach.
I don't need debug output. But an INT 10h implementation like sgabios¹ would be really useful on Quark, because there's normally no real VGA output (unless you can connect mini-PCI one, which is what I've done so far).
However, I note that sgabios already talks about having support for SMM traps to talk to an EFI console, so perhaps that's the way forward. The SMM side can be provided either by UEFI in the CONFIG_CSM case, or by SeaBIOS itself when it's native. You've already been looking at something very similar to this anyway, right?
I can live with that. Perhaps I should make it work in 16-bit mode but *only* if the appropriate BAR has been put in a memory hole below 1MiB.
That should be okay, but would it ever actually be mapped below 1Meg? Where would it be mapped to: 0xa0000-0xc0000?
Hm, I suspect we *could* set up the A and B segments to map to MMIO space and then set the BAR for the appropriate UART to be there. But an sgabios implementation is going to need *memory* in the A segment, and play tricks to spot when the application/OS has written there and output the appropriate changes to the serial port. So I'm not sure it's stunningly useful to do so.
On Mon, May 19, 2014 at 02:27:38PM +0100, David Woodhouse wrote:
On Fri, 2013-11-29 at 12:44 -0500, Kevin O'Connor wrote:
Do you need debug output from 16bit mode or 32bit segmented mode? The post and boot phases are all 32bit code so typical boot time debugging shouldn't be impacted. Gerd's cbmem debugging code uses this approach.
I don't need debug output. But an INT 10h implementation like sgabios¹ would be really useful on Quark, because there's normally no real VGA output (unless you can connect mini-PCI one, which is what I've done so far).
Yes, a serial console using mmio serial ports would be a good reason to integrate sgabios functionality into seabios.
A couple of months back I looked through the sgabios assembler. It looks mostly straight-forward. The only thing that was marginally complex was its ability to keep a cache of background attributes.
However, I note that sgabios already talks about having support for SMM traps to talk to an EFI console, so perhaps that's the way forward.
I wasn't aware of that. Do you have a link?
The SMM side can be provided either by UEFI in the CONFIG_CSM case, or by SeaBIOS itself when it's native. You've already been looking at something very similar to this anyway, right?
Yes - I have a testing branch at: https://github.com/KevinOConnor/seabios/tree/testing-32bit-drivers
However, I don't know of a protocol for informing sgabios how to use a SeaBIOS SMM handler.
I can live with that. Perhaps I should make it work in 16-bit mode but *only* if the appropriate BAR has been put in a memory hole below 1MiB.
That should be okay, but would it ever actually be mapped below 1Meg? Where would it be mapped to: 0xa0000-0xc0000?
Hm, I suspect we *could* set up the A and B segments to map to MMIO space and then set the BAR for the appropriate UART to be there.
Maybe, but I'd guess it isn't worth it.
But an sgabios implementation is going to need *memory* in the A segment, and play tricks to spot when the application/OS has written there and output the appropriate changes to the serial port. So I'm not sure it's stunningly useful to do so.
sgabios doesn't do anything like that today. Most apps that anyone cares about (ie, modern bootloaders) are well behaving - they output their vga text using the int 10h bios interrupts. Sgabios hooks these interrupts to provide service.
In my tests, the only thing I've found which does direct text writes to the 0xa0000-0xc0000 framebuffer are really old dos programs. Even freedos uses the standard bios interface.
-Kevin
On Mon, 2014-05-19 at 11:20 -0400, Kevin O'Connor wrote:
On Mon, May 19, 2014 at 02:27:38PM +0100, David Woodhouse wrote:
On Fri, 2013-11-29 at 12:44 -0500, Kevin O'Connor wrote:
Do you need debug output from 16bit mode or 32bit segmented mode? The post and boot phases are all 32bit code so typical boot time debugging shouldn't be impacted. Gerd's cbmem debugging code uses this approach.
I don't need debug output. But an INT 10h implementation like sgabios¹ would be really useful on Quark, because there's normally no real VGA output (unless you can connect mini-PCI one, which is what I've done so far).
Yes, a serial console using mmio serial ports would be a good reason to integrate sgabios functionality into seabios.
A couple of months back I looked through the sgabios assembler. It looks mostly straight-forward. The only thing that was marginally complex was its ability to keep a cache of background attributes.
However, I note that sgabios already talks about having support for SMM traps to talk to an EFI console, so perhaps that's the way forward.
I wasn't aware of that. Do you have a link?
https://code.google.com/p/sgabios/source/browse/trunk/design.txt#219
"Optionally the serial port input/output can be replaced with a SMI trigger that calls into an EFI BIOS in order to tie into its own console input and output routines rather than directly hitting the serial port. In this particular case it's assumed that all logging is handled in the EFI module that will be called. BIOS int 15h, ax = 0d042h is used to trigger SMI. The parameters passed will need to be changed to be specific to the EFI or SMI handler put in place. In the example in SMBIOS, for output, ebx = 0xf00d0000 | (char << 8), and for input, ebx = 0xfeed0000, with the character, if any, returned in the eax register with ZF set and eax=0 if no character was available."
This appears to be a lie. There's nothing but a FIXME in the code (line 849 on the send_byte function).
But an sgabios implementation is going to need *memory* in the A segment, and play tricks to spot when the application/OS has written there and output the appropriate changes to the serial port. So I'm not sure it's stunningly useful to do so.
sgabios doesn't do anything like that today. Most apps that anyone cares about (ie, modern bootloaders) are well behaving - they output their vga text using the int 10h bios interrupts. Sgabios hooks these interrupts to provide service.
In my tests, the only thing I've found which does direct text writes to the 0xa0000-0xc0000 framebuffer are really old dos programs. Even freedos uses the standard bios interface.
Hm, OK. Again I got that from sgabios's design.txt:
Known Bugs ---------- With some versions of DOS, only the last character of every line is displayed once dos boots since DOS will use direct access to the VGA framebuffer until the end of line is reached, at which point it will start using int 10h. Dual cursor tracking might fix this issue by maintaining positions for dos that look like the end of line and another for internal use to know where to output next.
On Mon, May 19, 2014 at 05:56:02PM +0100, David Woodhouse wrote:
On Mon, 2014-05-19 at 11:20 -0400, Kevin O'Connor wrote:
On Mon, May 19, 2014 at 02:27:38PM +0100, David Woodhouse wrote: A couple of months back I looked through the sgabios assembler. It looks mostly straight-forward. The only thing that was marginally complex was its ability to keep a cache of background attributes.
However, I note that sgabios already talks about having support for SMM traps to talk to an EFI console, so perhaps that's the way forward.
I wasn't aware of that. Do you have a link?
https://code.google.com/p/sgabios/source/browse/trunk/design.txt#219
"Optionally the serial port input/output can be replaced with a SMI trigger that calls into an EFI BIOS in order to tie into its own console input and output routines rather than directly hitting the serial port. In this particular case it's assumed that all logging is handled in the EFI module that will be called. BIOS int 15h, ax = 0d042h is used to trigger SMI. The parameters passed will need to be changed to be specific to the EFI or SMI handler put in place. In the example in SMBIOS, for output, ebx = 0xf00d0000 | (char << 8), and for input, ebx = 0xfeed0000, with the character, if any, returned in the eax register with ZF set and eax=0 if no character was available."
I don't see any reference to "int 15h, ax=0xd042" as a standard. So, maybe the author of the above text also wrote their own EFI module which used that magic value?
sgabios doesn't do anything like that today. Most apps that anyone cares about (ie, modern bootloaders) are well behaving - they output their vga text using the int 10h bios interrupts. Sgabios hooks these interrupts to provide service.
In my tests, the only thing I've found which does direct text writes to the 0xa0000-0xc0000 framebuffer are really old dos programs. Even freedos uses the standard bios interface.
Hm, OK. Again I got that from sgabios's design.txt:
Known Bugs
With some versions of DOS [...]
With that predicate, I'm sure any conclusion is true.
Simple usages of freedos and msdos 6.22 appear to use the standard vgabios interface. (As a simple test case, I have seabios put the vga in graphics mode and then see what breaks - see below - most things still work.)
-Kevin
--- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -44,7 +44,7 @@ enable_vga_console(void)
/* Enable VGA text mode */ memset(&br, 0, sizeof(br)); - br.ax = 0x0003; + br.ax = 0x006a; call16_int10(&br);
// Write to screen.
On Mon, 2014-05-19 at 13:42 -0400, Kevin O'Connor wrote:
I don't see any reference to "int 15h, ax=0xd042" as a standard. So, maybe the author of the above text also wrote their own EFI module which used that magic value?
Well, the INT 15h call would still be on the BIOS side; that doesn't sound like an EFI thing at all. Perhaps that's a special-case hack to make their platform *trigger* the SMM entry, which then gets handled by the EFI code?
Known Bugs
With some versions of DOS [...]
With that predicate, I'm sure any conclusion is true.
True. I suppose the question is whether it's true of any versions of DOS that we *care* about. Or other operating systems that we might want to use on Quark, I suppose. Your response seems to suggest not.
I just didn't want to design myself into a corner where I'd *never* be able to fix this "known bug"?
On Mon, May 19, 2014 at 07:49:47PM +0100, David Woodhouse wrote:
True. I suppose the question is whether it's true of any versions of DOS that we *care* about. Or other operating systems that we might want to use on Quark, I suppose. Your response seems to suggest not.
My opinion on this is that if one wants to run old DOS programs then they really should be running them under QEMU.
When it comes to emulating the interfaces (eg, usb keyboard, video with coreboot native init, video over serial adapter) then in my opinion the goal is support for the bootloaders of more modern OSes - WinXP and later (ntldr), lilo, syslinux, and grub.
-Kevin
On Mon, May 19, 2014 at 07:49:47PM +0100, David Woodhouse wrote:
On Mon, 2014-05-19 at 13:42 -0400, Kevin O'Connor wrote:
I don't see any reference to "int 15h, ax=0xd042" as a standard. So, maybe the author of the above text also wrote their own EFI module which used that magic value?
Well, the INT 15h call would still be on the BIOS side; that doesn't sound like an EFI thing at all. Perhaps that's a special-case hack to make their platform *trigger* the SMM entry, which then gets handled by the EFI code?
FYI, I just stumbled upon this definition in the std/LegacyBios.h efi header file:
/// /// SMM_FUNCTION Function constants. ///@{ #define INT15_D042 0x0000 [...]
-Kevin
On Wed, 2014-05-28 at 15:36 -0400, Kevin O'Connor wrote:
On Mon, May 19, 2014 at 07:49:47PM +0100, David Woodhouse wrote:
On Mon, 2014-05-19 at 13:42 -0400, Kevin O'Connor wrote:
I don't see any reference to "int 15h, ax=0xd042" as a standard. So, maybe the author of the above text also wrote their own EFI module which used that magic value?
Well, the INT 15h call would still be on the BIOS side; that doesn't sound like an EFI thing at all. Perhaps that's a special-case hack to make their platform *trigger* the SMM entry, which then gets handled by the EFI code?
FYI, I just stumbled upon this definition in the std/LegacyBios.h efi header file:
/// /// SMM_FUNCTION Function constants. ///@{ #define INT15_D042 0x0000 [...]
-Kevin
I've been reading through the EDK2 SMM stuff, and invoking SMM functions from seems to involve putting parameters into a buffer at a certainly location, then triggering an SMI. On the EFI side there's obviously a function you can invoke to *do* it, but we could do it directly.
To make use of it from SeaBIOS-CSM, I think we'd just need to pass in the location of that buffer. There's space in the EFI_COMPATIBILITY16 table for "IBV-specific" information.
On Wed, 2014-05-28 at 15:36 -0400, Kevin O'Connor wrote:
On Mon, May 19, 2014 at 07:49:47PM +0100, David Woodhouse wrote:
On Mon, 2014-05-19 at 13:42 -0400, Kevin O'Connor wrote:
I don't see any reference to "int 15h, ax=0xd042" as a standard. So, maybe the author of the above text also wrote their own EFI module which used that magic value?
Well, the INT 15h call would still be on the BIOS side; that doesn't sound like an EFI thing at all. Perhaps that's a special-case hack to make their platform *trigger* the SMM entry, which then gets handled by the EFI code?
FYI, I just stumbled upon this definition in the std/LegacyBios.h efi header file:
/// /// SMM_FUNCTION Function constants. ///@{ #define INT15_D042 0x0000 [...]
Looks like it's for BIOS updates. See §8.4 of http://docs.com/Z1P8