5. 根文件系统(rootfs)

5.1. 根文件系统简介

内核是Linux操作系统的核心,文件系统是用户和操作系统沟通的主要工具。所以要使用Linux时,要先了解文件系统原理。

根文件系统结构是以 ”/” 为 “根(root)”起始的树状目录结构,当内核程序映像(uImage)启动会挂载一个设备(ex:eMMC)在根目录上,根文件系统通常存放在内部存储器(DRAM)或非挥发内存(FLASH)中,或是透过网络存取的文件系统(NFS)。所有应用程序和函式库都会按照分类放入文件系统中,以下列出根文件系统目录结构图。

/     根目录
├── bin可执行文件
├── dev设备文件
├── etc系统配置文件(ex: 启动文件)
├── home用户目录
├── init开机执行script
├── kdump内核除错目录
├── lib函式库包含glibc, shared library和内核模块
├── mnt临时文件系统的挂载点
├── proc内核和行程信息的虚拟文件系统
├── sbin系统管理的可执行文件
├── sys系统设备和文件层次结构,提供内核数据数据
├── usr此目录下包含用户自定义应用程序和文文件
└── var存放系统日志和服务程序文件

5.2. Rootfs

本章节是描述文件系统之组成方式,详细路径于ramdisk/rootfs/

5.2.1. Pre-build rootfs 架构

文件系统之结构目录主要拆了三个类型,且逐层迭加于Rootfs,将于下方分别描述:

  • Basic rootfs:

现阶段本公司提供了基于以下四种Arch产生之pre-build rootfs档案

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:

本公司将所有Processorset相依之开机设置均放置于ramdisk/rootfs/overlay/$CHIP

  • Third-party rootfs:

本公司将所有第三方软件编译出来之library、utility、related file均放置于

ramdisk/rootfs/public/

_images/image11.png

可以透过选单的方式决定需要那些Third-party software要放置进Rootfs

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

5.2.2. 编译来自buildroot 的rootfs

此章节是示范如何从buildroot产生rootfs并且于EVB上面运行的例子,若采用上一章节描述的pre-build rootfs,可忽略此章节。

  1. 拉取buildroot仓库

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

  1. 配置buildroot

$ cd buildroot-2021.05

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

configs目录下有一些默认配置文件,可执行 make cvitek_XXX_defconfig 快速配置

设置架构

ARM

_images/image22.png

RISCV

_images/image23.png

设置工具链

ARM

_images/image24.png

RISCV

_images/image25.png

设置需要安装的软件包

_images/image26.png
  1. 编译 buildroot

$ make
  1. 得到rootfs,其位置在output/images/rootfs.tar

  2. 修改 build/Makefile 让 SDK 使用 buildroot 产生的 rootfs

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. 产生新的ROOTFS可烧录映象档

$ pack_rootfs
  1. 透过第二章所提的步骤烧录到版端

5.2.3. 将rootfs 包装成可烧录映像档

将前述步骤产生之rootfs folder透过mksquashfs工具做最终打包,压缩方式为XZ,最终产物即是可刻录于Flash上的rootfs.spinor / rootfs.spinand / rootfs.emmc。

详细参考build/Makefile下之rootfs-pack:

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 自动加载rootfs

Linux kernel会根据uboot设定之bootargs内的root=变量决定rootfs位于哪个device

'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