5. Root File System (rootfs)

5.1. Overview of Root File System

The kernel is the core of the Linux operating system and the file system is the main tool for communication between the user and the operating system. So to use Linux, it is important to understand the file system principles first.

The root file system structure is a tree directory structure starting with “/” as the “root”, and a device (ex: eMMC) is mounted on the root directory when the kernel program image (uImage) is booted. The root file system is usually stored in internal memory (DRAM) or non-volatile memory (FLASH), or in a file system accessible via the network (NFS). All applications and libraries are placed in the file system according to categories, and the following diagram shows the root file system directory structure.

/     Root directory
├── bin Executable file
├── dev Device file
├── etc System configuration file (ex: startup file)
├── home User Directory
├── init Script executed at boot
├── kdump Kernel debugging directory
├── lib Libraries include glibc, shared library and kernel modules
├── mnt Mount points for temporary file systems
├── proc Virtual file system for kernel and process information
├── sbin System managed executable file
├── sys System device and file hierarchy, providing kernel data
├── usr This directory contains user-defined applications and files
└── var Store system logs and service program files

5.2. Rootfs

This section describes how the file system is composed, and the detailed path is in ramdisk/rootfs/

5.2.1. Pre-build Rootfs Structure

The structure of the file system is divided into three main types of directories, which are iterated over Rootfs layer by layer, and are described below:

  • Basic rootfs:

At this stage, we provide pre-build rootfs files based on the following four types of Arch

Arch

Libc

Pre-build ramdisk path

Arm

glibc

ramdisk/rootfs/common_arm/

Arm

uclibc

ramdisk/rootfs/common_uclibc/

Aarch64

glibc

ramdisk/rootfs/common_arm64/

Riscv64

glibc

ramdisk/rootfs/common_riscv64/

Riscv64

musl

ramdisk/rootfs/common_musl64/

  • Processor configuration rootfs:

We place all Processorset dependent boot settings in ramdisk/rootfs/overlay/$CHIP

  • Third-party rootfs:

We place all third-party software compiled library, utility, and related file in

ramdisk/rootfs/public/

_images/RootFi002.png

It can be decided by means of a menu which Third-party software should be placed in Rootfs

$ menuconfig
_images/image18.png _images/image19.png

5.2.2. Compile the rootfs from buildroot

This section is an example of how to generate the rootfs from buildroot and run it on EVB. If the pre-build rootfs described in the previous section is used, this section can be ignored.

  1. Get buildroot repository

https://github.com/sophgo/buildroot-2021.05

  1. Configure buildroot

$ cd buildroot-2021.05

$ make menuconfig
_images/image21.png
  1. Set Arch Info & Toolchain & Packages

There are some default configuration files in the configs directory, which can be quickly configured by running make cvitek_XXX_defconfig

Set the architecture

ARM

_images/image22.png

RISCV

_images/image23.png

Set the Toochain

ARM

_images/image24.png

RISCV

_images/image25.png

Set the software package

_images/image26.png
  1. Compile the buildroot package

$ make
  1. Obtain the rootfs, which is located in output/images/rootfs.tar

  2. Modify build/Makefile so that SDK can use rootfs generated by buildroot

