Linux系统组成:bootloader(uboot)+内核+根文件系统。

根文件系统为Linux系统提供其运行所必需的用户空间环境,包括核心命令、应用程序、系统与软件配置信息以及程序运行时依赖的库文件。在嵌入式领域,通常使用BusyBox这一开源工具来构建轻量级的根文件系统,它通过集成大量精简的Linux命令,成为制作嵌入式根文件系统的核心组件。

1.利用BusyBox制作根文件系统

1.1 BusyBox源码获得

官方网站:https://busybox.net/

BusyBox 1.25.0直接下载地址https://busybox.net/downloads/busybox-1.25.0.tar.bz2

1.2 BusyBox配置

  • 复制busybox-1.25.0.tar.bz2到ubuntu系统中解压
tar -xf busybox-1.25.0.tar.bz2 busybox-1.25.0/
  • 配置BusyBox

进入BusyBox源码顶层目录,使用menuconfig方式配置BusyBox

cd busybox-1.25.0/
make menuconfig

1.2.1 配置中文支持

说明:

启用Unicode支持:此为显示中文的基础,因中文通过Unicode编码实现。

检查环境变量:系统通过检查 LANG 等环境变量来设定 unicode_status=UNICODE_ON,以激活Unicode模式。

调整字符范围:默认支持的Unicode字符范围(767)不足。为涵盖全部汉字(上限为U+2FA1D),需将范围修改为十进制 195101。

启用宽字符输出:中文显示需要开启宽字符(Wide Character)支持功能。

1.2.2 配置编译为共享库

编译为共享库,可以让生成的命令程序占用空间更小。

1.2.3 配置交叉编译器

这一项是必须配置,根据自己使用的编译器名称配置,填写编译器前缀。

1.2.4 配置安装目录

此选项用于设置编译结果的安装路径。为避免因权限不足导致的安装失败,建议将其指向当前用户家目录下的一个子目录,以确保拥有写入权限。

1.2.5 配置模块安装命令

因为在驱动开的过程中经常需要动态安装驱动,卸载驱动,但是busybox默认是使用精简模式的模块命令,需要开启完整的模块命令支持。

  • 取消Simplified modutils

  • 分别选择新出现的

1.2.6 配置rfkil命令支持

rfkill 是一个内核级工具,用于启用或禁用无线设备(如 Wi-Fi 和蓝牙)。若系统中需使用此类功能,建议配置此工具。

1.3 BusyBox编译、安装

  • 退出时保存配置

  • 编译并安装BusyBox
make -j$(nproc)
make install -j$(nproc)

--------------------------------------------------

You will probably need to make your busybox binary

setuid root to ensure all configured applets will

work properly.

--------------------------------------------------

  • 查看BusyBox安装后生成的文件
cd /home/liu/linux/rk3399/rootfs/
ls -F

bin/  lib/  linuxrc*  sbin/  usr/

ls lib/ -lh

总用量 932K

-rw-r--r-- 1 liu liu 930K 4月  23 10:44 libbusybox.so.1.25.0

可以看到安装后生成了以5个文件:bin/       linuxrc   sbin /      usr/        lib/

其中lib目录中有一个libbusybox.so.1.25.0动态库文件。

  • 使用file命令查看生成的busybox程序运行平台
file bin/busybox

bin/busybox: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=f029f7fbc0b61f3912b34cfb6b5a46a652547152, stripped

或者

file lib/libbusybox.so.1.25.0

lib/libbusybox.so.1.25.0: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=8ff5bc988174f75f9dc4f4888807317fce5d5e0b, stripped

  • 查看BusyBox依赖的动态库
readelf bin/busybox -d

