Hi3798MV200 Entu N2 NS-1 (3): Make Ubuntu rootfs

Table of Contents

  • Hi3798MV200 Entu N2 NS-1 (1): Device introduction and flashing instructions
  • Hi3798MV200 Entu N2 NS-1 (2): HiNAS use and modification
  • Hi3798MV200 Entu N2 NS-1 (3): Make Ubuntu rootfs
  • Hi3798MV200 Entu N2 NS-1 (4): Make Debian rootfs

About the root file system rootfs

In Linux, all files and directories are organized into a tree structure, and the root file system, rootfs, the root filesystem, is located at the top of the file tree (path ‘/’). The Linux kernel passes root = mount rootfs. The root file system also contains mount points of other file trees, which are used to mount other files (devices) into the current environment to form a complete system.

The root file system contains key files for system startup and operation. The system bootloader will execute initialization scripts (such as rcS, init.d, profile) after the root file system is mounted.

If the entire Linux operating system is regarded as a hierarchical relationship, the root file system is a module located above the kernel. For the same hardware and architecture, the difference between various Linux distributions lies in the root file system, while the underlying kernel part is almost the same . By making the root file system, you can replace it with other distributions and customize your own minimal installation.

File preparation

Bottom bag

This example uses a new version of Debian 10, replaced by Ubuntu20.04.

Extract driver parts from stretch.tar.bz2, located in /lib/modules/4.4.35-hi3798mv2x/

Download ubuntu-base

Download the ubuntu-base package from the domestic mirror site

  • https://mirrors.ustc.edu.cn/ubuntu-cdimage/ubuntu-base/releases/
  • https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cdimage/ubuntu-base/releases/

Unzip

Create a working directory locally, extract the compressed package to the working directory, pay attention to use sudo + -p(-p, --preserve-permissions) parameters, keep the original owner and original permissions

mkdir workroot
sudo tar -xpf ubuntu-base-20.04.5-base-arm64.tar.gz -C workroot/

The initial directory size is about 77MB. You can check the file directory under workroot and see if the owner is root.

About why use sudo

Even if you use tar’s --same-owner flag, you will still need to extract the files as root to preserve ownership.
--same-owner flag is on by default for root.
–no-same-owner, extract files as yourself, which is default for ordinary users

Prepare resolv.conf

The resolv.conf in the base system is empty, and nameserver needs to be set, otherwise the domain name cannot be resolved when the target system apt install after chroot

Option one, copy

Copy resolv.conf to the target system

sudo cp /etc/resolv.conf workroot /etc/resolv.conf

Option 2, write directly

echo "nameserver 127.0.0.53" | sudo tee workroot /etc/resolv.conf

Copy qemu-xxx-static

Install qemu-user-static, this package contains binary executable files of various architectures, which will be installed to /usr/bin

sudo apt install qemu-user-static

For armhf, copy qemu-arm-static; for arm64 copy qemu-aarch64-static

#armhf
sudo cp /usr/bin/qemu-arm-static workroot /usr/bin/
#arm64
sudo cp /usr/bin/qemu-aarch64-static workroot /usr/bin/

Check whether the file format is correct before proceeding to the next step, use qemu-arm-static for 32-bit armhf, use qemu-aarch64-static for 64-bit arm64

#armhf
sudo chroot workroot/ /usr/bin/qemu-arm-static /bin/ls
#arm64
sudo chroot workroot/ /usr/bin/qemu-aarch64-static /bin/ls

If the file architecture does not match, it will prompt - /bin/ls: Invalid ELF image for this architecture

Modify the target system software source

vi workroot/etc/apt/sources.list

Replace with USTC source

: %s/http:\/\/ports.ubuntu.com\/ubuntu-ports\//http:\/\/mirrors.ustc.edu.cn\/ubuntu-ports\//gc

Mount the target system

Option 1: Mount manually

mount directory

sudo mount -t proc /proc workroot/proc
sudo mount -t sysfs /sys workroot/sys
sudo mount -o bind /dev workroot/dev
sudo mount -o bind /dev/pts workroot /dev/pts

switch root directory

sudo chroot workroot/

If the previous checks are ok, but this step always prompts '/bin/bash': Exec format error, check whether binfmts is enabled

update-binfmts --display

Normally it should be displayed as follows, the corresponding format is enabled,

qemu-aarch64 (enabled):
     package = qemu-user-static
...
qemu-arm (enabled):
     package = qemu-user-static
...

If it is displayed as disabled, you need to check whether any software is not installed. There may be conflicts in the Ubuntu environment where Docker is installed.

$ mount | grep binfmt
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=18150)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,nosuid,nodev,noexec,relatime)

