[U-Boot] Unified u-boot feature set for simpler distro support

Stephen Warren swarren at wwwdotorg.org
Mon Aug 5 20:39:03 CEST 2013


On 08/03/2013 01:11 AM, Dennis Gilmore wrote:
> Hi all,
> 
> I wanted to start a discussion on defining a unified feature set that
> makes it simpler for the different distros to support ARM systems using
> u-boot. I have based a lot of my thoughts on how calxeda ship their
> systems configured as it works fairly well, recently i sent in a patch
> implementing most of what I would like to see for the wandboard[1]
> 
> right or wrong we want things to be simple for the user and to largely
> look like a linux system on x86 would. The user and distro should never
> need to worry about memory locations 

I agree. I'd certainly like to see various distros have regular
"PC-style" installers for Tegra boards.

I have attempted to write the "bootcmd" in upstream U-Boot for Tegra
devices in a way that helps this. More on that below.

> so this would mean similar partitioning. i.e. /boot on ext4 root and
> swap  on lvm or as raw partitions. people should be able to have
> just / on ext4 also. Down the road xfs /boot support would be a nice to
> have.

That's only partially relevant for U-Boot. Two things U-Boot needs to
support:

* Filesystem read for whatever filesystem /boot is part of (it could
very well be the / filesystem too, but U-Boot doesn't care, except for /
vs. /boot in path names). This is a matter of adding the right flags to
each board's U-Boot config file.

* Some way of determining which partition it should load things from.

For this point, I'd suggest MBR's bootable flag, or GPT's similar flags.
I always intended to implement a sub-command of U-Boot's "part" command
that read the partition flags and picked the correct partition to use
based on those flags...

The rest of the stuff (swap, LVM, ...) seems entirely related to the
distro itself and/or whatever gets put into the initrd.

> bootz and raw initrd support. not having to wrap kernels and initrds
> really is a must. raw initrd support means that its much simpler for a
> user to rebuild an initramfs if needed and bootz means we do not need
> to worry about making sure that we specify the correct addresses to
> load the kernel to when calling mkimage.

+1 from me.

> when it comes to memory addressing a distro and user shouldn't need to
> know anything. Ideally u-boot will auto allocate addresses based on the
> size of loaded objects. starting with a base address internal to u-boot
> you load a kernel, when loading an initramfs u-boot automatically
> calculates an address that ensures it does not overlap with the kernel.
> same for a fdt if loaded. I say auto calculated because what we think
> today will be enough room may not be tomorrow, dynamically calculating
> gives the flexibility for whatever may come.

The way I've approached this for Tegra is to have the default
environment define certain standard environment variables that U-Boot
scripts can use, without a care. For example, the kernel should be
loaded at ${kernel_addr_r}, initrd at ${ramdisk_addr_r}, DTB at
${fdt_addr_r}, etc.

I chose the values of those variables in the Tegra environment to
support reasonable max sizes. The kernel itself has a max size based on
practicality and the ARM ISA and jump range. There's no reason the
compressed kernel should be larger than the uncompressed kernel, etc.

> fdt will be automatically loaded and provided fedora ships dtbs
> in /boot/dtb-<kernelver>/ I am not sure where other distros provide
> them, however u-boot should automatically load dtb and provide access
> to a fdt in a ${fdt_addr} variable that can be used by pxe_cmd but still
> allows the user to specify their own in extlinux.conf if desired.
> ideally the devicetree files need to be decoupled from the kernel,
> along the lines of what is being discussed in the kernel now[2].
> Distros should agree on a single location for the dtbs to be
> placed. /boot/dtb/ or /boot/dtbs/ are probably good locations. u-boot
> can then look in the path with and without /boot

The model I chose on Tegra is slightly different.

For credit, I was heavily inspired by the default bootcmd from
downstream TrimSlice U-Boot and I think also the upstream Calxeda U-Boot.

Tegra's U-Boot searches all known boot devices for /boot/boot.scr (and
some other filenames), sets up some variables to record where it was
found, loads the file into RAM, and treats that as a U-Boot script. The
boot script then determines everything else that happens at boot;
loading the kernel/initrd/DTB, and booting it.

This lets boot.scr control e.g.:

* Whether the distro wraps zImage into a uImage or not, since the
distro-supplied script determines whether bootz or bootm is executed.

* Whether the distro has an initrd or not (I currently don't use one
typically).

* The filename of the initrd and DTB, since the location/name/... of
these is probably somewhat distro-specific.

* Whatever extra kernel command-line parameters the distro cares to pass
to the kernel, without having to add them to the U-Boot environment, but
rather just to boot.scr, which is a much more accessible file in a
regular file-system.

