SeaBIOS is now booting multiple operating systems on real hardware (including WinXP, WinVista, Linux, Freedos, etc.). I think it is time to start looking at the next steps for SeaBIOS.
USB support is a feature that SeaBIOS must have in order to be competitive with an "off the shelf" bios. I've spent some time investigating how this could be added. This email is to gather feedback from the coreboot developers and to see if there is an approach that makes sense.
A legacy bios typically has two main USB features - usb mass storage handling and usb keyboard/mouse handling. The former is needed to support booting from flash drives, external hard drives, and usb cdroms. The latter is needed because some users only have a usb keyboard - indeed, many machines no longer have PS/2 ports.
Both of the above require usb code that runs in 16bit mode. This certainly complicates the usb support - there are several open source projects that implement usb, but I'm not aware of any with this requirement. Since SeaBIOS is compiled with gcc a lot of the issues with 16bit mode wont be a problem; however, the memory restrictions of 16bit mode can't be ignored.
Some info on the usb requirements:
Mass storage requirements: The usb drive support looks to be straight forward. There is a document describing the minimum commands a bios can expect to have from a drive capable of booting the machine (search usb_msc_boot_1.0.pdf). It would seem that the 16bit code need only support sending BulkOut packets and receiving BulkIn packets. Interrupt support would not be needed, as the bios can poll for completion of requests.
Keyboard/mouse requirements: Thankfully, full HID support is not needed as the USB spec includes a "boot" mode for keyboard and mice. The limited features of "boot" mode is sufficient for our purposes. The 16bit code would need to be able to send Control packets and receive InterruptIn packets. It looks like it will be necessary to have a USB interrupt handler - the 16bit code will need to catch an interrupt, extract the kbd/mouse data, and then ack the irq.
I think it would be possible to add the above USB support to SeaBIOS. The initialization phase of SeaBIOS (aka "post") runs in 32bit mode today. The usb setup, bus scan, and hub detection can all be done during this post phase. All the dma setup, device initialization, and endpoint connections can also be done. It should then be possible to arrange for a handful of "transfer descriptors" to be setup in memory below 1MiB for all the requests that could be needed when in 16bit mode. The 16bit mode code would then only need to know how to fill out a "transfer descriptor" to communicate with the usb devices.
This would require that SeaBIOS add support for uhci and ohci controllers. (Support for ehci would also be possible, but it would only speed up mass storage support - it is probably not worth the complexity.) It would also be necessary to setup irqs on the usb controller. In particular, this means coreboot will need to populate PCI_INTERRUPT_LINE and make sure that the pci devices are available in PIC mode.
This type of support would limit the ability for the BIOS to support "plug and play" with devices. Only devices found during "post" would be available after post, and any device found during post but subsequently removed would no longer be available. However, the primary target for SeaBIOS is support for OS loaders (eg, lilo/grub/ntldr), and I don't think supporting plug-and-play during the small time window from bios post to OS load is critical.
Finally, this style of support would not emulate a keyboard/mouse for software that uses direct PS/2 io port accesses (0x60/0x64). However, I have confirmed that none of lilo, grub, nor the windows boot loader directly access these ports. (Indeed, even freedos calls the bios to read the keyboard/mouse.)
An alternative to the above plan would be to implement an SMI handler for USB support. I read somewhere that "off the shelf" bios frequently do this. Using an SMI handler would allow the usb code to all be 32bit, and it would allow full emulation of PS/2 keyboard/mouse accesses (ioport 0x60/0x64).
However, there are some disadvantages to using an SMI handler: SMI appears to be board specific to setup, SMI has a "bad rap" among many developers, it may not be easy to share an SMI handler with vendor code and bios usb code, and it might be difficult to coordinate kbd/mouse and disk accesses if only part is done with SMI.
One nice tool that already has USB support (uhci) is libpayload. Unfortunately, libpayload seems to be targeted for standalone "applications" and it doesn't seem to fit SeaBIOS' model. Because SeaBIOS needs to support 16bit callbacks it has more stringent requirements then a typical bootloader does. (An example of this in libpayload is the malloc call - malloc doesn't make sense in seabios because there are distinct areas that one can grab memory from (high memory, ebda, f segment, option rom area, etc.). The parameters to malloc aren't descriptive enough to convey these requirements.)
One way forward would be to introduce these complications to libpayload and then use libpayload in seabios. Another option would be to introduce separate usb support in seabios.
Well - that was a long email - thanks for reading. Any thoughts?
-Kevin