The Architecture of Minimal Linux Live

Welcome to the wonderful world of Minimal Linux Live! :)

Minimal Linux Live (MLL) is a tiny educational Linux distribution, which is designed to be built from scratch by using a collection of automated shell scripts. Minimal Linux Live offers a core environment with just the Linux kernel, GNU C library, and Busybox userland utilities. Additional software can be included in the ISO image at build time by using a well-documented configuration file.

The generated ISO image file contains Linux kernel, GNU C library compiled with default options, Busybox compiled with default options, quite simple initramfs structure and some "overlay bundles" (the default build process provides few overlay bundles). You don't get Windows support out of the box, nor you get any fancy desktop environment. All you get is a simple shell console with default Busybox applets, network support via DHCP and... well, that's all. This is why it's called "minimal".

Note that by default Minimal Linux Live provides support for legacy BIOS systems. You can change the build configuration settings in the .config file and rebuild MLL with support for modern UEFI systems.

All build scripts are well organized and quite small in size. You can easily learn from the scripts, reverse engineer the build process and later modify them to include more stuff (I encourage you to do so). After you learn the basics, you will have all the necessary tools and skills to create your own fully functional Linux based operating system which you have built entirely from scratch.

Boot Process


BIOS

  1. The machine passes the execution control to the BIOS firmware.
  2. BIOS passes the execution control to the Syslinux boot loader, which is present in the MLL ISO image.
  3. The Syslinux boot loader has special configuration file syslinux.cfg which describes where the Linux kernel (kernel.xz) and the initramfs (rootfs.xz) files are located in the ISO image.
  4. Syslinux loads both the kernel and the initramfs files in the RAM and then passes the execution control to the kernel.
  5. The kernel detects the available hardware and loads the corresponding necessary drivers.
  6. The kernel unpacks the initramfs archive (already loaded in the RAM by Syslinux) and then passes the execution control to the initramfs.
  7. At this point the actual execution control is passed to the shell script file /init, which is present in the initramfs file.

Refer to the init section below for more details on how /init handles the OS preparation.

UEFI

  1. The machine passes the execution control to the UEFI firmware.
  2. UEFI detects properly configured EFI boot image that is present in the MLL ISO image.
  3. UEFI loads the EFI boot image from the MLL ISO image in the RAM.
  4. UEFI passes the execution control to the special EFI file EFI/BOOT/BOOTx64.EFI (for 64-bit machines) from the previously described EFI boot image. This special file is the entry point of the systemd-boot UEFI boot manager.
  5. The systemd-boot UEFI boot manager has special configuration files (loader.conf and all files in the entries/ folder) which describe where the Linux kernel (kernel.xz) and the initramfs (rootfs.xz) files are located in the EFI boot image.
  6. systemd-boot loads the kernel in the RAM.
  7. The kernel detects the available hardware and loads the corresponding necessary drivers.
  8. The kernel loads the initramfs file in the RAM. Refer to the kernel EFI stub documentation for more details.
  9. The kernel unpacks the initramfs archive (already loaded in the RAM by the kernel) and then passes the execution control to the initramfs.
  10. At this point the actual execution control is passed to the shell script file /init, which is present in the initramfs file.

Refer to the init section below for more details on how /init handles the OS preparation.

INIT

The /init shell script is responsible to prepare the actual OS environment and to present the user with functional shell prompt.

The base initramfs structure is located here:

https://github.com/ivandavidov/minimal/tree/master/src/minimal_rootfs

The actual /init script is located here:

https://github.com/ivandavidov/minimal/blob/master/src/minimal_rootfs/init

This is what happens when /init is executed:

  1. All core filesystems (i.e. /dev, /sys, /proc) are mounted.
  2. The overlay system is prepared. At this point the initramfs structure and the overlay bundles are merged.
  3. The execution control is passed to /sbin/init which is located in the initramfs.
  4. /sbin/init uses the special configuration file /etc/inittab which describes the system initialization actions.
  5. All autorun scripts are executed one by one.
  6. Welcome message is displayed and the user is presented with functional shell prompt.

MLL ISO Image Structure


The default build process generates a bootable ISO image file named minimal_linux_live.iso.

BIOS

When the property FIRMWARE_TYPE in the configuration file .config is set to bios, the generated ISO image has the following structure.

