Boot, ELF loading, and initial task

Some recent offline discussions have brought up a number of questions about how the boot process works, how we get from an external bootloader such as U-Boot to an initial task executing on seL4, and which components are involved and what their precise responsibilities are.

The current situation differs somewhat between architectures, ARM and RISC-V both boot via the intermediary elfloader which is responsible for booting multiple cores, unpacking the ELF for the kernel and the initial task into physical memory a small amount of information about the initial task and device tree (although the form this currently takes is fairly limited). For x86, the kernel boots directly from multiboot and the boot code within the kernel is responsible for ELF loading the initial task and initialising additional cores.

The interface between the kernel and whatever starts it is fairly limited and can make it difficult to start the kernel via something other than elfloader (such as a ROM-based firmware loader) without needing to maintain a fork of the kernel itself. The documentation for this process is also limited.

For static systems, where there is a static set of task ELF files that are loaded at system startup, this can also lead to both elfloader and the root task being responsible for loading ELF binaries into memory.

I’m personally a fan of the way that elfloader separates the concern of initializing physical memory from the kernel’s responsibility of creating the initial kernel objects and capabilities for the root task and think we could better generalize this. I think we should consider making the kernel’s boot responsibilities more consistent across architectures and better defined and documented.

Fundamentally, the only responsibility the kernel needs to have is to initialize its global and per-core internal state and to create the initial capabilities and kernel objects and set up the capability space and virtual address space for the initial task. Much of what occupies the initial state of the initial task could be passed through directly from the whatever initializes the kernel, all the kernel needs to be able to add is the information describing how the initial capability space is structured.

My question at this point is what should the responsibilities of each component in the boot chain actually be and what should the interfaces between them look like?

1 Like

As someone who works on highly dynamic systems, I think seL4 should ideally be part of the platform firmware. Otherwise, one needs to have various device drivers in the (trusted) bootloader, which does not seem to be a good idea. In particular, users of laptop and desktop computers expect to be able to boot from USB devices as well as various types of hard disks. Servers also need network boot abilities.

After some other discussions, I think it would make more sense for the kernel to be responsible for platform initialization. The kernel should be able to initialize the platform assuming little more than its location in memory and the existence and location of the root task ELF in memory. This would allow bootloaders such as U-Boot to boot the kernel but also for a minimal firmware to simply copy the images into memory and boot in a production system.