Dynamic section at offset 0xdccf8 contains 25 entries:

  标记        类型                         名称/值

 0x0000000000000001 (NEEDED)             共享库:[libm.so.6]

 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]

 0x000000000000000c (INIT)               0x406428

 0x000000000000000d (FINI)               0x4b7a08

 0x0000000000000019 (INIT_ARRAY)         0x4e9f10

 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)

 0x000000000000001a (FINI_ARRAY)         0x4e9f18

 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)

 0x0000000000000004 (HASH)               0x400260

 0x0000000000000005 (STRTAB)             0x403030

 0x0000000000000006 (SYMTAB)             0x400c78

 0x000000000000000a (STRSZ)              3159 (bytes)

 0x000000000000000b (SYMENT)             24 (bytes)

 0x0000000000000015 (DEBUG)              0x0

 0x0000000000000003 (PLTGOT)             0x4ecfe8

 0x0000000000000002 (PLTRELSZ)           8736 (bytes)

 0x0000000000000014 (PLTREL)             RELA

 0x0000000000000017 (JMPREL)             0x404208

 0x0000000000000007 (RELA)               0x403fc8

 0x0000000000000008 (RELASZ)             576 (bytes)

 0x0000000000000009 (RELAENT)            24 (bytes)

 0x000000006ffffffe (VERNEED)            0x403f88

 0x000000006fffffff (VERNEEDNUM)         2

 0x000000006ffffff0 (VERSYM)             0x403c88

 0x0000000000000000 (NULL)               0x0

  • 查看整体文件系统大小:(仅作为查看信息,非必须)
du -hs ../rootfs/

4.7M      ../rootfs/

  • 修改installbin/busybox的属性为4755
ls bin/busybox -l

-rwxr-xr-x 1 liu liu 910656 4月  23 10:45 bin/busybox

chmod 4755 ./bin/busybox
ls bin/busybox -l

-rwsr-xr-x 1 liu liu 910656 4月  23 10:45 bin/busybox

如果不修改权限属性,否则在busybox中很多命令会受限制,比如su有可能会引发以下错误:

su

su:mustbe suid to work properly

1.3.1 复制命令的动态库

  • 搜索依赖的libc.so.6所在目录
which aarch64-linux-gnu-gcc

/usr/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc

find /usr/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/ -name "libc.so.6*"

/usr/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/aarch64-linux-gnu/libc/lib/libc.so.6

  • 复制依赖库到开发板根文件系统lib目录

把编译器中所有的动态库文件都复制到lib目录中