# FIRMWARE_TYPE=bios

minimal_linux_live.iso
├── boot/
│   ├── kernel.xz
│   ├── rootfs.xz
│   └── syslinux/
├── EFI/
└── minimal/

boot/

This folder contains all files that are necessary for the proper BIOS boot process. More precisely, you can find the Linux kernel, the initial RAM filesystem (initramfs) and the boot loader.

boot/kernel.xz

This is the Linux kernel. The kernel detects the available hardware, loads necessary drivers and then it passes the execution control to the initramfs.

boot/rootfs.xz

This is the initial RAM filesystem. The initramfs file is an archive, automatically unpacked by the kernel in the RAM. The actual execution control is passed to the shell script file /init, which must be present in the initramfs file.

boot/syslinux/

This folder contains the ISOLINUX boot loader (binaries and configuration files), part of the Syslinux project.

EFI/

This folder contains a simple .nsh script which allows MLL to boot on EFI based machines, provided that these machines support UEFI shell.

minimal/

This folder contains all MLL overlay bundles (i.e. additional software prepared during the build process).

UEFI

When the property FIRMWARE_TYPE in the configuration file .config is set to uefi, the generated ISO image has the following structure.

# FIRMWARE_TYPE=uefi

minimal_linux_live.iso
├── boot/
│   └── uefi.img
└── minimal/

boot/

This folder contains all files that are necessary for the proper UEFI boot process. More precisely, you can find the EFI boot image.

boot/uefi.img

This is the EFI boot image. It contains the systemd-boot UEFI boot manager, corresponding boot configurations, the Linux kernel and the initramfs.

minimal/

This folder contains all MLL overlay bundles (i.e. additional software prepared during the build process).

Initial workspace

These are the shell scripts and folders that you need in order to build Minimal Linux Live.

src/
├── .config
├── common.sh
├── 00_clean.sh
├── 01_get_kernel.sh
├── 02_build_kernel.sh
├── 03_get_glibc.sh
├── 04_build_glibc.sh
├── 05_prepare_sysroot.sh
├── 06_get_busybox.sh
├── 07_build_busybox.sh
├── 08_prepare_bundles.sh
├── 09_generate_rootfs.sh
├── 10_pack_rootfs.sh
├── 11_generate_overlay.sh
├── 12_get_syslinux.sh
├── 12_get_systemd-boot.sh
├── 13_prepare_iso.sh
├── 14_generate_iso.sh
├── 15_generate_image.sh
├── 16_cleanup.sh
├── minimal_boot/
├── minimal_config/
├── minimal_overlay/
└── minimal_rootfs/

Build Process

The MLL build process can be divided in several major phases. Refer to the common properties for more details on the folders that are referenced below.


Preparations

Everything from WORK_DIR is removed. All previous MLL build artifacts are lost and the MLL build process can start from scratch. The previously downloaded sources are preserved in order to speed up the process.

Kernel

Linux kernel source code is downloaded. OverlayFS and EFI stub are configured. Kernel is built and the kernel binary, along with the kernel header files are placed in KERNEL_INSTALLED.

GNU C Library

GNU C Library source code is downloaded. Build preparations are made in the GLIBC_OBJECTS. GLIBC is built and the final artifacts are placed in GLIBC_INSTALLED. The .so files, along with all GLIBC headers and all kernel headers are placed in SYSROOT.

Busybox

Busybox source code is downloaded. The build configuration is tweaked to reference SYSROOT. The final build artifacts are placed in BUSYBOX_INSTALLED.

Overlay bundles

All overlay bundles that have been enabled in .config are built. The final overlay structure is generated in OVERLAY_ROOTFS.

Initramfs

The installed Busybox artifacts and src/minimal_rootfs/ are merged in ROOTFS. The initramfs file WORK_DIR/rootfs.cpio.xz is generated from ROOTFS. The final initramfs ISO image structure for the overlay bundles is generated in ISOIMAGE_OVERLAY.

Boot loader

Syslinux and/or systemd-boot are downloaded.

ISO image

The boot loader for BIOS/UEFI is prepared and the boot configuration artifacts from src/minimal_boot/ are properly placed. The final ISO image layout structure is prepared in ISOIMAGE. This directory contains the BIOS/UEFI boot loader, Linux kernel and initramfs, along with all MLL overlay bundles (i.e. additional software and/or configurations) that have been enabled. The ISO image file src/minimal_linux_live.iso is generated. The MLL filesystem image (e.g. use in Docker) src/mll_image.tgz is generated. Final cleanup is performed.