In other words, I've tried to define a "boot interface" between U-Boot
and the distro (which is to simply load/execute boot.scr, and provide
some data to boot.scr in environment variables), rather than making
U-Boot have complete knowledge of how to boot the distro.

Also, I have set up all boards so that they define standard U-Boot
environment variables ${soc}, ${board} that define which HW the code is
running on. This can be used to automatically construct the DTB
filename, and hence makes boot.scr pretty much HW-agnostic.

An example boot.scr that I use is shown below, with some extra comments
for the purposes of this email:

==========
# I anticipate replacing this hard-coded assignment with e.g.:
# part find-bootable ${devtype} ${devnum} rootpart
setenv rootpart 1

# Find partition UUID (not fs UUID) at run-time, so script adapts to
# whatever is there without regenerating it
part uuid ${devtype} ${devnum}:${rootpart} uuid

# Here is the use of ${uuid} from aboe
# bootargs_extra allows the user to interrupt boot and add to the
# kernel command-line
setenv bootargs ... root=PARTUUID=${uuid} ${bootargs_extra}

# You could load a "uEnv.txt" here too, which could set some variables
# that e.g. get added to bootargs etc., if you want plain-text disk-
# based configuration of this boot script.

# Complete generic...
load ${devtype} ${devnum}:${rootpart} ${kernel_addr_r} /boot/zImage

load ${devtype} ${devnum}:${rootpart} ${ramdisk_addr_r} /boot/initrd.gz
# So that we don't need to regenerate script when initrd size changes
ramdisk=${ramdisk_addr_r}:0x${filesize}
# :-(
setenv initrd_high 0xffffffff

load ${devtype} ${devnum}:${rootpart} ${fdt_addr_r} \
	/boot/${soc}-${board}.dtb

bootz ${kernel_addr_r} ${ramdisk} ${fdt_addr_r}
==========

For specifics in the code, see the definition of
CONFIG_EXTRA_ENV_SETTINGS in U-Boot's
include/configs/tegra-common-post.h, and work backwards from there.

Note that I'm also in the process of pushing a project to github that
creates a few boot.scr that fit into this model. I've written the code,
and hope to have IP approval to upload it very soon. Aside from the
example above, it also supports netboot, initrd being optional,
hard-coding various extra stuff into bootargs, etc.

You can also see some hard-coded boot scripts that I hope to get added
to the Ubuntu installer image generator at:

https://code.launchpad.net/~srwarren/debian-installer/tegra/+merge/175967

(I'd love to have similar support added to other distros; I just had to
pick one to work on first)

> What this gets us in the end is that with a unified kernel, device tree
> and u-boot implementing the system specific knowledge, supporting new
> ARM systems is along the same lines as supporting new x86 systems. Get
> the drivers and platform support in the mainline kernel and as long as
> the Distro enables it it will just work in the next OS release. The one
> part then that we as Distro's need to do is to ensure we install
> u-boot into the disk correctly for the board in question if it is a
> system that does not ship with some kind of storage for u-boot. If it
> is a system with NOR, Nand, SPI storage for u-boot it is then entirely
> in the vendors hand, and assuming that they implement everything, all
> distros will be able to simply support them. Giving users and vendors
> more choice in what to run on their hardware.

At least for Tegra, the U-Boot binary won't (ever?) be part of the
file-system, but is rather always somewhere dedicated (eMMC boot sectors
rather than the main user area, SPI, or NAND for example). As such, the
model I'd like to push for Tegra is that you use HW-specific tools to
install U-Boot, then use a distro installer SD card, USB device, or even
CD-/DVD-ROM image to install the distro, and that the distro doesn't
have to know anything at all about the bootloader, except to install a
hopefully entirely HW-agnostic boot.scr that I detailed above.

I know that some other SoCs store U-Boot etc. on
storage-partitions/filesystems instead. Perhaps distros should always
assume that the "U-Boot partition" is sacred, and just large enough for
the firmware, and put all their files on other partitions. The only
difference between Tegra and OMAP then would be an extra partition, and
hence the distro's / or /boot would be either partition 1 or 2:

Tegra:
Boot flash: U-Boot
storage partition 1: /       (boot.scr, DTB, zImage, etc.)

(p1 marked bootable)

OMAP:
storage partition 1: U-Boot
storage partition 2: /       (boot.scr, DTB, zImage, etc.)

(p2 marked bootable)

> I may not be entirely clear here and there may be things I am missing,
> I feel it is a good place to start the discussion.

I like where I think you're going!



More information about the U-Boot mailing list