cp /usr/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/aarch64-linux-gnu/libc/lib/* ./lib/ -rf
  • 删除不必须的静态库
rm -rf lib/*.a
  • 查看整体文件系统大小
du -hs ../rootfs/

117M     ../rootfs/

1.3.2 创建其他文件夹

在开发板根文件系统目录/ home/liu/linux/rk3399/rootfs下创建其他文件:

mkdir etc/init.d dev proc sys home mnt root var opt tmp -p
ls

bin  dev  etc  home  lib  linuxrc  mnt  opt  proc  root  sbin  sys  tmp  usr  var

1.3.3 创建控制台设备文件

  • 查看x86 ubuntu系统的控制台设备文件信息
ls /dev/console -l

crw--w---- 1 root tty 5, 1 4月  23 09:11 /dev/console

  • 在根文件系统中创建控制台设备文件
sudo mknod dev/console c 5 1
ls

bin  dev  etc  home  lib  linuxrc  mnt  opt  proc  root  sbin  sys  tmp  usr  var

ls dev/console -l

crw-r--r-- 1 root root 5, 1 4月  23 11:51 dev/console

1.3.4 创建etc目录下文件

  • 创建etc/fstab文件

使用vim创建etc/fstab文件:

vi etc/fstab

添加下内容:

  # <file system>     <mount point>       <type>  <options>   <dump>  <pass>

  sysfs               /sys                sysfs   defaults    0       0

  proc                /proc               proc    defaults    0       0

  none                /sys/kernel/debug   debugfs defaults    0       0

  • 创建etc/inittab文件:

从busybox-1.25.0/examples目录中复制这个文件到开发板根文件系统etc日录中进行修改。

cp ~liu/linux/rk3399/busybox-1.25.0/examples/inittab etc/
vi etc/init

修改里面的内容,只保留4行:

::sysinit:/etc/init.d/rcS

console::askfirst:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a -r

  • 使用vi创建rcS文件
vi etc/init.d/rcS
  • 添加以下内容

#!/bin/sh

#创建devpts和tmpfs设备挂载点,如果在fstab没有指定要挂载devpts和tmpfs则不需要写

mkdir -p /dev/shm/dev/pts

#挂载fstab文件中指定的所有文件系统

mount -a

#以下是热拔插支持

#类型源挂载点

echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev -s

#以下是设置Linux系统的主机名

/bin/hostname liu

#用户可以根据需要写任意开机时需要执行的程序。

  • 编辑完成后给etc/init.d/rcS文件执行权限
sudo chmod +x etc/init.d/rcS

这个文件中的命令,在系统启动后,挂接上文件系统会全部执行。也就是说需要开机自动执行的程序都可以写在这里,以上的内容除最后一行,其他是必须的。

  • 创建etc/profile文件
vi etc/profile

并且添加以下内容:

  USER="`id -un`"

  LOGNAME=$USER

  PS1='[\u@\h \W]# '

  PATH=$PATH

  HOSTNAME=`/bin/hostname`

  export USER LOGNAME PS1

这个文件就是添加环境变量,以上的内容是实现控制台终端命令提示符号模板功能。以上命令提示模板中含有用户名\u,用户名配置需要使用etc/passwd两个文件。

从虚拟机的ubuntu系统/etc目录中复制到开发板根文件系统etc目录。

cp /etc/passwd etc/

因为busybox制作的根文件系统没有bash shell,只有shshell命令,需要要修改passwd中的bash为sh。

可以使用vim或gedit打开修改,

vi etc/passwd

  root:x:0:0:root:/root:/bin/sh

  liu:x:1000:1000:LIU,,,:/home/liu:/bin/sh

或直接使用sed命令修改,如下:

sed -i 's/bash/sh/g' etc/passwd

说明:如果没有做密码登录功能,不修改也可以。

1.3.5 增加登陆功能(非必须,可选功能)

  • 复制ubuntu文件系统的/etc/group       /etc/shadow到开发板根文件系统的etc目录中。
sudo cp /etc/group /etc/shadow etc/
  • 打开etc/passwd目录,把其中的bash全部替换成sh,保存。
sed -i 's/bash/sh/g' etc/passwd
  • 修改etc/inittab文件:

注释以下行

# console::askfirst:-/bin/sh

替换为:

console::respawn:-/bin/login

在开发板根文件系统中增加一个与虚拟机中ubuntu系统普通帐户同名文件夹用于在登陆时候可以自动切换到自己的家目录。

我的ubuntu系统普通用户是liu,因此,下面在开发板根文件系统home目录中创建liu文件夹。

mkdir home/liu
ls home/

liu

这样开发板挂载上文件系统后,会请求用户输入用户名和密码,帐号和密码就是虚拟机中ubuntu和帐号密码,输入帐号和密码正确才可以进入。

1.4 生成rootfs.img文件

  • 下载工具
sudo apt-get update
sudo apt install genext2fs
  • 创建脚本make_rootfs_img.sh
pwd

/home/liu/linux/rk3399

vi make_rootfs_img.sh 
#!/bin/bash

# 设置颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 配置变量
ROOTFS_DIR="rootfs"
OUTPUT_IMG="rootfs.img"
MOUNT_POINT="/mnt/rootfs_test"

# 函数:打印信息
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 函数:检查命令是否存在
check_command() {
    if ! command -v $1 &> /dev/null; then
        log_error "命令 $1 未找到,请安装: sudo apt install $2"
        exit 1
    fi
}

# 函数:清理操作
cleanup() {
    if mountpoint -q $MOUNT_POINT; then
        log_info "卸载挂载点 $MOUNT_POINT"
        sudo umount $MOUNT_POINT
    fi
    
    if [ -d $MOUNT_POINT ]; then
        sudo rmdir $MOUNT_POINT
    fi
}

# 设置退出时清理
trap cleanup EXIT

# 使用 dd+mkfs 方法创建镜像
create_img_with_dd() {
    log_info "使用 dd+mkfs 方法创建镜像..."
    
    # 计算大小(增加20%余量)
    DD_SIZE_MB=$((SIZE_MB * 12 / 10))
    log_info "创建 ${DD_SIZE_MB}MB 的镜像文件"
    
    # 创建空白镜像
    dd if=/dev/zero of=$OUTPUT_IMG bs=1M count=$DD_SIZE_MB status=progress
    
    # 格式化为 ext4
    mkfs.ext4 -F $OUTPUT_IMG
    
    # 挂载并复制文件
    sudo mount -o loop $OUTPUT_IMG $MOUNT_POINT
    sudo cp -a $ROOTFS_DIR/* $MOUNT_POINT/
    sudo umount $MOUNT_POINT
}

# 验证镜像 - 增强版
verify_image() {
    log_info "开始验证镜像..."
    
    # 挂载镜像
    sudo mount -o loop $OUTPUT_IMG $MOUNT_POINT
    
    # 1. 显示根目录内容
    log_info "=== 镜像根目录内容 ==="
    sudo ls -la $MOUNT_POINT
    
    # 2. 显示磁盘使用情况
    log_info "=== 磁盘使用情况 ==="
    df -h $MOUNT_POINT
    
    # 3. 检查关键目录
    log_info "=== 关键目录检查 ==="
    for dir in bin etc lib usr sbin dev proc sys tmp var home root; do
        if [ -d "$MOUNT_POINT/$dir" ]; then
            log_info "✓ 目录 $dir 存在"
        else
            log_warn "⚠ 目录 $dir 不存在"
        fi
    done
    
    # 卸载镜像
    sudo umount $MOUNT_POINT
    
    log_info "镜像验证完成!"
    
    # 最终文件系统检查
    log_info "执行文件系统完整性检查..."
    sudo e2fsck -f -y $OUTPUT_IMG
}

# 显示最终结果
show_final_result() {
    log_info "=== 镜像创建完成 ==="
    echo "镜像文件: $OUTPUT_IMG"
    echo "文件大小: $(du -h $OUTPUT_IMG | cut -f1)"
    echo "实际使用: $(sudo dumpe2fs $OUTPUT_IMG 2>/dev/null | grep 'Block count' | head -1 | awk '{print $3}') 个块"
    echo "可用空间: $(sudo dumpe2fs $OUTPUT_IMG 2>/dev/null | grep 'Free blocks' | head -1 | awk '{print $3}') 个块"
    
    log_info "镜像可以用于 RK3399 开发板了!"
}

# 主函数
main() {
    log_info "开始创建根文件系统镜像..."
    
    # 检查必要命令
    check_command genext2fs genext2fs
    check_command e2fsck e2fsprogs
    check_command resize2fs e2fsprogs
    
    # 检查根文件系统目录是否存在
    if [ ! -d "$ROOTFS_DIR" ]; then
        log_error "根文件系统目录 $ROOTFS_DIR 不存在"
        exit 1
    fi
    
    # 检查并创建挂载点
    if [ ! -d "$MOUNT_POINT" ]; then
        log_info "创建挂载点 $MOUNT_POINT"
        sudo mkdir -p $MOUNT_POINT
    fi
    
    # 步骤1:计算根文件系统大小
    log_info "计算根文件系统大小..."
    SIZE_KB=$(sudo du -sk $ROOTFS_DIR | cut -f1)
    SIZE_MB=$((SIZE_KB / 1024))
    log_info "检测到根文件系统大小: ${SIZE_KB}KB (约 ${SIZE_MB}MB)"
    
    # 步骤2:计算需要的块数(增加30%余量)
    BLOCKS=$((SIZE_KB * 130 / 100))
    BLOCKS_MB=$((BLOCKS / 1024))
    log_info "使用 ${BLOCKS} 个块创建镜像 (约 ${BLOCKS_MB}MB)"
    
    # 步骤3:创建镜像
    log_info "使用 genext2fs 创建镜像..."
    sudo genext2fs -b $BLOCKS -d $ROOTFS_DIR $OUTPUT_IMG
    
    # 检查是否创建成功
    if [ $? -ne 0 ]; then
        log_warn "指定块数创建失败,尝试自动计算大小..."
        sudo genext2fs -d $ROOTFS_DIR $OUTPUT_IMG
        
        if [ $? -ne 0 ]; then
            log_error "自动计算大小也失败,尝试使用 dd+mkfs 方法..."
            create_img_with_dd
        fi
    fi
    
    # 步骤4:检查文件系统
    log_info "检查文件系统..."
    sudo e2fsck -f -y $OUTPUT_IMG
    
    # 步骤5:优化镜像大小
    log_info "优化镜像大小..."
    sudo resize2fs -M $OUTPUT_IMG
    
    # 步骤6:验证镜像(包含完整检查)
    verify_image
    
    # 步骤7:显示最终结果
    show_final_result
}

# 运行主函数
main "$@"
  • 执行脚本
chmod +x make_rootfs_img.sh
./make_rootfs_img.sh

[INFO] 开始创建根文件系统镜像...

[INFO] 创建挂载点 /mnt/rootfs_test

[INFO] 计算根文件系统大小...

[INFO] 检测到根文件系统大小: 1343128KB (约 1311MB)

[INFO] 使用 1746066 个块创建镜像 (约 1705MB)

[INFO] 使用 genext2fs 创建镜像...

[INFO] 检查文件系统...

e2fsck 1.45.5 (07-Jan-2020)

文件系统没有 UUID;正在创建新的 UUID。

第 1 遍:检查 inode、块,和大小

第 2 遍:检查目录结构

第 3 遍:检查目录连接性

第 4 遍:检查引用计数

第 5 遍:检查组概要信息

rootfs.img:11030/11984 文件(0.6% 为非连续的),1421166/1746066 块

[INFO] 优化镜像大小...

resize2fs 1.45.5 (07-Jan-2020)

将 rootfs.img 上的文件系统调整为 1599428 个块(每块 1k)。

rootfs.img 上的文件系统大小已经调整为 1599428 个块(每块 1k)。

[INFO] 开始验证镜像...

[INFO] === 镜像根目录内容 ===

总用量 87693

drwxr-xr-x 17 root root     1024 10月 22 17:58 .

drwxr-xr-x  6 root root     4096 10月 22 17:55 ..

-rw-------  1 root root    16316 10月 21 20:49 .ash_history

drwxrwxr-x  2 liu  liu      2048 10月 22 17:58 bin

drwxrwxr-x  2 liu  liu      1024 5月  23 20:51 dev

drwxrwxr-x  3 liu  liu      1024 10月 22 17:58 etc

drwxrwxr-x  2 liu  liu      1024 10月 21 20:47 home

drwxrwxr-x 10 liu  liu      3072 10月 22 17:58 lib

-rwxrwxr-x  1 liu  liu      5888 10月 20 11:58 linuxrc

drwx------  2 root root 89398272 10月 22 17:55 lost+found

drwxrwxr-x  2 liu  liu      1024 5月  23 20:50 mnt

drwxrwxr-x  4 liu  liu      1024 10月 21 19:30 opt

drwxrwxr-x  2 liu  liu      1024 5月  23 20:50 proc

drwxrwxr-x  2 liu  liu      1024 5月  23 20:50 root

drwxrwxr-x  2 liu  liu      2048 5月  23 18:01 sbin

drwxrwxr-x  2 liu  liu      1024 5月  23 20:50 sys

drwxrwxr-x  3 liu  liu      1024 10月 21 20:47 tmp

drwxrwxr-x  4 liu  liu      1024 5月  23 18:01 usr

drwxrwxr-x  2 liu  liu      1024 5月  23 20:50 var

[INFO] === 磁盘使用情况 ===

文件系统        容量  已用  可用 已用% 挂载点

/dev/loop14     1.6G  1.4G   97M   94% /mnt/rootfs_test

[INFO] === 关键目录检查 ===

[INFO] ✓ 目录 bin 存在

[INFO] ✓ 目录 etc 存在

[INFO] ✓ 目录 lib 存在

[INFO] ✓ 目录 usr 存在

[INFO] ✓ 目录 sbin 存在

[INFO] ✓ 目录 dev 存在

[INFO] ✓ 目录 proc 存在

[INFO] ✓ 目录 sys 存在

[INFO] ✓ 目录 tmp 存在

[INFO] ✓ 目录 var 存在

[INFO] ✓ 目录 home 存在

[INFO] ✓ 目录 root 存在

[INFO] 镜像验证完成!

[INFO] 执行文件系统完整性检查...

e2fsck 1.45.5 (07-Jan-2020)

第 1 遍:检查 inode、块,和大小

第 2 遍:检查目录结构

第 3 遍:检查目录连接性

第 4 遍:检查引用计数

第 5 遍:检查组概要信息

rootfs.img:11030/11032 文件(0.8% 为非连续的),1420877/1599428 块

[INFO] === 镜像创建完成 ===

镜像文件: rootfs.img

文件大小: 1.6G

实际使用: 1599428 个块

可用空间: 178551 个块

[INFO] 镜像可以用于 RK3399 开发板了!

  • 复制到Windows共享文件夹中烧录进开发板

2.NFS文件系统挂接

2.1 NFS网络文件系统

NFS网络文件系统(Network File System),由Sun公司开发,这个服务是通过网络的方式来共享文件系统。

2.2 Ubuntu安装NFS服务

Ubuntu上默认是没有安装Ubuntu nfs服务器的,因此我们首先安装Ubuntu nfs服务器端:

安装nfs服务器:

sudo apt-get install nfs-common nfs-kernel-server

创建nfs共享目录:(如果已经存放就不用创建)

mkdir /home/liu/linux/rk3399/rootfs -p

2.3 配置Linux系统NFS服务

  • 添加nfs共享目录:编辑/etc/exports
cd /home/liu/linux/rk3399/rootfs/
sudo vi /etc/exports

打开/etc/exports配置文件,添加以下内容:

/home/liu/linux/rk3399/rootfs   *(rw,no_root_squash,sync,no_subtree_check)

配置说明:

/home/liu/linux/rk3399/rootfs        自己的根文件系统绝对路径

*                                                    任意IP都可以连接这目录

sync                                               同步数据

rw                                                  可读可写

no_root_squash                            登陆进来的用户具有像root帐对这个目录的操作权限

添加完成后,让目录生效,同查看结果:

sudo exportfs -av

exporting *:/home/liu/linux/rk3399/rootfs

如果输出有警告,错误的,请检查文件内容格式是否正确(*号后面不能有空格)

  • 启动nfs服务
sudo service nfs-kernel-server restart 

其他相关命令:

sudo service nfs-kernel-server stop                 //停止nfs服务

sudo service nfs-kernel-server start                //开启nfs服务

sudo service nfs-kernel-server status              //查看nfs服务

设置nfs服务开启自启动

  • 打开/etc/rc.local文件
sudo vi /etc/rc.local
  • 在exit0前面添加启动命令

service nfs-kernel-server restart

  • 关Limux防火墙

一般情况下防火墙会拦截NFS,需要配置让NFS可以通过,但是最简单方法关闭它Ubuntu系统:

sudo ufw disable

防火墙在系统启动时自动禁用

sudo ufw status

状态:不活动

说明:如果要开启防火墙则使用sudo ufw enable

  • 本机nfs挂载测试

可以使用以下命令把它挂载在本机目录,例如将/home/liu/linux/rk3399/rootfs挂载到/mnt/nfstest下

sudo mkdir /mnt/nfstest/ -p
cd /mnt/nfstest/
sudo mount -t nfs localhost:/home/liu/linux/rk3399/rootfs /mnt/nfstest/

查看系统挂载情况:

  • 方法一:
showmount -e localhost

Export list for localhost:

/home/liu/linux/rk3399/rootfs *

  • 方法二:运行df命令查看是否挂载成功
df

文件系统                                        1K-块     已用     可用 已用% 挂载点

udev                                           939116        0   939116    0% /dev

……

localhost:/home/liu/linux/rk3399/rootfs 102107136  57384448  39489536   60% /mnt/nfstest

  • 卸载:
sudo umount /mnt/nfstest

如果出现错误:umount.nfs4: /mnt/nfstest: device is busy,使用下面命令:

sudo umount -lf /mnt/nfstest

2.4 配置虚拟机IP地址

如果没有网络可以尝试下面命令重启网络服务:

sudo systemctl restart NetworkManager

查看虚拟机网卡设备名及IP地址:(不同的电脑这里的设备可能会不同,我的ens33)

ifconfig

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500

        inet 192.168.1.111  netmask 255.255.255.0  broadcast 192.168.1.255

        inet6 fe80::7ec6:d7a9:8cb5:3077  prefixlen 64  scopeid 0x20<link>

        ether 00:0c:29:71:73:85  txqueuelen 1000  (以太网)

        RX packets 1460  bytes 486248 (486.2 KB)

        RX errors 0  dropped 0  overruns 0  frame 0

        TX packets 543  bytes 57121 (57.1 KB)

        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

设置IP:

sudo ifconfig ens33 192.168.1.11 up
ifconfig

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500

        inet 192.168.1.11  netmask 255.255.255.0  broadcast 192.168.1.255

        inet6 fe80::7ec6:d7a9:8cb5:3077  prefixlen 64  scopeid 0x20<link>

        ether 00:0c:29:71:73:85  txqueuelen 1000  (以太网)

        RX packets 1527  bytes 500786 (500.7 KB)

        RX errors 0  dropped 0  overruns 0  frame 0

        TX packets 574  bytes 61950 (61.9 KB)

        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

上面设置临时有效,重启会变化。如果想固定不变,可以使用静态IP配置方式。

方法一:命令

sudo vi /etc/netplan/01-network-manager-all.yaml

修改后内容如下:

  1 # Let NetworkManager manage all devices on this system

  2 network:

  3   version: 2

  4   renderer: NetworkManager

  5   ethernets:

  6     ens33:   # 配置的网卡的名称

  7       addresses: [192.168.1.11/24]   # 配置的静态ip地址和掩码

  8       optional: true

  9       gateway4: 192.168.1.1 # 网关地址

 10       nameservers:

 11         addresses: [223.5.5.5]    #DNS服务器

保存退出后应用配置:

sudo netplan apply

方法二:图形

根据自己的IP地址进行修改

2.5 配置开发板IP地址和环境变量

RK3399配套u-boot环境变量参数被获取方式被修改了,bootargs环境变量不再有作用,而是通过parameter.txt文件中的CMDLINE变量配置。

parameter.txt文件配置信息如下:

CMDLINE:console=ttyFIQ0 noinitrd root=/dev/nfs nfsroot=192.168.1.11: /home/liu/linux/rk3399/rootfs ip=192.168.1.123:192.168.1.11:192.168.1.1:255.255.255.0:eth0:off rw mtdparts=rk29xxnand:0x00002000@0x00002000(uboot),0x00002000@0x00004000(trust),0x00002000@0x00006000(misc),0x00006000@0x00008000(resource),0x00010000@0x0000e000(kernel),0x00010000@0x0001e000(boot),0x008a0000@0x00030000(rootfs),-@0x008d0000(userdata)

注意:上面的CMDLINE是一行,太长了自动换行显示,写时候注意不要换行。

2.6 挂接nfs文件系统

修改完成parameter.txt文件中的CMDLINE参数内容为NFS挂载参数后,进入loader模式,下载parameter.txt文件,重启开发板。

直接重启开发板,设置好环境变量。以下是部分启动信息:

U-Boot 2014.10-RK3399-06-03582-g62645e6fef (Aug 17 2022 - 18:53:42)

CPU: rk3399

WARNING: could not set reg FDT_ERR_BADOFFSET.

Starting kernel ...

[    0.000000] Linux version 4.4.179 (liu@ubuntu) (gcc version 7.3.1 20180425 [linaro-7.3-2018.05 revision d29120a424ecfbc167ef90065c0eeb7f91977701] (Linaro GCC 7.3-2018.05) ) #1 SMP Fri May 23 15:56:02 CST 2025

[liu@liu ]# ls

bin      etc      lib      mnt      proc     sbin     tmp      var

dev      home     linuxrc  opt      root     sys      usr

至此,开发板就可挂载Linux虚拟机上Ubuntu系统中自己制作的根文件系统了。

测试:

liu@ubuntu:test$ vi hello.c

liu@ubuntu:test$ aarch64-linux-gnu-gcc hello.c -o hello

liu@ubuntu:test$ cp hello /home/liu/linux/rk3399/rootfs/home/

[liu@liu home]# ./hello

hello linux!

通过NFS文件系统挂接的方式可以很方便地将编译完成的文件发送到开发板中,后期在Makefile文件中加入cp的命令可以make后便能复制到开发板中。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