Configuration File (src/.config)

Common Properties And Functions


The shell script file common.sh is sourced in all MLL scripts. It provides common properties and functions.

Properties

SRC_DIR

SRC_DIR=src/

This is the main source directory, i.e. the property references the main project directory src/.

CONFIG

CONFIG=src/.config

This is the main configuration file. The configuration properties are described here.

SOURCE_DIR

SOURCE_DIR=src/source/

This is the directory where all source archives are downloaded.

WORK_DIR

WORK_DIR=src/work/

This is the directory where all MLL artifacts are processed. All build actions happen in this directory.

KERNEL_INSTALLED

KERNEL_INSTALLED=src/work/kernel/kernel_installed/

This is the directory where the kernel and its corresponding header files are placed after the kernel build phase has been completed.

GLIBC_OBJECTS

GLIBC_OBJECTS=src/work/glibc/glibc_objects/

This is the directory where the GNU C Library is going to be built.

GLIBC_INSTALLED

GLIBC_INSTALLED=src/work/glibc/glibc_installed/

This is the directory where the GNU C Library shared objects (.so files) are placed after the build phase has been completed.

BUSYBOX_INSTALLED

BUSYBOX_INSTALLED=src/work/busybox/busybox_installed/

This is the directory where Busybox is placed after the build phase has been completed.

SYSROOT

SYSROOT=src/work/sysroot/

The system root folder for MLL. This folder contains GLIBC, and kernel header files. MLL uses the sysroot folder in order to properly link Busybox with the custom built kernel and GLIBC.

ROOTFS

ROOTFS=src/work/rootfs/

This folder contains the rootfs/initramfs structure which is generated by the core MLL build process.

OVERLAY_ROOTFS

OVERLAY_ROOTFS=src/work/overlay_rootfs/

This folder contains the rootfs/initramfs structure which is generated by the overlay subsystem build process.

ISOIMAGE

OVERLAY_ROOTFS=src/work/isoimage/

This folder contains the final ISO image structure.

ISOIMAGE_OVERLAY

OVERLAY_ROOTFS=src/work/isoimage_overlay/

This folder contains the final overlay subsystem ISO structure.

Functions

read_property(prop_name)

This function reads properties from the main .config file.

# Example

JOB_FACTOR=`read_property JOB_FACTOR`

download_source(url, file_to_save)

This function downloads the url resource and saves it as $file_to_save.

# Example
#
# This is the filesystem structure before the execution
# of the function.
#
# src/
# └── source/
#     └── (no files/folders)

download_source \
  'https://busybox.net/downloads/busybox-1.32.0.tar.bz2' \
  $SOURCE_DIR/busybox-1.32.0.tar.bz2
  
# This is the filesystem structure after the execution
# of the function.
#
# src/
# └── source/
#     └── busybox-1.32.0.tar.bz2

extract_source(archive_file, dest_dir)

This function extracts the archive archive_file in the directory src/work/$dest_dir/.

# Example
#
# This is the filesystem structure before the execution
# of the function.
#
# src/
# ├── source/
# │   └── busybox-1.32.0.tar.bz2
# └── work/
#     └── (no files/folders)

extract_source \
  $SOURCE_DIR/busybox-1.32.0.tar.bz2 \
  busybox
  
# This is the filesystem structure after the execution
# of the function.
#
# src/
# ├── source/
# │   └── busybox-1.32.0.tar.bz2
# └── work/
#     └── busybox
#         └── busybox-1.32.0/

Clean

Get kernel

Build kernel

Step 03 - Get GLIBC

Step 04 - Build GLIBC

Step 05 - Prepare Sysroot

Step 06 - Get Busybox

Step 07 - Build Busybox

Step 08 - Prepare Bundles

Step 09 - Generate Rootfs

Step 10 - Pack Rootfs

Step 11 - Generate Overlay

Step 12 - Get Syslinux

Step 12 - Get systemd-boot

Step 13 - Prepare ISO

Step 14 - Generate ISO

Step 15 - Generate Image

Step 16 - Final Cleanup