02 - Bootstrapping Linux

Contents

Lecture Notes

Initial ramdisk & rootfs

When Linux tries to boot into User Space, it does so by starting the init (PID=1) process from several well-known locations (e..g: /usr/sbin/init, etc.) For this to happen, the kernel first needs to load a root filesystem. The location of this rootfs is specified as part of the kernel's command line arguments:

$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-linux root=/dev/mapper/volgrp0-lv_root rw loglevel=3 quiet

Notice in this example how the root variable is not /dev/sda or /dev/nvme0n1, but instead a Logical Volume (i.e.: an intermediate representational layer that abstracts the backing storage devices – see figure below.) Although the kernel has LVM support, the drivers are likely to be compiled as modules, to be loaded on demand when the user requires them, rather than increasing the size and complexity of the kernel with features that the majority of users do not need. This puts us in an awkward position where we need the LVM drivers to access the root partition but the modules are located on the very same root partition.

Figure 1: Abstraction of storage mediums under LVM.

The solution is to add an initial ramdisk: a disk image that is loaded in RAM at the same time as the kernel. The kernel will view this region in RAM as a storage device, without needing extensive driver support (e.g.: NET_FS). This minimal disk image should contain all kernel modules and tools required to gain access and mount the real rootfs. Once the initramfs is mounted at / and the real rootfs is mounted at another location (e.g.: /mnt/), the init process will use the pivot_root() system call to switch around the two mount points. As a result, the real rootfs will then be mounted at /, making the initramfs safe to unmount from /mnt/ and clear from RAM.

During ARM development, such ramdisks are often used for prototyping purposes. Once we ensure that the Linux kernel successfully boots to User Space, we may consider writing a partition table to the eMMC memory.

Flattened Device Trees

A Device Tree (DT) is a data structure that (normally) contains a hierarchical representation of the available hardware, but also runtime configuration information. The DT is always written in the Device Tree Source (DTS) format and looks something like this:

Heavily truncated DTS

Heavily truncated DTS

/dts-v1/;

/ {
    interrupt-parent = <0x01>;
    #address-cells = <0x02>;
    #size-cells = <0x02>;
    model = "TechNexion PICO-PI-8M";
    compatible = "technexion,pico-pi-imx8m", "fsl,imx8mq";

    cpus {
        #address-cells = <0x01>;
        #size-cells = <0x00>;

        cpu@0 {
            device_type = "cpu";
            compatible = "arm,cortex-a53";
            reg = <0x00>;
            clock-latency = <0xee6c>;
            clocks = <0x02 0x102>;
            enable-method = "psci";
        };
    };
        
    soc@0 {
        compatible = "fsl,imx8mq-soc", "simple-bus";
        #address-cells = <0x01>;
        #size-cells = <0x01>;
        ranges = <0x00 0x00 0x00 0x3e000000>;
        dma-ranges = <0x40000000 0x00 0x40000000 0xc0000000>;

        bus@30800000 {
	    compatible = "fsl,aips-bus", "simple-bus";
	    reg = <0x30800000 0x400000>;
	    #address-cells = <0x01>;
	    #size-cells = <0x01>;
	    ranges = <0x30800000 0x30800000 0x400000 0x8000000 0x8000000 0x10000000>;

	    serial@30890000 {
                compatible = "fsl,imx8mq-uart", "fsl,imx6q-uart";
                reg = <0x30890000 0x10000>;
                interrupts = <0x00 0x1b 0x04>;
                clocks = <0x02 0xcb 0x02 0xcb>;
                clock-names = "ipg\0per";
                dmas = <0x11 0x18 0x04 0x00 0x11 0x19 0x04 0x00>;
                dma-names = "rx\0tx";
	        status = "okay";
	    };
        };
    };
};


We notice that the DT is structured as multiple nested nodes. Each node can be referenced by a path comprised of the names of all of its ancestors. In fact, nodes that represent hardware devices are usually assigned an alias based on this path:

Node aliases

Node aliases

aliases {
    ethernet0 = "/soc@0/bus@30800000/ethernet@30be0000";
    gpio0     = "/soc@0/bus@30000000/gpio@30200000";
    mmc0      = "/soc@0/bus@30800000/mmc@30b40000";
    mmc1      = "/soc@0/bus@30800000/mmc@30b50000";
    serial0   = "/soc@0/bus@30800000/serial@30860000";
};

Each node is comprised of properties and other node. A property can be a:

  • String: device_type = “cpu”;
  • Boolean: regulator-boot-on;
    • Its presence means true.
  • Packed array of integers: reg = <0x30860000 0x10000>;

Additionally, there are special properties that start with a # symbol. These properties are used by the FDT parser as hints on how to interpret the packed array of integers. Normally, each element in the array is a uint32_t. However, certain properties (reg especially) usually contain one or more (address, size) tuples. In the example above, the reg property located in the serial@30890000 node informs the kernel that the serial (UART) device is mapped in memory starting at 0x30890000 has a size of 0x10000. Note that in this case we have one tuple where each element consists of precisely one uint32_t element. This may not always be the case! Hence, the following properties:

  • #address-cells: Number of uint32_t cells that comprise the address element in each tuple.
  • #size-cells: Number of uint32_t cells that comprise the size element in each tuple.

Knowing these values is the only way to determine the number of tuples in a packed array property. Note, however, that the #*-cells properties do not apply to the node where they are encountered, but only to its children. For example, if bus@30800000 overrides these properties (whose default value was inherited from soc@0), only the reg of serial@30890000 would adhere to these changes. The ranges property of bus@30800000 would still use the values inherited from soc@0.

ass/cursuri/02.txt · Last modified: 2023/07/24 13:49 by radu.mantu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0