Hi,
There has been suggestions recently on using parts of libpayload in seabios. The following is my thoughts on some challenges of such an integration:
Constrained memory - unlike a normal libpayload app, SeaBIOS must reserve all memory that it uses during runtime in the e820 map. This reserved memory then can't be used by the OS. Naturally, this means reserved memory needs to be kept to a minimum - it would be a shame to keep any sizable amount of memory unusable by the OS just so that it can be used for the 5 seconds or so before the OS starts. I'd say all code and ram used by SeaBIOS runtime shouldn't exceed 256KB. Right now, SeaBIOS is using around 80K.
Also, code needed from 16bit mode must be located in the first 1Meg of ram. The constraints on memory here are even stricter - I'd say all code and ram here shouldn't exceed 100K.
As a result of these restrictions, SeaBIOS code uses different memory "zones" (6 of them) and purposely allocates ram from the different zones to optimize the memory footprint. (For example, an allocation needed only during init wouldn't be reserved in the e820, an allocation needed during runtime but not from 16bit code would be in e820 high-mem, and only those allocations needed during 16bit run-time would go into the e820 low-mem.)
Support for 16bit mode - SeaBIOS is fundamentally a 16bit bios implementation and that means supporting 16bit callers. Because SeaBIOS uses gcc, this isn't as difficult as it may seem, but it does require implementation restrictions. All code needs to be compiled by the seabios build (to manipulate the assembler and set compiler flags); it's not possible to just link in a library. Also, special macro wrappers must be placed in the code around all non-stack memory accesses.
Because of these memory restrictions, seabios tends to pass parameters by value (so as to avoid lots of macro accesses). Seabios also tends to avoid function pointers (is the pointer to the 16bit version of the function or to the 32bit version of the function?).
Finally, available stack space in 16bit mode is severely constrained. A hw irq handler probably shouldn't use more than 100 bytes of stack. A regular 16bit handler probably shouldn't use more than 250 bytes of stack.
Seabios must work without coreboot - seabios can be used natively with qemu, bochs, and kvm. This isn't necessarily a problem for pulling in a libpayload driver, but it does constrain other parts of libpayload. (For example, it's not possible to assume a coreboot table will be found).
Parts of libpayload tend to assume other parts of libpayload are available - this can be difficult for "cherry picking" drivers. For example, usb requires malloc, in/out, printf, mdelay, pci_config_write, etc. These can be redirected, but that's troublesome for maintenance because the different implementations may have subtly different behavior. Alternatively, one could try to introduce more parts of libpayload into seabios, but that further expands the scope of conflicts. For example, should the libpayload version of malloc know how to do e820 map allocations?
On the flip side, the clear advantage of using libpayload in seabios is a reduction of the overall code that needs to be maintained. It could also lead to better test coverage of the code and a higher quality.
In general, I think this raises a high-level question. Is there a desire to introduce the memory and operating constraints into the libpayload code that SeaBIOS will need? This is a bit of a difficult question, as the other users (eg, filo) have no need to worry about these restrictions and it will definitely make maintenance and testing harder.
My general feel has been that this isn't worth the cost. The amount of code being duplicated I would estimate is around 3000 lines. This is unarguably very tricky code (eg, hw init, timing, malloc), but there is not an overwhelming amount of it.
Thoughts? -Kevin
If libpayload can't fit seabios' needs then it needs to change so that it can. It's not much of a library if seabios can't use it IMHO. This may boil down to making the build process more flexible. I don't know.
I wonder how much of the low 1M we should just take for our purposes. 1M is a tiny amount of memory, and there are already options for reserving the low 64k for "BIOSen" in the newer kernels, as well as scans for low memory corruption. Should we just mark all of low 1M as reserved and use it as needed?
ron
ron minnich wrote:
If libpayload can't fit seabios' needs then it needs to change so that it can.
Not so fast.
It's not much of a library if seabios can't use it IMHO.
I disagree. libpayload is not optimized for a BIOS environment, and I think that's a really good thing. But it does mean it's not a great fit for SeaBIOS.
If libpayload becomes tailored to a single user, it's not much of a library either.
This may boil down to making the build process more flexible. I don't know.
That can be a good thing, but I don't know how helpful it is.
For memory allocation, maybe a variation on malloc in libpayload could take a malloc context struct parameter which describes where the area is located and has some callback hooks for when allocations change so that a memory map can be updated if needed.
In the common case there will only be one malloc context. In SeaBIOS Kevin said there are six. In FILO the area resize hooks are NULL and never called, in SeaBIOS they can update the memory map.
Because SeaBIOS is a little special (nice way of saying partly 16bit) it has special requirements. I think it would be very nice to reuse source from libpayload, as well as open up the libpayload build process if neccessary, if it is possible.
But I agree with Kevin that it needs to be worthwhile to actually go and make changes both in SeaBIOS and in libpayload.
I also agree with Kevin that it doesn't really look like it is..
//Peter