On Thu, Aug 9, 2012 at 11:23 AM, Brendan Conoboy blc@redhat.com wrote:
On 08/08/2012 08:37 PM, Matt Sealey wrote:
uEnv.txt and boot.scr aren't the same thing. uEnv.txt is the U-Boot environment usually on a fat partition. boot.scr is loaded by a readily loaded environment... You either predefined your environment and boot from it or you're using values from that environment. I wouldn't use uEnv.txt to replace a boot.scr on any system..
I don't think that is entirely accurate- uboots such as those for OMAP rely on uEnv.txt for everything. Sure, you can daisy-chain load a boot.scr, but why do so when uEnv.txt can perform both functions?
Seperation.
Apologies if I re-hash any part of the conversation I missed, but this is my understanding of what is required and what the current situation is;
uEnv.txt or the SPI NOR or MMC raw blocks or the default environment in U-Boot encoded at compile-time then run-time is the thing that should define the absolute fixed definitions of the board. This is, after all, the environment you want every time you boot. The reason it's a text file on OMAP is because on OMAP all they have is a FAT partition and it's less intrusive to read that file of that filename out from the disk. It is not to make life for distros more convenient by negating the need to write boot scripts; especially since every other ARM, PPC, MIPS, et al architecture might actually need the boot script. Why differentiate? uEnv.txt needs to be there to load a DIFFERENT environment, but there's also one compiled into U-Boot anyway. 99% of the time they're identical. If you need to dynamically change the booted environment from the default, you can; for instance to fix some errata that makes booting not work, or write a register or modify the way the thing boots without modifying the U-Boot compile, but on OMAP.. you have access to the binary anyway, it's in the same FAT partition :)
Since uEnv.txt isn't there on all boards, nor required, you could just do away with uEnv.txt completely, and trust the one compiled into U-Boot which would be standardized anyway, and just trust the boot.scr process to do any changes you need to make. That way all the boards boot one way; U-Boot comes with a standardized environment compiled in, and boot.scr is the thing it loads to further the boot process in a distribution-specific way.
boot.scr, as above, is the part that is distribution-specific. It needs to load from a certain device, the one U-Boot found it on or was directed to boot from. In environments where there is only one boot method (for instance, a single SD card slot) bootcmd may just be a loop through several valid filesystems, culminating in some environment being set (temporarily, please never saveenv in boot.scr!) which allows boot.scr to know
a) how to load other files from that media where it can be applied to common argument list for another command b) what to load and where to load it
e.g.
setenv loadcmd "${fs}load ${device} ${unit}:${part}" ${loadcmd} ${address_to_load_to} ${filename_to_load}
The address to load to is probably properly defined in the environment, but if it's not this is a good reason to redefine uEnv.txt. In the case of a fixed memory start and size, the memory map is defined in U-Boot but could be done in the script just as well since the distro will know what location to boot from. In the case of a dynamic memory start (MX6 does this, it can be 0x10000000 or 0x80000000) or size (with SO-DIMM for example) the script should not be playing with this value, so it makes sense not to define this in the script, but to use a standard set of environment variables to define these addresses, and importantly define these SEPERATELY from the U-Boot standard ${loadaddr} which means a very specific thing and has very specific actions - it is the DEFAULT address to load to, if you for example say "mmc dev 0; mmc part 1; fatload uImage" it will fill in the blanks for missing device, unit, partition from the currently selected entities, and use ${loadaddr} to put the file. This is NOT ALWAYS the place you want your kernel! The example is a good reason to define ${loadcmd} with specific device, unit and partition entries too since otherwise the device unit and partition is basically undefined, random and/or dependent on user fiddling before running "run bootcmd" if they paused the autoboot process.
So what you'd need are basically an address defined ${kerneladdr}, ${ramdiskaddr}, ${dtbaddr} or so which are the arguments for common bootm or bootz. These need to be set to safe places in the memory map and these should be hardcoded into U-Boot or provided in a known-to-be-safe uEnv.txt. The names aren't important, but they're the places these things are *to be loaded to* and they SHOULD be the same as the addresses *to be relocated to* in the event they do not match the configuration. In this sense, what should really happen is people quit using bootm to source uImage files, and just use zImage and raw ramdisks. Or fix U-Boot to take a perfectly invalid "load address" or "entry point" in a uImage header to mean "don't relocate me", or define a flag in the uImage format that says "do not relocate this under any circumstances". U-Boot has no idea about what it's doing to the file in regards to ANY other file you're loading into memory, nor the constraints around the addresses you want those files at, so relocation can give non-deterministic behavior, and it also involves memory copies which slow down boot. U-Boot and Distro would need to "cooperate" on their use of addresses passed to mkimage to reduce this if possible. Distro SHOULD also endeavour to not compress any uImage since in the vast majority of cases, the kernel is pre-compressed (gzip, lzo, bzip, xz, whatever) and decompresses itself. -C none should be the default in mkimage for distros. Ramdisks are almost always compressed, and the kernel will either decompress it fully (gzipped cpio archive or so) on it's own terms or do it on the fly (squashfs or so). Either way it has much better compression options than U-Boot can support (gzip, and that's it). So -C none makes no sense here anyway unless you are architecturally bound to gzip, and it would also force a kind of relocation (decompression to another location than the load address) which is therefore both redundant and somewhat non-deterministic too. Compressing boot.scr files only makes sense if your script is absolutely massive, otherwise most of them check out at about 900 bytes maximum (the biggest we've ever made was still less than a memory page) - saving yourself 30% on 4KiB isn't going to save you from any noticable disk access. At the end of the day though as long as U-Boot is safe within itself in terms of decompressing the script (i.e. if it does it (and it does currently) from top of memory and you define your addresses in the low part) "source" will run it fine and this decompression is quite safe. The Distro should determine whether compressing a boot.scr is a good idea. Device trees... also not a lot of point but it COULD happen, but where it decompresses to MUST be 16-byte (or is it 16KiB?) aligned or __vet_atags will NULL the pointer. It could also be decompressed to a place the kernel can't reach or overwrites at random (during decompression of kernel image). It's safer not to.
And that's it.. other operating systems should either write custom boot.scr scripts with custom addresses OR re-use kernel, ramdisk, dtb addr variables for it's own use (or for cleanliness, copy dtbaddr to a well-named one and use that as the third argument to bootm or bootz, assuming of course that it follows the Linux kernel entry convention) or if it is a wonderfully smart or integrated operating system, just kerneladdr or loadaddr and it can find the rest of the system on it's own or from it's filesystem or so (Solaris used to do this, Windows does this, MacOS does this).
The one thing I have never been able to resolve writing bootloaders is what the memory map should be. Usually what I end up with is, a place to put the boot script (lets call this scriptaddr), a place for device tree, place for kernel, place for ramdisk - in that order, in the low memory map. We usually need to keep 0x100 upwards to a reasonable amount of memory for legacy ATAGs for the board. So the first address (where the boot script is loaded to) is usually 32KiB into the memory map. We add 32KiB and put the dtb there. We add 64KiB (can a device tree really get that big?) and then the kernel goes there. Add 16MiB and put the ramdisk there. The ramdisk is a pretty arbitrarily sized thing, putting it before the kernel means you end up with "I cant' load ramdisks bigger than n MiB" problems which we've experienced before. It would be unheard of for a COMPRESSED Linux kernel to be more than 16MiB though. I find it hard to believe you could have one uncompressed amassing that amount of code, either (with all the modules and the kernel image I think my linux-virtual image on VMWare is about 32MiB added together, though. That's with EVERY module Ubuntu tries to do, and would assume they are linked into the kernel to be bigger than 16MiB. Unless Ubuntu want to do static, super-monolithic kernels, it will never happen IMO...). Your ramdisk is then just bounded by the limits of the kernel, if I'm putting my kernel at 64KiB and have 16MiB space for it, and my ramdisk loads there.. automatic zrel address location requires the kernel entry point to be less than 128MiB into the memory map but I think this is before decompression (right?) so it's just got to not overwrite the U-Boot stack (probably around 16MiB at the top of memory including all the binaries, segments, malloc space and stack). If it's done after decompression my ramdisk is limited to 128MiB-16MiB-64KiB-SizeOfDecompressedKernel so it can actually be inside that 128MiB. I'll have to look into that again... but who's going to make a 100MiB ramdisk anyway, boot from SD card and NOT use the SD card filesystem? It seems to rare to care about.
that can perform all bootup initialization is preferable- no need to regenerate boot.scr, which is sometimes not practical (EG, you're creating installations on a system without mkimage, or you're half-booted and in emergency recovery shell and your initramfs didn't include mkimage).
Why would you be creating installations on a system without mkimage? How would you prep your kernel?
I think what you're really talking about here is a way for U-Boot to load a boot.scr file that isn't encoded inside a uImage header, all it needs to know at this point though is the length of the file so that "source" knows where it can stop parsing (otherwise it will run the risk of not having a null terminator and it running into otherwise unprotected but unwise to access memory).
Like I said, the way we do it on the Efika MX is that the U-Boot environment (old U-Boot, stored in NOR; new U-Boot, built-in to U-Boot and not changeable) defines the bootcmd string and that's it. That's all U-Boot knows as standard apart from loadaddr. There is no bootmmc, booteth, bootsata, or other env to "run," and it does not really need them. If you start coding those you have to take into account the configurability, for instance bootmmc would need variables in the environment to know which device and partition to use, the filename, the load addresses for each component shouldn't be hardcoded into the bootmmc variable. What could be quite simple standardizing the environment for these variables implies and infers more environment variables, some unique to some systems and some common, but definitely not ALL common and standardizable.
As I understand this, the discussion is just talking about how to make life easier on Linux distributions so they don't have to know about non-standard U-Boot messes, but this just isn't possible. flash-kernel on Debian worked fine and could be JUST more modular but, no offense Loic, making it data driven is what is driving this discussion as a whole. What should have been less work is now a cross-distro discussion of why it doesn't really meet real life. What would make flash-kernel cleaner is if everyone updated their U-Boot.. which is unlikely. If Linaro have their U-Boot work then they can engineer them all to boot the same way. We already did this at Genesi, we took a hint from the Marvell Dove code that was embedded into flash-kernel and embedded it into our U-Boot so that we didn't have to restrict everyone to putting boot.scr on a single device (since U-Boot is capable of scripting looking for it). So Marvell Dove can do it too, if it worked from boot.scr it will work from bootcmd. OMAP, the same way. MX6Q SabreLite, we were disappointed that it went halfway and then bailed and then called the script "6q_bootscript". We fixed that internally here, now it boots from microSD, SD, SATA in that order without changing any "boot option registers" or flashing anything to SPI NOR (although we will have to eventually, the way the i.MX series works means all we need is a USB cable to load our own U-Boot from any old system with a USB port. Thanks Troy, Eric for imx_usb_loader so we don't need Windows anymore :)
What we should do is not pick around talking but collect all the relevant environments and boot.scr implementations and find the common points. But I guarantee they all have at least one boot source soldered to the board that is user-accessible (SD card, SATA drive, USB port), where they have two it will be easy to dynamically search for the right file in the right place, and if we fixate on the Linaro SD card format (partition 1 == for U-Boot on OMAP or other devices, partition 2 == /boot, partition 3 == /) and copy this for every expected-to-be-bootable-device for the distro, that's the kind of standardization we can achieve. The distro just needs the above, and the ability to write a boot.scr, and we might want to fix U-Boot-Linaro to be able to load a plaintext boot script instead of encoding it with mkimage, and to ignore relocation with uImages anyway at certain flags or impossible values (0xffffffff for example, since this would nearly always be the top of the memory map if not far beyond the end of RAM, except on 64-bit, but we'll get to that later), right?