buildroot-prepare:$(OUTPUT_DIR)/rootfs
  $(call print_target)
  #clean_all
  rm -rf $(ROOTFS_DIR)/*
  #extract buildroot roofs
  tar xf $(BR_DIR)/output/images/rootfs.tar -C $(ROOTFS_DIR)
rootfs-pack:export CROSS_COMPILE_KERNEL=$(patsubst "%",%,$(CONFIG_CROSS_COMPILE_KERNEL))
rootfs-pack:export CROSS_COMPILE_SDK=$(patsubst "%",%,$(CONFIG_CROSS_COMPILE_SDK))
rootfs-pack:$(OUTPUT_DIR)/rawimages
#rootfs-pack:rootfs-prepare
rootfs-pack:buildroot-prepare
rootfs-pack:
  $(call print_target)
  ${Q}printf '\033[1;36;40m  Striping rootfs \033[0m\n'
ifeq (${FLASH_SIZE_SHRINK},y)
  ${Q}printf 'remove unneeded files'
  ${Q} $(COMMON_TOOLS_PATH)/spinand_tool/clean_rootfs.sh $(ROOTFS_DIR)
endif
  ${Q}find $(ROOTFS_DIR) -name "*.ko" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL)strip --strip-unneeded {} \;
  ${Q}find $(ROOTFS_DIR) -name "*.so*" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL)strip --strip-all {} \;
  ${Q}find $(ROOTFS_DIR) -executable -type f ! -name "*.sh" ! -path "*etc*" ! -path "*.ko" -printf 'striping %p\n' -exec $(CROSS_COMPILE_SDK)strip --strip-all {} 2>/dev/null \;
  1. Generate the new ROOTFS burnable image files

$ pack_rootfs
  1. Burn to the board by the steps mentioned in Chapter 3

5.2.3. Package rootfs as a Burnable Image File

Package the rootfs folder from the previous steps with the mksquashfs tool, compress it with XZ, and the end product is rootfs.spinor / rootfs.spinand / rootfs.emmc, which can be burned to Flash.

Refer to the rootfs-pack in build/Makefile for details:

rootfs-pack:export CROSS_COMPILE_KERNEL=$(patsubst "%",%,$(CONFIG_CROSS_COMPILE_KERNEL))
rootfs-pack:export CROSS_COMPILE_SDK=$(patsubst "%",%,$(CONFIG_CROSS_COMPILE_SDK))
rootfs-pack:$(OUTPUT_DIR)/rawimages
rootfs-pack:rootfs-prepare
rootfs-pack:
    $(call print_target)
    ${Q}printf '\033[1;36;40m  Striping rootfs \033[0m\n'
ifeq (${FLASH_SIZE_SHRINK},y)
    ${Q}printf 'remove unneeded files'
    ${Q} $(COMMON_TOOLS_PATH)/spinand_tool/clean_rootfs.sh $(ROOTFS_DIR)
endif
    ${Q}find $(ROOTFS_DIR) -name "*.ko" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL)strip --strip-unneeded {} \;
    ${Q}find $(ROOTFS_DIR) -name "*.so*" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL)strip --strip-all {} \;
    ${Q}find $(ROOTFS_DIR) -executable -type f ! -name "*.sh" ! -path "*etc*" ! -path "*.ko" -printf 'striping %p\n' -exec $(CROSS_COMPILE_SDK)strip --strip-all {} 2>/dev/null \;
ifeq ($(STORAGE_TYPE),spinor)
    ${Q}mksquashfs $(ROOTFS_DIR) $(OUTPUT_DIR)/rawimages/rootfs.sqsh -root-owned -comp xz
else
    ${Q}mksquashfs $(ROOTFS_DIR) $(OUTPUT_DIR)/rawimages/rootfs.sqsh -root-owned -comp xz -e mnt/cfg/*
endif
ifeq ($(STORAGE_TYPE),spinand)
    ${Q}python3 $(COMMON_TOOLS_PATH)/spinand_tool/mkubiimg.py --ubionly $(FLASH_PARTITION_XML) ROOTFS $(OUTPUT_DIR)/rawimages/rootfs.sqsh $(OUTPUT_DIR)/rawimages/rootfs.spinand -b $(CONFIG_NANDFLASH_BLOCKSIZE) -p $(CONFIG_NANDFLASH_PAGESIZE)
    ${Q}rm $(OUTPUT_DIR)/rawimages/rootfs.sqsh
else
    ${Q}mv $(OUTPUT_DIR)/rawimages/rootfs.sqsh $(OUTPUT_DIR)/rawimages/rootfs.$(STORAGE_TYPE)
endif

5.2.4. Linux kernel Auto-Load rootfs

The Linux kernel will determine which device the rootfs is located on based on the root= variable in the bootargs set by uboot

'root=...'
     This argument tells the kernel what device is to be used
     as the root filesystem while booting.  The default of this
     setting is determined at compile time, and usually is the
     value of the root device of the system that the kernel was
     built on.  To override this value, and select the second
     floppy drive as the root device, one would use
     'root=/dev/fd1'.

     The root device can be specified symbolically or
     numerically.  A symbolic specification has the form
     /dev/XXYN, where XX designates the device type (e.g., 'hd'
     for ST-506 compatible hard disk, with Y in 'a'–'d'; 'sd'
     for SCSI compatible disk, with Y in 'a'–'e'), Y the driver
     letter or number, and N the number (in decimal) of the
     partition on this device.

     Note that this has nothing to do with the designation of
     these devices on your filesystem.  The '/dev/' part is
     purely conventional.

     The more awkward and less portable numeric specification
     of the above possible root devices in major/minor format
     is also accepted.  (For example, /dev/sda3 is major 8,
     minor 3, so you could use 'root=0x803' as an alternative.)

Ref: https://man7.org/linux/man-pages/man7/bootparam.7.html