I've been considering a possible architectural change to SeaBIOS. Currently, SeaBIOS contains a mix of 16bit code and 32bit code. All of the initialization and bootup code is done in regular 32bit mode, but runtime code (the callbacks the OS uses) is generally run in 16bit mode. I have been thinking about possibly changing this so that hardware driver code runs exclusively in 32bit mode.
Specifically, this would involve running the disk controller code, the keyboard/mouse controller code, and all hardware interrupt handlers exclusively in 32bit mode. To support this, some BIOS calls would require SeaBIOS to transition from 16bit mode to 32bit mode in order to satisfy the request. This trampolining to 32bit mode at runtime is already done for the AHCI driver, the XHCI driver, and the pvscsi driver - as these devices can not function with only a 16bit driver.
Even with this proposed change, SeaBIOS would still continue to have 16bit code, though the remaining 16bit code would be almost exclusively for interface support and it would be noticeably smaller. In initial tests, the final 16bit code size drops from ~35K to ~16K.
The main benefit of this change is that it makes it easier to develop and enhance the SeaBIOS hardware driver code, it makes understanding the code simpler, and reduces the overall size of the SeaBIOS binary.
The biggest downside to this change would be problems running old DOS era programs that attempt to run the BIOS in vm86 mode. Specifically, the dos emm386 program is known to prevent 32 bit trampolines in SeaBIOS from working. (There's been a bit of experience with AHCI drivers running in 32bit mode (and now XHCI) so we have good confidence that modern OSes wont present a problem.) To continue to support these old DOS era programs I'm proposing we implement an SMI to help trampoline to 32bit mode. This can be done within SeaBIOS for QEMU TCG, but it would require work on kvm, coreboot, and ovmf to support it. (If we go down this path and these projects aren't extended to help trampoline to 32bit mode, then these projects would no longer be able to run these old DOS era programs with SeaBIOS.)
For testing purposes, I have put together a series of patches to run the SeaBIOS drivers in 32bit mode and to implement the QEMU TCG SMI helper. The code is in a very rough state, but it demonstrates the idea. It's available at:
https://github.com/KevinOConnor/seabios/tree/testing-32bit-drivers
Unfortunately, the QEMU TCG SMI doesn't seem to help in vm86 mode, but I believe it is due to the QEMU code not handling CPL changes properly in SMM mode. I still need to confirm this though.
In closing, this email is to start discussion on the proposal. This would not impact the next release of SeaBIOS.
Comments?
-Kevin
On Thu, 2014-04-24 at 22:02 -0400, Kevin O'Connor wrote:
I've been considering a possible architectural change to SeaBIOS. Currently, SeaBIOS contains a mix of 16bit code and 32bit code. All of the initialization and bootup code is done in regular 32bit mode, but runtime code (the callbacks the OS uses) is generally run in 16bit mode. I have been thinking about possibly changing this so that hardware driver code runs exclusively in 32bit mode.
...
The biggest downside to this change would be problems running old DOS era programs that attempt to run the BIOS in vm86 mode. Specifically, the dos emm386 program is known to prevent 32 bit trampolines in SeaBIOS from working. (There's been a bit of experience with AHCI drivers running in 32bit mode (and now XHCI) so we have good confidence that modern OSes wont present a problem.) To continue to support these old DOS era programs I'm proposing we implement an SMI to help trampoline to 32bit mode.
This sounds broadly similar to the approach taken by some CSM implementations. Instead of having native device drivers in the CSM and actually taking over the hardware as SeaBIOS does, they use SMI to trampoline back into UEFI-side code and use the drivers there.
If we're going to do this, it would be interesting to see if we can use the same protocol — both for thunking from 16-bit to 32-bit SeaBIOS code, and for thunking from the SeaBIOS CSM to OVMF/UEFI.
Using the native UEFI drivers via such a thunk would resolve a number of the issues around who owns the hardware, and how we continue with a UEFI boot after a 'Legacy' boot attempt has failed (to detect the 0x55aa signature on a boot sector, for example).
On Tue, May 13, 2014 at 03:27:30PM +0100, David Woodhouse wrote:
On Thu, 2014-04-24 at 22:02 -0400, Kevin O'Connor wrote:
I've been considering a possible architectural change to SeaBIOS. Currently, SeaBIOS contains a mix of 16bit code and 32bit code. All of the initialization and bootup code is done in regular 32bit mode, but runtime code (the callbacks the OS uses) is generally run in 16bit mode. I have been thinking about possibly changing this so that hardware driver code runs exclusively in 32bit mode.
...
The biggest downside to this change would be problems running old DOS era programs that attempt to run the BIOS in vm86 mode. Specifically, the dos emm386 program is known to prevent 32 bit trampolines in SeaBIOS from working. (There's been a bit of experience with AHCI drivers running in 32bit mode (and now XHCI) so we have good confidence that modern OSes wont present a problem.) To continue to support these old DOS era programs I'm proposing we implement an SMI to help trampoline to 32bit mode.
This sounds broadly similar to the approach taken by some CSM implementations. Instead of having native device drivers in the CSM and actually taking over the hardware as SeaBIOS does, they use SMI to trampoline back into UEFI-side code and use the drivers there.
If we're going to do this, it would be interesting to see if we can use the same protocol — both for thunking from 16-bit to 32-bit SeaBIOS code, and for thunking from the SeaBIOS CSM to OVMF/UEFI.
That is interesting. Do you have a link to code or a spec handy? (I looked through the "Compatibility Support Module Specification" again and I see it talks about SMMs, but it seems to say that what is implemented is "IBV" specific.)
I have some SMI code for QEMU TCG at: https://github.com/KevinOConnor/seabios/commit/11468b9faf80eae729e863eb949f4... it's raw, but the basic idea is to implement the same logic in stacks.c:call32() and romlayout.S:trampoline32() except by using an SMI instead of the normal method of entering protected mode. That is, the high level goal is to provide a function that can be called from SeaBIOS 16bit C code which can run a SeaBIOS 32bit C function.
Using the native UEFI drivers via such a thunk would resolve a number of the issues around who owns the hardware, and how we continue with a UEFI boot after a 'Legacy' boot attempt has failed (to detect the 0x55aa signature on a boot sector, for example).
One of my sub-goals with moving the drivers to 32bit mode is to make a more clear separation between all the legacy interface code and the hardware driver code. It sounds like such a separation would also help with what you describe above. That said, I'm skeptical lots more interaction with UEFI is a solution. :-)
-Kevin
On Tue, 2014-05-13 at 12:45 -0400, Kevin O'Connor wrote:
That is interesting. Do you have a link to code or a spec handy? (I looked through the "Compatibility Support Module Specification" again and I see it talks about SMMs, but it seems to say that what is implemented is "IBV" specific.)
Right. The CSM specification is fairly incomplete, and large parts of the details around how you enumerate boot targets and communicate that to the CSM are left to the implementer.
It's only on chasing up my questions about how it's supposed to work, that I ended up being told that we expect it all to happen with SMM and "native" UEFI drivers, and the CSM really having very little hardware-specific code at all.