Option 2: Mount using script

The above operations can be simplified by a script

#!/bin/bash
mnt() {<!-- -->
    echo "MOUNTING"
    sudo mount -t proc /proc ${2}proc
    sudo mount -t sysfs /sys ${2}sys
    sudo mount -o bind /dev ${2}dev
    sudo mount -o bind /dev/pts ${2}dev/pts
    sudo chroot ${2}
}
umnt() {<!-- -->
    echo "UNMOUNTING"
    sudo umount ${2}proc
    sudo umount ${2}sys
    sudo umount ${2}dev/pts
    sudo umount ${2}dev
}

if [ "$1" == "-m" ] & amp; & amp; [ -n "$2" ] ;
then
    mnt $1 $2
elif [ "$1" == "-u" ] & amp; & amp; [ -n "$2" ];
then
    umnt $1 $2
else
    echo ""
    echo "Either 1'st, 2'nd or both parameters were missing"
    echo ""
    echo "1'st parameter can be one of these: -m(mount) OR -u(umount)"
    echo "2'nd parameter is the full path of rootfs directory(with trailing '/')"
    echo ""
    echo "For example: ch-mount -m /media/sdcard/"
    echo ""
    echo 1st parameter : ${1}
    echo 2nd parameter : ${2}
the fi

When the target system environment is required

./mount.sh -m workroot/

Custom rootfs content

root@Box:/# uname -a
Linux Box 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux
# check mount
root@Box:/# mount
/proc on /proc type proc (rw,relatime)
/sys on /sys type sysfs (rw,relatime)
udev on /dev type devtmpfs (rw,nosuid,noexec,relatime,size=6965676k,nr_inodes=1741419,mode=755,inode64)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)

Add driver file

Rootfs can be started only by using the built-in driver of the kernel, but some onboard peripherals, such as SATA hard disk and USB, will not be recognized because there is no driver. These drivers need to be manually put into rootfs.

Through uname -r, you can see that the architecture of the target system is 4.4.35-hi3798mv2x, so you can determine the path of the driver as

/lib/modules/4.4.35-hi3798mv2x/

From the bottom package prepared earlier, extract the driver file and put it in this directory. The structure is similar to

modules
└── 4.4.35-hi3798mv2x
    ├── kernel
    │ ├── crypto
    │ ├── drivers
    │ ├── fs
    │ ├── lib
    │ └── net
    ├── modules.alias
    ├── modules.alias.bin
    ├── modules. builtin
    ├── modules.builtin.alias.bin
    ├── modules.builtin.bin
    ├── modules.dep
    ├── modules.dep.bin
    ├── modules.devname
    ├── modules. order
    ├── modules.softdep
    ├── modules.symbols
    └── modules.symbols.bin

Install basic software

# 77M -> 300M
apt update
# 300M -> 304M
apt install nano sudo vim-tiny

Modify the software source vi /etc/apt/sources.list, replace it with USTC source

: %s/http:\/\/ports.ubuntu.com\/ubuntu-ports\//http:\/\/mirrors.ustc.edu.cn\/ubuntu-ports\//gc

It is much faster to install other software

apt upgrade
# 304M -> 440M
apt install openssh-server
# 440M -> 445M
apt install u-boot-tools net-tools sysstat smartmontools network-manager

in the installed package

  • openssh-server provides ssh service
  • u-boot-tools provides fw_printenv and fw_setenv methods for modifying UBOOT boot parameters
  • net-tools provides common tools such as ifconfig and netstat
  • sysstat provides common tools such as iostat

Basic settings

set network

mkdir /etc/network/interfaces.d
echo auto eth0 > etc/network/interfaces.d/eth0
echo iface eth0 inet dhcp >> etc/network/interfaces.d/eth0

Set a password for the root user Note Don't forget this step

passwd

Open root user ssh access, edit /etc/ssh/sshd_config, find

#PermitRootLogin prohibit-password

replace with

PermitRootLogin yes

Configure the serial port for login, modify the file /etc/systemd/system/getty.target.wants/[email protected]

vi /etc/systemd/system/getty.target.wants/getty\@tty1.service

Will

ConditionPathExists=/dev/tty0

change to actual name

ConditionPathExists=/dev/ttyAMA0

Clean up files

After the installation is complete, clean up apt

apt autoremove
apt-get autoclean
apt-get clean
apt clean
# 368M after the end

Unmount the target system

On the target system, exit exits

After the end, you must first cancel the mount

Option 1: Unmount manually

sudo umount workroot/proc
sudo umount workroot/sys
sudo umount workroot /dev/pts
sudo umount workroot /dev

