
In message 528646bc0701271419l8069e56nb06bb328cf85b8b7@mail.gmail.com you wrote:
Just for the moment; forget the term 'block device' and forget about the current implementation of u-boot. How significant are the
OK.
difference between the following devices? mmc, CF, IDE HD, SCSI HD, DataFlash, memmapped flash, NAND flash, i2c eeprom, USB storage. Here's my short list:
- different block sizes; DataFlash can be written byte at a time;
while other devices have minimum write sizes. Some devices need blocks to be specifically erased before rewriting.
- some devices can also only be read in blocks of a certain size
- some device can have sectors / blocks write protected, both logi- cally (in U-Boot), or in hardware; some of these devices come up write protected out of reset i. e. you have to unprotect these to make them writable.
- some devices may require (re-) write operations evey now and then to avoid data loss.
- some devices must never be wrtitten to when the board resets / loses power.
- some devices may be "banked"; right now, for example, we have no way to access flash devices on systems that need bank switching.
- memmapped flash can be be read directly on the memory bus; but
writing requires a special routine
- Large variation of size, from a few kbytes up to thousands of gigabytes.
- Some devices are typically partitioned for convenience
- speed differences
- large number of
of ???
The technology varies wildly, but they are all storage devices which store of an ordered sequence of bytes. In every device, the address of a single item of data can be boiled down to a single integer.
...assuming your "integer" type has enough bits to address any byte.
Take a look at the following interface. For *most* commands; how well does this is this api encapsulate those differences for common commands? Assume that device specific commands still exist for things that don't fit well into the model. ie. block erase and protect commands.
I don't doubt that you can come up with aninterface that fits more or less nicely on oll possible tyes of storage media. After all, a file is a file is a file, as we all have learnt - haven't we?
IN addition to your own fun inh designing nice interfaces, please also keep in minde the mental welfare of the normal end user, who thinks of "flash memory" as some simple thing where you can just read data from.
open(device) # Prepare for read/write operation seek(distance, abs_flag) # Relative or absolute seek read(buffer, count) write(buffer, count) close() # Operation finished; sync any pending buffers back to disk.
Please keep in mind that this is a boot loader, not an OS. One im- portant point is, and always has been, to keep the memory footprint small. I often sacrificed beautiful code for an uglier, but much smaller implementation. And I guess I will (have to) do this again.
Notes:
- assume device can only be opened once. ie. it's a bug to call open() twice
Why?
- this could be used by commands like mm, md, bootm, etc. I'm not
trying to design a full control interface (protect, erase, etc).
Why not? I'm not willing to see such functions dropped.
- common commands would typically call open(), seek(),
read/write(), read/write(), ..., close() before returning to user. ie. device would *not* be left open after command completes.
Sounds like a lot of code to implement (code size) and run (execution times).
- should be suitable for partition access too
- read/write commands are expected to transparently handle block
boundaries. ie. if one byte is written to the middle of a block; the write hook should read the block, modify the byte, and keep it buffered until it either a read/write/seek() moves to another sector, or close() is called.
- and yes, I'm just using the each device as a file perspective.
It's a well established abstraction, so why not here too?
Well, just to name one of the potential issues: U-Boot is designed to make porting to new hardware as eassy as possible. So we want to have serial console output as soon as possible. That means that very, very early in the boot process you will have to read the environment to read environment variables like "baudrate" and some others. In this stage, we usually don't have a regular stack, we have no BSS, and we have no writable data segment. In other words, we don't have a regular C environment, only a very primitve subset. But *all* your new code would have to be able to run in this environment. Or we would need duplicate implementations which is even worse than what we have today. If you want, you can even go one step further and think about NAND booting, where you have even more severe size restrictions (for which we don't have a good solution yet).
I don't want to say it's impossible what you usggest, but I have to admit that I cannot see a way to implement this without redefining the basics of the project.
Thoughts? Feel free to tell me if I'm flying too high in the stratosphere on this one.
I can't read your altimeter from here, but it seems you did take off (i. e. lose ground ;-)
Best regards,
Wolfgang Denk