On Thursday, March 13, 2014 04:29:06 PM David Hendricks wrote:
On Tue, Mar 11, 2014 at 7:55 AM, Naman Govil namangov@gmail.com wrote:
Hi!
Hi!
Hi!
a generic interface for accessing block devices on ARM SoCs so that coreboot could launch its stages from the block devices (an MMC for example).
Seems interesting, but I am a little bit worried that the project is too narrow. We updated CBFS about a year ago to allow CBFS content to come from any media. This was required for the earlier ARM-based platforms which use SPI ROM since the content was not memory mapped as it is on x86 platforms. It should be reasonably easy to follow that model using MMC as a backing media.
The problem is not that CBFS is not easily extendable to incorporate MMC; that's a 100 liner [1]. The problem is creating yet another API for accessing stuff, besides which we'll add an MTD and NAND API, etc. etc. etc. This would make us EFI-ish.
IIRC Alexandru ran into issues with adapting the A10's MMC driver from u-boot to coreboot and making it fit into the bootblock, which was constrained by the amount of SRAM available on the A10. I am worried that you will end up fighting implementation-specific problems on the platform you choose instead of doing more interesting infrastructure work.
I'm glad you brought that up. I ran into several problems, most of which were a result of CBFS's x86-centric design rather than the shortage of SRAM. A lot of CBFS callers love to generate map() calls, which means we as the backend need to provide the cache where to map that. When I get a map() call to map 20+ KiB of romstage into an area of SRAM I must provide, which must not overlap the final destination of romstage, I am wasting SRAM. If I only got a call to read(), with the destination being the resting place of romstage, that would eliminate the SRAM pressure a bit.
My first solution was to make the CBFS cache and the romstage destination overlap. That needed a trivial change in CBFS, but that patch dropped the soap for various reasons. The alternate_cbfs implementation for that was also clumsy and difficult to read.
Another problem I almost had was caused by problem #1. Since I needed a ton of RAM for the CBFS cache, I had to initialize RAM in the bootblock. Adding that code almost caused overgrowing the maximum bootblock size. I was getting close to the 24KiB limit with the MMC driver in there as well. I moved a bunch of non-essential stuff to romstage, and optimized the code layout a bit to not compile big bloat in bootblock. If I nuke the MMC debug messages, the bootblock goes under 13KiB, with MMC and raminit. Seems like there's also room for an MTD/NAND driver.
So, I hope I killed any worries about "fighting implementation-specific problems on the platform", which brings me back to the awkward design of CBFS. If we go the way of separate API for every possible bootblock media, you can have a Kconfig to select which to boot from.
If, on the other hand, you have a well designed, unified block dev API, you can select your block device based on some some heuristic to decide which media to boot from. Make it a GPIO.
Why is this better? You don't need two implementations of alternate_cbfs, which are extra code size, extra code, and generally look ugly and complicate the code.
I hope I convinced both of you that this is not an easy, trivial problem, and will take a big chunk of GSoC time, as well as tons of dedication to get done right. The purpose is not to hack something together to boot. I already did that in my github branch [2]. The purpose is to Do It Right (TM).
Naman, that means that if you pull this off, you'll need to be completely involved with the community for the twelve or so weeks of coding. You'll need to have patches up on gerrit early, take feedback, and involve in lots of discussion about the design. You will often be rewriting patches in the afternoon, in order to conform to the new design ideologies you discussed in the morning. You will repeat this process many times. You'll have to get intimate with the coding standards and ideologies of coreboot. I suggest you demonstrate a profound understanding of the foundation of our coding standards in your application, by correctly formatting any example code included therein. Your goal must be to have your work merged in coreboot master, and your board booting from MMC/SD with that code, by the pencils down date.
Alex
[1] https://github.com/mrnuke/coreboot/blob/369998920685852246dcae4c3e88b268c1c9... [2] https://github.com/mrnuke/coreboot/commits/cubie_mmc
On Thu, Mar 13, 2014 at 10:15 PM, mrnuke mr.nuke.me@gmail.com wrote:
On Thursday, March 13, 2014 04:29:06 PM David Hendricks wrote:
On Tue, Mar 11, 2014 at 7:55 AM, Naman Govil namangov@gmail.com wrote:
Hi!
Hi!
Hi!
a generic interface for accessing block devices on ARM SoCs so that coreboot could launch its stages from the block devices (an MMC for example).
Seems interesting, but I am a little bit worried that the project is too narrow. We updated CBFS about a year ago to allow CBFS content to come from any media. This was required for the earlier ARM-based platforms which use SPI ROM since the content was not memory mapped as it is on x86 platforms. It should be reasonably easy to follow that model using MMC as a backing media.
The problem is not that CBFS is not easily extendable to incorporate MMC; that's a 100 liner [1]. The problem is creating yet another API for accessing stuff, besides which we'll add an MTD and NAND API, etc. etc. etc. This would make us EFI-ish.
IIRC Alexandru ran into issues with adapting the A10's MMC driver from u-boot to coreboot and making it fit into the bootblock, which was constrained by the amount of SRAM available on the A10. I am worried that you will end up fighting implementation-specific problems on the platform you choose instead of doing more interesting infrastructure work.
I'm glad you brought that up. I ran into several problems, most of which were a result of CBFS's x86-centric design rather than the shortage of SRAM. A lot of CBFS callers love to generate map() calls, which means we as the backend need to provide the cache where to map that. When I get a map() call to map 20+ KiB of romstage into an area of SRAM I must provide, which must not overlap the final destination of romstage, I am wasting SRAM. If I only got a call to read(), with the destination being the resting place of romstage, that would eliminate the SRAM pressure a bit.
CBFS is definitely not friendly to environments that can't map() the storage area of the CBFS itself. Beyond that in-storage format with metadata tightly coupled to the data itself leads to needing to stream large amounts of data through the working set just to locate the piece that is desired.
On top of that the CBFS API doesn't allow for freeing up of used resources. Yes, there is the construct of map() and unmap(), but the used API in the code base returns pointers from map() and that means there is no way to free up the internal cache. However, read() doesn't solve the map() problem. read() and map() both need memory so in a constrained environment w/o memory-mapped access to the CBFS storage.
Lastly, the big reason for large map() requests is because we don't have a pipelined lzma path. For the non-lzma files read() will work exactly as you described.
My first solution was to make the CBFS cache and the romstage destination overlap. That needed a trivial change in CBFS, but that patch dropped the soap for various reasons. The alternate_cbfs implementation for that was also clumsy and difficult to read.
Another problem I almost had was caused by problem #1. Since I needed a ton of RAM for the CBFS cache, I had to initialize RAM in the bootblock. Adding that code almost caused overgrowing the maximum bootblock size. I was getting close to the 24KiB limit with the MMC driver in there as well. I moved a bunch of non-essential stuff to romstage, and optimized the code layout a bit to not compile big bloat in bootblock. If I nuke the MMC debug messages, the bootblock goes under 13KiB, with MMC and raminit. Seems like there's also room for an MTD/NAND driver.
I noticed in your code [1] you just read in all of the CBFS in-core. Or did I misread that? And your init_default_cbfs_media() always re-initializes and reads the CBFS again? I take it that function only gets called once? Most likely because that is the bootblock.
So, I hope I killed any worries about "fighting implementation-specific problems on the platform", which brings me back to the awkward design of CBFS. If we go the way of separate API for every possible bootblock media, you can have a Kconfig to select which to boot from.
If, on the other hand, you have a well designed, unified block dev API, you can select your block device based on some some heuristic to decide which media to boot from. Make it a GPIO.
Why is this better? You don't need two implementations of alternate_cbfs, which are extra code size, extra code, and generally look ugly and complicate the code.
I hope I convinced both of you that this is not an easy, trivial problem, and will take a big chunk of GSoC time, as well as tons of dedication to get done right. The purpose is not to hack something together to boot. I already did that in my github branch [2]. The purpose is to Do It Right (TM).
Naman, that means that if you pull this off, you'll need to be completely involved with the community for the twelve or so weeks of coding. You'll need to have patches up on gerrit early, take feedback, and involve in lots of discussion about the design. You will often be rewriting patches in the afternoon, in order to conform to the new design ideologies you discussed in the morning. You will repeat this process many times. You'll have to get intimate with the coding standards and ideologies of coreboot. I suggest you demonstrate a profound understanding of the foundation of our coding standards in your application, by correctly formatting any example code included therein. Your goal must be to have your work merged in coreboot master, and your board booting from MMC/SD with that code, by the pencils down date.
Alex
[1] https://github.com/mrnuke/coreboot/blob/369998920685852246dcae4c3e88b268c1c9... [2] https://github.com/mrnuke/coreboot/commits/cubie_mmc
-- coreboot mailing list: coreboot@coreboot.org http://www.coreboot.org/mailman/listinfo/coreboot
Am Donnerstag, den 13.03.2014, 22:15 -0500 schrieb mrnuke:
I'm glad you brought that up. I ran into several problems, most of which were a result of CBFS's x86-centric design rather than the shortage of SRAM. A lot of CBFS callers love to generate map() calls, which means we as the backend
Those map() calls are relatively new. I blame architecture astronauts from outer Mountain View ;-)
Patrick
We've been kind of holding off on this, but, fact is, coreboot has followed the well trod path of firmware everywhere and become a small kernel. It started as little more than memcpy with a frisson of I2C packet IO thown in, but thanks to the generous ideas of hardware designers everywhere, with ever-increasing needs for block IO devices, little on-chip packet networks, and so forth, here we are: YAFOS (Yet Another Firmware OS).
LinuxBIOS/coreboot was intentionally not designed to be a kernel or become a kernel, and the strain is starting to show as we find ourselves needing to be more of what a kernel is. Alex points out that "The problem is creating yet another API for accessing stuff, besides which we'll add an MTD and NAND API, etc. etc. etc. This would make us EFI-ish."
I've been feeling the same way. Adding specific APIs for specific device types is very old school design (and I mean REALLY old school, like OSes from the 60s). That was always a major objection I had to EFI -- it looked like the guys who designed it had never heard of Unix.
There's not much point in fighting the tide here. The idea of linux-as-bios was nice, but we have come to the point where linux-as-bios requires a small firmware kernel just to load it.
I think we need to step back from the small problems just a bit (i.e. generic block device interface) and think about generic device interfaces. It's doable: see Unix. We don't have as broad a range of devices as Unix had to contend with (no paper tape). And we've got tons of different examples to draw from.
But should this device abstraction be a driver or a device? And, in this new world, would the driver/device distinction in coreboot disappear?
ron