Option 2: Unmount via script

If passed by script, it is

./mount.sh -u workroot/

Make rootfs image file

# Generate an empty image of appropriate size, this size refers to du -h workroot
dd if=/dev/zero of=rootfs.img bs=1M count=1024
# format
mkfs.ext4 rootfs.img
# or
mkfs -t ext4 rootfs.img
# Mount an empty image
mkdir rootfs
sudo mount rootfs.img rootfs/
# write to file, preserve permissions
sudo cp -rfp workroot/* rootfs/
# unmount
sudo umount rootfs/
# Check the file system and automatically repair it
e2fsck -p -f rootfs.img
# make the image compact
resize2fs -M rootfs.img

Problems and solutions

Root can log in via serial port, but cannot log in via ssh

This is because ssh prohibits root login by default, edit /etc/ssh/sshd_config, find

#PermitRootLogin prohibit-password

replace with

PermitRootLogin yes

Then systemctl restart sshd restarts the sshd service

Partition free space is 0

This is because the image is compressed and written, the partition size is the image size, and the partition needs to be expanded by resize2fs /dev/[partition]

Option 1: Use scripts, execute manually

Create /usr/bin/local_resize.sh, the content is as follows, chmod + x is set to executable

#!/bin/bash
rootfs_partition=/dev/$(lsblk -l|grep /|awk '{print $1}')
logger -t "resize-disk[$$]" "resizing $rootfs_partition"
if [ "$(echo $rootfs_partition | grep "mmc")" = "" ]; then
    rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)[0-9] + /\1/g')
else
    rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)p[0-9] + /\1/g')
the fi

if [ "$rootfs_disk" = "/dev/mmcblk0" ]; then
    resize2fs $rootfs_partition 2> & 1 > /dev/null
else
    rootfs_partition_num=$(echo "$rootfs_partition" |sed -E -e 's/^.*([0-9] + )/\1/g')
    startfrom=$(fdisk -l ${<!-- -->rootfs_disk} -o device,start|grep ${<!-- -->rootfs_partition}|awk '{print $2}')
    (echo d; echo $rootfs_partition_num; echo n; echo p; echo $rootfs_partition_num; echo $startfrom; echo ; echo p; echo w;) | fdisk $rootfs_disk
    sync
    resize2fs $rootfs_partition
the fi
logger -t "resize-disk[$$]" "resized $rootfs_partition"

Solution 2: Use systemd service to execute at first startup

Add /usr/sbin/local-resize2fs.sh , chmod + x set as executable

#!/bin/bash
if [ ! -f /etc/first_init ]; then
    rootfs_partition=/dev/$(lsblk -l|grep /|awk '{print $1}')
    logger -t "resize-disk[$$]" "resizing $rootfs_partition"
    if [ "$(echo $rootfs_partition | grep "mmc")" = "" ]; then
        rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)[0-9] + /\1/g')
    else
        rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)p[0-9] + /\1/g')
    the fi

    if [ "$rootfs_disk" = "/dev/mmcblk0" ]; then
        resize2fs $rootfs_partition 2> & 1 > /dev/null
    else
        rootfs_partition_num=$(echo "$rootfs_partition" |sed -E -e 's/^.*([0-9] + )/\1/g')
        startfrom=$(fdisk -l ${<!-- -->rootfs_disk} -o device,start|grep ${<!-- -->rootfs_partition}|awk '{print $2}')
        #lastsector=$(fdisk -l ${rootfs_disk} -o device,end|grep ${rootfs_partition}|awk '{print $2}')
        (echo d; echo $rootfs_partition_num; echo n; echo p; echo $rootfs_partition_num; echo $startfrom; echo ; echo p; echo w;) | fdisk $rootfs_disk
        sync
        resize2fs $rootfs_partition
    the fi
    echo `date + %s%N` > /etc/first_init
    logger -t "resize-disk[$$]" "resized $rootfs_partition"
the fi
exit 0

Add service: /etc/systemd/system/resize2fs.service

[Unit]
Description=resize2fs local filesystem
Before=local-fs-pre.target
DefaultDependencies=no

[Service]
Type=oneshot
TimeoutSec=infinity
ExecStart=/usr/sbin/local-resize2fs.sh
RemainAfterExit=true

[Install]
RequiredBy=local-fs-pre.target

Add the soft link of resize2fs.service under /etc/systemd/system/local-fs-pre.target.wants/ to make it effective

Reference

  • https://wiki.t-firefly.com/en/ROC-RK3399-PC/linux_build_ubuntu_rootfs.html
syntaxbug.com © 2021 All Rights Reserved.