Everything between power on and your component

This document aims to detail, at a high-level, everything that happens between machine power on and software components running on the system.

Outline:

Kernel

The process for loading the Fuchsia kernel (zircon) onto the system varies by platform. At a high level the kernel is stored in the ZBI, which holds everything needed to bootstrap Fuchsia.

Once the kernel (zircon) is running on the system its main objective is to start userspace, where processes can be run. Since zircon is like a microkernel, it doesn't have to do a whole lot in this stage (especially compared to Linux). The executable for the first user process is baked into the kernel, which the kernel copies into a new process and starts. This program is called userboot.

Initial processes

Userboot is carefully constructed to be easy for the kernel to start, because otherwise the kernel would have to implement a lot of process bootstrap functionality (like a library loader service) that would never be used after the first process has been started.

Userboot’s job is really straightforward, to find and start the next process. The kernel gives userboot a handle to the ZBI, inside of which is the bootfs image. Userboot reads through the ZBI to find the bootfs image, decompresses it if necessary, and copies it to a fresh vmo. The bootfs image contains a read-only filesystem, which userboot then accesses to find an executable and its libraries. With these it starts the next process, which is component manager.

Userboot may exit at this point, unless the userboot.shutdown option was given on the kernel command line.

Component manager, the next process, is dynamically linked by userboot. This makes it a better home than userboot for early boot complex logic, as it can use libraries. Because of this component manager runs various FIDL services for its children, the most notable of which for boot purposes is bootfs, a FIDL-based filesystem backed by the bootfs image that userboot decompressed. It also finishes parsing the ZBI and decommits unnecessary pages, and uses the extracted information to host item, item factory, and argument services.

Component manager marks its process as critical, which means that if something goes wrong and it crashes, the job that it is in is killed. As it runs in the root job which has the special property that if it is killed the kernel force restarts the system, component manager crashing will cause a reboot.

Component manager

Component manager is the program that drives the component framework. This framework controls how and when programs are run and which capabilities these programs can access from other programs. A program run by this framework is referred to as a component.

The components that component manager runs are organized into a tree. There is a root component, and it has two children named bootstrap and core. Bootstrap's children are the parts of the system needed to get the system functional enough to run more complex software like appmgr.

The root, bootstrap, and core components are non-executable components, which means that they have no program running on the system that corresponds to them. They exists solely for organizational purposes.

A diagram showing that fshost and driver manager, are children of thebootstrap component, appmgr is a child of the core component, and core andbootstrap are children of the root component

Initial system components

Background

There are two important components under bootstrap, fshost and driver manager. These two components work together to bring up a functional enough system for appmgr, which then starts up all the user-facing software.

driver manager

Driver manager is the component responsible for finding hardware, running drivers to service the hardware, and exposing a handle for devfs to Fuchsia.

Drivers are run by driver hosts, which are child processes that driver manager starts. Each driver is a dynamic library stored in either bootfs or a package, and when a driver is to be run it is dynamically linked into a driver host and then executed.

The drivers stored in packages aren't available when driver manager starts, as those are stored on disk and drivers must be running before block devices for filesystems can appear. Before the filesystems are loaded, only drivers in the Zircon Boot Image (ZBI) can be loaded and run. The Driver Index is a component that knows where all of the drivers live in the system. The Driver Index will let Driver Manager know when base packages have finished loading and it has found base drivers.

fshost

Fshost is a component responsible for finding block devices, starting filesystem processes to service these block devices, and providing handles for these filesystems to the rest of Fuchsia. To accomplish this, fshost attempts to access the /dev handle in its namespace. This capability is provided by driver manager.

As fshost finds block devices, it reads headers from each device to detect the filesystem type. It will initially find the [Fuchsia Volume Manager][glossary.fuchsia-volume-manager] (fvm) block, which points to partitions for other block devices. Fshost will use devfs to cause driver manager to run the fvm driver for this block device, which causes other block devices to appear for fshost to inspect. It does a similar thing when it discovers a zxcrypt partition, as the disk will need to be decrypted to be usable. Once fvm and zxcrypt are loaded, fshost will find the appropriate block devices and start the minfs and blobfs filesystems, which are needed for a fully functioning system.

appmgr

Appmgr runs the legacy component framework. Appmgr is stored in a package, unlike fshost and driver manager, which are stored in bootfs, so component manager uses the /pkgfs handle from fshost to load appmgr.

Appmgr coordinates with component manager to share capabilities between legacy components and the rest of the system. Component manager forwards external capabilities to the sys realm in appmgr, and services managed by sysmgr can be exposed outside the sys realm.

Startup sequence

Component manager generally starts components lazily on-demand in response to something accessing a capability provided by the component. Components may also be marked as “eager”, which causes the component to start at the same point its parent starts.

In order to get the system running, appmgr is marked as an eager component. Since appmgr is stored in a package this causes component manager to attempt to load appmgr, and thus access the /pkgfs handle from fshost, causing fshost to be started.

Once running, fshost attempts to access the /dev handle from driver manager, which causes driver manager to start. Together they bring up drivers and filesystems, eventually culminating in pkgfs running. At this point fshost starts responding to requests on the /pkgfs handle, and component manager finishes loading appmgr and starts it.

A sequence diagram showing that appmgr loading begins due to it being an eagercomponent, fshost starting due to the /pkgfs handle, driver manager starting dueto the /dev handle, block devices appearing, filesystems appearing, and thenappmgr successfully starting.

Boot complete

At this point, the system is ready to launch additional components through FIDL protocols and services, or by directly launching them with services provided by appmgr.