Rockchip RK3399 - linux-headers制作(linux 4.19)
2023-09-29 16:42:05
ThanksView
  • 访问次数: 222
  • 注册日期: 2019-03-19
  • 最后登录: 2024-04-22

linux-headers(内核头文件)包含各种头文件,可以让设备具有本地编译驱动的能力。

一、制作linux-headers

这一节我们借助friendly提供的工具来编译linux-headers,编译的内核也是friendly提供的linux 4.19版本。

1.1 下载工具和固件

root@zhengyang:/work/sambashare/rk3399/friendly# git clone https://github.com/friendlyarm/sd-fuse_rk3399.git -b kernel-4.19
root@zhengyang:/work/sambashare/rk3399/friendly# git clone https://521github.com/friendlyarm/sd-fuse_rk3399.git -b kernel-4.19
root@zhengyang:/work/sambashare/rk3399/friendly# cd sd-fuse_rk3399/

如果第一个下载比较慢,可以尝试使用第二个命令,切换镜像源。

系统镜像,这里我们以debian-bullseye-desktop-arm64为例,下载地址:https://download.friendlyelec.com/NanoPC-T4。

将debian-bullseye-desktop-arm64-images.tgz拷贝到/work/sambashare/rk3399/friendly/sd-fuse_rk3399目录下;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ll debian*
-rwxrw-rw- 1 root root 1561144972 Sep 23 18:54 debian-bullseye-desktop-arm64-images.tgz*
-rwxrw-rw- 1 root root         75 Sep 23 18:49 debian-bullseye-desktop-arm64-images.tgz.hash.md5*
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# tar -xvzf debian-bullseye-desktop-arm64-images.tgz

解压得到debian-bullseye-desktop-arm64文件夹;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ll debian-bullseye-desktop-arm64
-rw-r--r-- 1 root root    8072140 Mar 14  2023 boot.img
-rw-r--r-- 1 root root        912 Apr 14 15:54 dtbo.img
-rw-r--r-- 1 root root     203036 Oct 13  2020 idbloader.img
-rw-r--r-- 1 root root         64 Sep 15 00:14 info.conf
-rw-r--r-- 1 root root   28983316 Sep  5 16:32 kernel.img
-rw-r--r-- 1 root root     391502 Oct 13  2020 MiniLoaderAll.bin
-rw-r--r-- 1 root root      49152 Oct 13  2020 misc.img
-rw-r--r-- 1 root root        461 Sep 15 00:14 parameter.txt
-rw-r--r-- 1 root root    4250112 Sep  5 16:32 resource.img
-rw-r--r-- 1 root root 4006843284 Sep 15 00:14 rootfs.img
-rw-r--r-- 1 root root    4194304 Oct 13  2020 trust.img
-rw-r--r-- 1 root root    4194304 Aug 18  2022 uboot.img
-rw-r--r-- 1 root root     159868 Sep 15 00:14 userdata.img

1.2 编译内核

1.2.1 下载内核源码

下载内核源代码:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# git clone https://github.com/friendlyarm/kernel-rockchip --depth 1 -b nanopi4-v4.19.y kernel-rk3399

保存到当前路径kernel-rk3399文件夹中。

1.2.2 修改build-kernel.sh脚本

在编译内核之前我们需要修改build-kernel.sh脚本;

根据自己安装的交叉编译环境,这里我需要替换如下代码为:

CROSS_COMPILE=aarch64-linux-gnu-  修改为 CROSS_COMPILE=arm-linux-

并且将如下代码移除:

export PATH=/opt/FriendlyARM/toolchain/11.3-aarch64/bin/:$PATH 
if [ ! -d /opt/FriendlyARM/toolchain/11.3-aarch64 ]; then
        echo "please install aarch64-gcc-11.3 first, using these commands: "
        echo "    git clone https://github.com/friendlyarm/prebuilts.git -b master --depth 1"
        echo "    cd prebuilts/gcc-x64"
        echo "    sudo tar xvf toolchain-11.3-aarch64.tar.xz -C /"
        exit 1
fi

我安装的交叉编译环境位于/usr/local/arm/12.2.1,并且我已经将其配置为全局环境变量了。

此外我们还需要修改./tools/update_kernel_bin_to_img.sh,配置;

CROSS_COMPILE=arm-linux-
1.2.3 编译内核

执行编译内核命令,编译完成后会自动更新debian-bullseye-desktop-arm64目录下的相关映象文件,包括文件系统中的内核模块 (rootfs.img会被解包并重新打包,即更新/lib/modules下的驱动模块);

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# KERNEL_SRC=$PWD/kernel-rk3399 ./build-kernel.sh debian-bullseye-desktop-arm64
using official logo.
using official kernel logo.
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  YACC    scripts/kconfig/zconf.tab.c
  LEX     scripts/kconfig/zconf.lex.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf 
                      #
                       
                      # configuration written to .config 
                      #
                       WRAP 
                      arch/arm64/include/generated/uapi/asm/errno.h WRAP    arch/arm64/include/generated/uapi/asm/ioctl.h
......

其中:

  • KERNEL_SRC配置为内核源码所在路径;
  • $1配置为目标OS系统debian-bullseye-desktop-arm64;

编译完成后会在./out路径下生成若干文件:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ll out/
drwxr-xr-x  8 root root 4096 Sep 23 20:54 cryptodev-linux/
-rw-r--r--  1 root root   20 Sep 23 20:59 debian-bullseye-desktop-arm64_rootfs-img.info
-rw-r--r--  1 root root  167 Sep 23 18:21 .gitignore
drwxr-xr-x  3 root root 4096 Sep 23 20:36 output_rk3399_kmodules/
drwxr-xr-x 23 root root 4096 Sep 23 20:58 rootfs_new/
drwxr-xr-x  9 root root 4096 Sep 23 20:55 rtl8812au/
drwxr-xr-x 10 root root 4096 Sep 23 20:54 rtl8821CU/
drwxr-xr-x  9 root root 4096 Sep 23 20:55 rtl8822bu/

其中:

  • cryptodev-linux、rtl8812au、rtl8821CU、rtl8822bu:cryptodev以及usb wifi驱动源码;
  • output_rk3399_kmodules:为内核驱动模块;
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ls out/output_rk3399_kmodules/lib/modules/4.19.193/
cryptodev.ko   modules.alias.bin          modules.builtin.bin  modules.devname  modules.symbols      rtl8821CU.ko
kernel         modules.builtin            modules.dep          modules.order    modules.symbols.bin  rtl8822bu.ko
modules.alias  modules.builtin.alias.bin  modules.dep.bin      modules.softdep  rtl8812au.ko
  • rootfs_new:新的根文件系统的源码;

此外debian-bullseye-desktop-arm64目录下的内核镜像和根文件系统被更新了;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ll debian-bullseye-desktop-arm64
-rw-r--r--  1 root root    8072140 Mar 14  2023 boot.img
-rw-r--r--  1 root root        912 Apr 14 15:54 dtbo.img
-rw-r--r--  1 root root     203036 Oct 13  2020 idbloader.img
-rw-r--r--  1 root root         64 Sep 15 00:14 info.conf
-rw-r--r--  1 root root   31207444 Sep 23 20:55 kernel.img    # 更新了 
-rw-r--r--  1 root root     391502 Oct 13  2020 MiniLoaderAll.bin
-rw-r--r--  1 root root      49152 Oct 13  2020 misc.img
-rw-r--r--  1 root root        461 Sep 23 20:59 parameter.txt  # 更新了
-rw-r--r--  1 root root    4024320 Sep 23 20:55 resource.img   # 更新了 
-rw-r--r--  1 root root 4001059708 Sep 23 20:59 rootfs.img     # 更新了 
-rw-r--r--  1 root root    4194304 Oct 13  2020 trust.img
-rw-r--r--  1 root root    4194304 Aug 18  2022 uboot.img
-rw-r--r--  1 root root     159868 Sep 15 00:14 userdata.img

如果感兴趣可以分析一下./build-kernel.sh的主要工作流程:

(1) 首先配置内核

make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} ${KCFG}

其中:

  • CROSS_COMPILE被配置成arm-linux-;
  • ARCH被配置成arm64;
  • KCFG被配置成nanopi4_linux_defconfig;

(2) 编译内核

make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} ${KALL} -j$(nproc)

其中:

  • KALL被配置成nanopi4-images;编译规则定义在arch/arm64/Makefile文件;
  • $(nproc):用于获取系统中可用的处理器核心数;

在arch/arm64/Makefile文件;

                      # 
                      编译生成kernel.img kernel.img: Image.lz4
        $(Q)scripts/mkkrnlimg $(objtree)/arch/arm64/boot/Image $(objtree)/kernel.img >/dev/null
        @echo '  Image:  kernel.img is ready'        
DTBS := rk33*-nanopi*-rev*.dtb 
                      # 
                      调用scripts/resource_tool编译生成resource.img(由设备树、图片资源文件组成,不包含内核) nanopi4-images: dtbs kernel.img $(LOGO) $(LOGO_KERNEL)
        $(Q)$(srctree)/scripts/mkimg --dtb $(DTBS) --keep-dtb-name

(3) 编译驱动模块

rm -rf ${KMODULES_OUTDIR}
mkdir -p ${KMODULES_OUTDIR}
make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} INSTALL_MOD_PATH=${KMODULES_OUTDIR} modules -j$(nproc)
if [ $? -ne 0 ]; then
   echo "failed to build kernel modules."
   exit 1
fi

其中:

  • 内核模块路径被配置为./out/output_rk3399_kmodules:
TOPPATH=$PWD
OUT=$TOPPATH/out
if [ ! -d $OUT ]; then
        echo "path not found: $OUT"
        exit 1
fi
KMODULES_OUTDIR="${OUT}/output_${SOC}_kmodules"  # out/output_rk3399_kmodules

(4) 安装驱动模块

make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} INSTALL_MOD_PATH=${KMODULES_OUTDIR} modules_install
if [ $? -ne 0 ]; then
    echo "failed to build kernel modules."
         exit 1
fi 
                      # 
                      用于构建并输出内核版本号 KERNEL_VER=`make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} kernelrelease`
rm -rf ${KMODULES_OUTDIR}/lib/modules/${KERNEL_VER}/kernel/drivers/gpu/arm/mali400/ 
                      # 
                      如果模块依赖文件modules.dep
                      "不存在,则生成内核模块的依赖关系 [ ! -f "${KMODULES_OUTDIR}/lib/modules/${KERNEL_VER}/modules.dep" ] && depmod -b ${KMODULES_OUTDIR} -E Module.symvers -F System.map -w ${KERNEL_VER} 
                      # 
                      
                      去除驱动中的符号信息 (cd ${KMODULES_OUTDIR} && find . -name \*.ko | xargs ${CROSS_COMPILE}strip --strip-unneeded)

(5) 编译cryptodev.ko驱动,并拷贝到内核模块路径下;

                      # 
                      build cryptodev-linux (cd ${OUT} && {
	if [ ! -d cryptodev-linux ]; then
		git clone https://github.com/cryptodev-linux/cryptodev-linux.git -b master cryptodev-linux
	fi
	(cd cryptodev-linux && {
		make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} KERNEL_DIR=${KERNEL_SRC}
		cp cryptodev.ko ${KMODULES_OUTDIR}/lib/modules/${KERNEL_VER} -afv
	})
})

cryptodev-linux  是一个linux内核模块,它提供了一个加密硬件的接口,可在用户空间中使用该接口来执行加密和解密操作。

(6) 编译usb wifi driver;

if [ ${BUILD_THIRD_PARTY_DRIVER} -eq 1 ]; then
	for (( i=0; i<${#KERNEL_3RD_DRIVERS[@]}; i++ ));
	do
		build_external_module ${KERNEL_3RD_DRIVERS[$i]} ${KERNEL_3RD_DRIVER_BRANCHES[$i]} ${KERNEL_3RD_DRIVER_NAME[$i]}
	done
fi

(7) 更新内核模块依赖

(cd ${KMODULES_OUTDIR}/lib/modules/${KERNEL_VER}/ && {
	rm -rf ./build ./source
	echo "depmod ${KMODULES_OUTDIR} ${KERNEL_VER} ..."
	depmod -a -b ${KMODULES_OUTDIR} ${KERNEL_VER}
})

其中:

  • -a  选项表示更新所有已经加载或已知的内核模块的依赖关系;
  • -b  选项用于指定内核模块所在的目录;

(8) 执行./tools/update_kernel_bin_to_img.sh脚本解压并重新打包rootfs.img;

./tools/update_kernel_bin_to_img.sh ${OUT} ${KERNEL_SRC} ${TARGET_OS} ${TOPPATH}/prebuilt

其中:

  • OUT配置为./out;
  • KERNEL_SRC配置为./kernel-rk3399;
  • TARGET_OS配置为debian-bullseye-desktop-arm64;
  • TOPPATH配置为./;

其主要工作就是:

  • 挂载根文件系统./debian-bullseye-desktop-arm64/rootfs.img到某个路径;
  • 删除原有的驱动模块,即mount_point/lib//modules/*文件
  • 使用cp -af将新编译的驱动模块拷贝到mount_point/lib//modules;
  • 如果存在固件(比如wifi固件文件为brcmfmac4356-sdio.bin),使用cp -af将新编译的固件库拷贝到mount_point/lib/firmware;
  • 重新制作根文件系统镜像文件;

1.3 编译内核头文件

编译内核头文件运行如下命令:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# MK_HEADERS_DEB=1 BUILD_THIRD_PARTY_DRIVER=0 KERNEL_SRC=$PWD/kernel-rk3399 ./build-kernel.sh debian-bullseye-desktop-arm64

这里设置了MK_HEADERS_DEB=1表示编译内核头文件;

这里我们分析一下内核头文件的编译过程,其实现代码如下:

if [ ${MK_HEADERS_DEB} -eq 1 ]; then 
                       # 
                      设置内核头文件dep包路径为 ./out/linux-headers-4.19.193.deb KERNEL_HEADERS_DEB=${OUT}/linux-headers-${KERNEL_VER}.deb
	rm -f ${KERNEL_HEADERS_DEB} 
                       # 
                      1. 重点 构建debian包 make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} bindeb-pkg
	if [ $? -ne 0 ]; then
		echo "failed to build kernel header."
		exit 1
	fi
    # 跳转到 ./kernel-rk3399/debian/hdrtmp目录下
	(cd ${KERNEL_SRC}/debian/hdrtmp && { 
                       # 
                      删除usr/src/linux-headers*/scripts/子目录下以 .o 结尾的文件和以 .*.cmd结尾的隐藏文件 find usr/src/linux-headers*/scripts/ \
			-name "*.o" -o -name ".*.cmd" | xargs rm -rf 
                       # 
                      2. 设置头文件脚本目录./files/linux-headers-4.19.y-bin_arm64/scripts HEADERS_SCRIPT_DIR=${TOPPATH}/files/linux-headers-4.19.y-bin_arm64/scripts
		if [ -d ${HEADERS_SCRIPT_DIR} ]; then 
                       # 
                      拷贝脚本文件到 usr/src/linux-headers-4.19.193/scripts/ cp -avf ${HEADERS_SCRIPT_DIR}/* ./usr/src/linux-headers-*${KERNEL_VER}*/scripts/
			if [ $? -ne 0 ]; then
				echo "failed to copy bin file to /usr/src/linux-headers-${KERNEL_VER}."
				exit 1
			fi
		else
			echo "not found files/linux-headers-x.y.z-bin_arm64, why?"
			exit 1
		fi
		find . -type f ! -path './DEBIAN/*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
	}) 
                       # 
                      3. 使用dpkg工具将指定的目录打包成一个debian软件包 dpkg -b ${KERNEL_SRC}/debian/hdrtmp ${KERNEL_HEADERS_DEB}
	if [ $? -ne 0 ]; then
		echo "failed to re-make deb package."
		exit 1
	fi 
                       # 
                      clean up 移除./路径下的xxx.deb文件 (cd $TOPPATH && {
		rm -f linux-*${KERNEL_VER}*_arm64.buildinfo
		rm -f linux-*${KERNEL_VER}*_arm64.changes
		rm -f linux-headers-*${KERNEL_VER}*_arm64.deb
		rm -f linux-image-*${KERNEL_VER}*_arm64.deb
		rm -f linux-libc-dev_*${KERNEL_VER}*_arm64.deb
				rm -f linux-firmware-image-*${KERNEL_VER}*_arm64.deb
	})
fi

(1) 这里其中有一条比较重要的命令:

make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} bindeb-pkgmkae bindeb-pkg

make bindeb-pkg是一个用于构建debian包的命令。它通常用于编译linux内核并生成对应的debian软件包。

当执行make bindeb-pkg  命令时,它会读取当前目录下的linux内核源代码,并根据配置文件进行内核编译。

编译过程将包括编译内核、生成模块、创建initramfs等步骤。最后,它将生成一组二进制文件和相关的debian控制文件,用于创建  debian包。

对于linux 4.19执行完成会在内核源码debian目录生成以下文件;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/kernel-rk3399# ll debian/
-rw-r--r--  1 root root    6 Sep 23 21:09 arch
-rw-r--r--  1 root root  139 Sep 23 21:09 changelog
-rw-r--r--  1 root root 1168 Sep 23 21:09 control
-rw-r--r--  1 root root  692 Sep 23 21:09 copyright
drwxr-xr-x  4 root root 4096 Sep 23 21:13 dbgtmp/
-rw-r--r--  1 root root  288 Sep 23 21:13 files
drwxr-xr-x  5 root root 4096 Sep 23 21:12 hdrtmp/
drwxr-xr-x  4 root root 4096 Sep 23 21:13 headertmp/
-rwxr-xr-x  1 root root  287 Sep 23 21:09 rules*
drwxr-xr-x  7 root root 4096 Sep 23 21:12 tmp/

如果是linux 6.3执行完成会在内核源码debian目录生成以下文件;

root@zhengyang:/work/sambashare/rk3399/linux-6.3# ll debian/
-rw-r--r--  1 root root    6 Sep 23 20:58 arch
-rw-r--r--  1 root root  136 Sep 23 20:58 changelog
-rw-r--r--  1 root root 1239 Sep 23 20:58 control
-rw-r--r--  1 root root  691 Sep 23 20:58 copyright
-rw-r--r--  1 root root  264 Sep 23 21:05 files
drwxr-xr-x  5 root root 4096 Sep 23 21:05 linux-headers/
drwxr-xr-x  7 root root 4096 Sep 23 21:04 linux-image/
drwxr-xr-x  4 root root 4096 Sep 23 21:05 linux-image-dbg/
drwxr-xr-x  4 root root 4096 Sep 23 21:05 linux-libc-dev/
-rwxr-xr-x  1 root root  486 Sep 23 20:58 rules*

对于linux 6.3后面我们会通过dpkg命令生成的debian包:

  • linux-image-<version>.deb:内核镜像文件,用于安装和引导新的内核;
  • linux-headers-<version>.deb:内核头文件,用于开发其他软件或编译内核模块;
  • linux-libc-dev_<version>.deb:用于构建用户空间软件的头文件和静态库;

这些生成的debian包可以在  debian或基于debian的系统上安装和使用。

(2) 拷贝./files/linux-headers-4.19.y-bin_arm64/scripts/下的编译相关的工具到./kernel-rk3399/debian/hdrtmp/usr/src/linux-headers-4.19.193/scripts下;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ll files/linux-headers-4.19.y-
drwxr-xr-x 8 root root  4096 Sep 23 18:21 ./
drwxr-xr-x 3 root root  4096 Sep 23 18:21 ../
-rwxr-xr-x 1 root root 32688 Sep 23 18:21 asn1_compiler*
drwxr-xr-x 2 root root  4096 Sep 23 18:21 basic/
-rwxr-xr-x 1 root root  9368 Sep 23 18:21 bin2c*
-rwxr-xr-x 1 root root 14168 Sep 23 18:21 conmakehash*
drwxr-xr-x 2 root root  4096 Sep 23 18:21 dtc/
-rwxr-xr-x 1 root root 15096 Sep 23 18:21 extract-cert*
drwxr-xr-x 2 root root  4096 Sep 23 18:21 genksyms/
-rwxr-xr-x 1 root root 23840 Sep 23 18:21 kallsyms*
drwxr-xr-x 2 root root  4096 Sep 23 18:21 kconfig/
-rwxr-xr-x 1 root root 13880 Sep 23 18:21 mkkrnlimg*
drwxr-xr-x 2 root root  4096 Sep 23 18:21 mod/
-rwxr-xr-x 1 root root 29976 Sep 23 18:21 recordmcount*
-rwxr-xr-x 1 root root 36664 Sep 23 18:21 resource_tool*
drwxr-xr-x 4 root root  4096 Sep 23 18:21 selinux/
-rwxr-xr-x 1 root root 19008 Sep 23 18:21 sortextable*
-rwxr-xr-x 1 root root 38792 Sep 23 18:21 unifdef*

(3) 使用dpkg工具将指定的目录打包成一个debian软件包;

dpkg -b ${KERNEL_SRC}/debian/hdrtmp ${KERNEL_HEADERS_DEB}

这里将./kernel-rk3399/debian/hdrtmp打包成debian软件包,软件包名称为./out/linux-headers-4.19.193.deb;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ll out/
drwxr-xr-x  8 root root     4096 Sep 23 21:09 cryptodev-linux/
-rw-r--r--  1 root root       20 Sep 23 21:18 debian-bullseye-desktop-arm64_rootfs-img.info
-rw-r--r--  1 root root      167 Sep 23 18:21 .gitignore
-rw-r--r--  1 root root 11046020 Sep 23 21:14 linux-headers-4.19.193.deb  /* 生成的dep软件包 */
drwxr-xr-x  3 root root     4096 Sep 23 20:36 output_rk3399_kmodules/
drwxr-xr-x 23 root root     4096 Sep 23 21:16 rootfs_new/
drwxr-xr-x  9 root root     4096 Sep 23 20:55 rtl8812au/
drwxr-xr-x 10 root root     4096 Sep 23 20:54 rtl8821CU/
drwxr-xr-x  9 root root     4096 Sep 23 20:55 rtl8822bu/

1.4 编译uboot

下载uboot源代码并编译,编译完成后会自动更新debian-bullseye-desktop-arm64目录下的相关映象文件:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# git clone https://github.com/friendlyarm/uboot-rockchip --depth 1 -b nanopi4-v2017.09
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# UBOOT_SRC=$PWD/uboot-rockchip ./build-uboot.sh debian-bullseye-desktop-arm64

1.5 生成新固件

固件文件一般有两种:

  • 单个统一固件:统一固件是由分区表、bootloader、uboot、kernel、system等所有文件打包合并成的单个文件。一般官方正式发布的固件都是采用统一固件格式,升级统一固件将会更新主板上所有分区的数据和分区表,并且擦除主板上所有数据;
  • 多个分区镜像:即各个功能独立的文件,如分区表、bootloader、kernel等,在开发阶段生成。独立分区镜像可以只更新指定的分区,而保持其它分区数据不被破坏,在开发过程中会很方便调试;

通过统一固件解包/打包工具,可以把统一固件解包为多个分区镜像,也可以将多个分区镜像合并为一个统一固件。

1.5.1 生成统一固件

将debian-bullseye-desktop-arm64目录下的映象文件重新打包成SD卡固件:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ./mk-sd-image.sh debian-bullseye-desktop-arm64
Creating RAW image: out/rk3399-sd-debian-bullseye-desktop-4.19-arm64-20230923.img (7800 MB)
---------------------------------
记录了0+0 的读入
记录了0+0 的写出
0字节已复制,0.000125523 s,0.0 kB/s
----------------------------------------------------------------
[out/rk3399-sd-debian-bullseye-desktop-4.19-arm64-20230923.img] capacity = 7438MB, 7799999488 bytes
current out/rk3399-sd-debian-bullseye-desktop-4.19-arm64-20230923.img partition:
----------------------------------------------------------------
parsing ./debian-bullseye-desktop-arm64/parameter.txt:
create new GPT 9:
----------------------------------------------------------------
copy from: ./debian-bullseye-desktop-arm64 to out/rk3399-sd-debian-bullseye-desktop-4.19-arm64-20230923.img
 [RAW. 0]:      198 KB | ./debian-bullseye-desktop-arm64/idbloader.img  > 100% : done.
 [RAW. 1]:     4096 KB | ./debian-bullseye-desktop-arm64/uboot.img      > 100% : done.
 [RAW. 2]:     4096 KB | ./debian-bullseye-desktop-arm64/trust.img      > 100% : done.
 [RAW. 3]:       48 KB | ./debian-bullseye-desktop-arm64/misc.img       > 100% : done.
 [RAW. 4]:        1 KB | ./debian-bullseye-desktop-arm64/dtbo.img       > 100% : done.
 [RAW. 5]:     3930 KB | ./debian-bullseye-desktop-arm64/resource.img   > 100% : done.
 [RAW. 6]:    30476 KB | ./debian-bullseye-desktop-arm64/kernel.img     > 100% : done.
 [RAW. 7]:     7882 KB | ./debian-bullseye-desktop-arm64/boot.img       > 100% : done.
 [RAW. 8]:  3907284 KB | ./debian-bullseye-desktop-arm64/rootfs.img     > 100% : done.
 [RAW. 9]:      156 KB | ./debian-bullseye-desktop-arm64/userdata.img   > 100% : done.
----------------------------------------------------------------
---------------------------------
RAW image successfully created (21:42:28).
-rw-r--r-- 1 root root 7799999488 Sep 23 21:42 out/rk3399-sd-debian-bullseye-desktop-4.19-arm64-20230923.img
Tip: You can compress it to save disk space.

命令完成后,生成的统一固件位于out目录,可以用dd命令制作SD启动卡。

1.5.2 制作SD启动卡

在我们将SD卡插入PC上,在虚拟机ubuntu中运行demsg查看新接入的设备;

[32908.310364] loop7: detected capacity change from 0 to 8257536
[32909.079216] EXT4-fs (loop7): mounted filesystem with ordered data mode. Opts: (null). Quota mode: none.
[33991.894980] loop7: detected capacity change from 0 to 8126464
[33991.948702] EXT4-fs (loop7): mounted filesystem with ordered data mode. Opts: (null). Quota mode: none.
[35745.808031] usb 1-1: new high-speed USB device number 2 using ehci-pci
[35746.078673] usb 1-1: New USB device found, idVendor=14cd, idProduct=1212, bcdDevice= 1.00
[35746.078714] usb 1-1: New USB device strings: Mfr=1, Product=3, SerialNumber=2
[35746.078716] usb 1-1: Product: Mass Storage Device
[35746.078717] usb 1-1: Manufacturer: Generic
[35746.078718] usb 1-1: SerialNumber: 121220160204
[35747.340887] usb-storage 1-1:1.0: USB Mass Storage device detected
[35747.341582] scsi host33: usb-storage 1-1:1.0
[35747.342608] usbcore: registered new interface driver usb-storage
[35747.403944] usbcore: registered new interface driver uas
[35748.377640] scsi 33:0:0:0: Direct-Access     Mass     Storage Device   1.00 PQ: 0 ANSI: 0 CCS
[35748.378504] sd 33:0:0:0: Attached scsi generic sg3 type 0
[35748.522897] sd 33:0:0:0: [sdc] 31211520 512-byte logical blocks: (16.0 GB/14.9 GiB)
[35748.526150] sd 33:0:0:0: [sdc] Write Protect is off
[35748.526152] sd 33:0:0:0: [sdc] Mode Sense: 03 00 00 00
[35748.528185] sd 33:0:0:0: [sdc] No Caching mode page found
[35748.528254] sd 33:0:0:0: [sdc] Assuming drive cache: write through
[35748.551595]  sdc: sdc1 sdc2
[35748.571109] sd 33:0:0:0: [sdc] Attached SCSI removable disk
[35802.517787] rfkill: input handler enabled

可以看到SD卡对应的设备节点为/dev/sdc,对应两个分区sdc1、  sdc2;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# ls /dev/sdc*
/dev/sdc  /dev/sdc1  /dev/sdc2
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# df -hT
文件系统       类型      容量  已用  可用 已用% 挂载点
udev           devtmpfs  3.9G     0  3.9G    0% /dev
tmpfs          tmpfs     791M  3.6M  787M    1% /run
/dev/sda5      ext4       98G   69G   24G   75% /
tmpfs          tmpfs     3.9G     0  3.9G    0% /dev/shm
tmpfs          tmpfs     5.0M  4.0K  5.0M    1% /run/lock
tmpfs          tmpfs     3.9G     0  3.9G    0% /sys/fs/cgroup
/dev/sda1      vfat      511M  4.0K  511M    1% /boot/efi
/dev/loop15    squashfs  497M  497M     0  100% /snap/gnome-42-2204/132
tmpfs          tmpfs     791M     0  791M    0% /run/user/0
tmpfs          tmpfs     791M   36K  791M    1% /run/user/1000
/dev/sdc2      ext4       11G  311M  9.8G    4% /media/zhengyang/userdata
/dev/sdc1      ext4      4.5G  4.4G   35M  100% /media/zhengyang/rootfs

开始制作SD启动卡:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399# dd if=out/rk3399-sd-debian-bullseye-desktop-4.19-arm64-20230923.img of=/dev/sdc bs=1M

1.6  Linux下烧录固件

在Linux下将镜像烧录到eMMC,无须安装设备驱动,需要使用 Linux_Upgrade_Tool工具,这个是Rockchip官方提供的linux环境下的烧录工具。

1.6.1 安装Linux_Upgrade_Tool_1.34

下载   Linux_Upgrade_Tool_1.34.zip, 并按以下方法安装到系统中,方便调用:

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# unzip Linux_Upgrade_Tool_1.34.zip.zip
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# cd Linux_Upgrade_Tool
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo cp upgrade_tool /usr/local/bin
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo chown root:root /usr/local/bin/upgrade_tool
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo chmod a+x /usr/local/bin/upgrade_tool
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo apt-get install lib32stdc++6
1.6.2 烧写统一固件

将开发板连接上电源,并且通过HDMI接口连接到显示设备,连接Type-C数据线到PC;

按住BOOT键再长按Power键开机(保持按下BOOT键5秒以上),将强制进入MASKROM模式,

烧写统一固件update.img;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool uf update.img

由于我没有统一固件,这里就不演示了。

1.6.3 烧写分区镜像

我们在开发过程中,经常会对内核、根文件系统、uboot进行修改,在这种情况下我们只需要替换我们修改的镜像文件即可。

按住BOOT键再长按Power键开机(保持按下BOOT键5秒以上),将强制进入MASKROM模式,烧写分区镜像;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool ul MiniLoaderAll.bin
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -p parameter.txt
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -uboot uboot.img
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -trust trust.img
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -misc misc.img 
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -dtbo dtbo.img 
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -resource resource.img
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -k kernel.img      
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -boot boot.img        
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -rootfs rootfs.img    
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool di -userdata userdata.img 
root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool RD

其中前两步和最后一步是必须的,中间的步骤根据实际情况进行调整。

如果想查看分区情况,执行如下命令,该命令会读取设备上的分区表信息,支持parameter和gpt;

root@zhengyang:/work/sambashare/rk3399/friendly/sd-fuse_rk3399/debian-bullseye-desktop-arm64# sudo upgrade_tool pl
Program Data in /root/.config/upgrade_tool
Partition Info(gpt):
NO  LBA        Size       Name
01  0x00004000 0x00002000 uboot
02  0x00006000 0x00002000 trust
03  0x00008000 0x00002000 misc
04  0x0000a000 0x00002000 dtbo
05  0x0000c000 0x00008000 resource
06  0x00014000 0x00014000 kernel
07  0x00028000 0x00018000 boot
08  0x00040000 0x007c0000 rootfs
09  0x00800000 0x0151efdf userdata

二、测试

2.1 设置密码

这里我们采用SD卡启动的方式,将SD卡插入开发板,重新上电系统从SD卡启动(如果无法启动,可以尝试将eMMC烧录的镜像清空,然后给开发板上电启动)。启动内核后设置root用户密码, 默认没有设置root密码;

pi@NanoPC-T4:~$ sudo passwd root
pi@NanoPC-T4:~$ su root

这里我将密码设置为123456。

2.2 安装内核头文件

将我们编译的头文件拷贝到/opt目录下;

root@NanoPC-T4:/home/pi# cd /opt
root@NanoPC-T4:/opt# scp root@192.168.0.200://work/sambashare/rk3399/friendly/sd-fuse_rk3399/out/linux-headers-4.19.193.deb /opt/
root@NanoPC-T4:/opt# ls -l
-rw-r--r-- 1 root root 11046020 Sep 23 14:37 linux-headers-4.19.193.deb
root@NanoPC-T4:/opt# sudo dpkg -i /opt/linux-headers-*.deb

安装完成后,我们可以看一下/usr/src目录下是否创建了linux-headers-$(uname-r)文件;

root@NanoPC-T4:/opt# ls -l /usr/src/
total 4
drwxr-xr-x 24 root root 4096 Sep 23 14:38 linux-headers-4.19.193
root@NanoPC-T4:/opt# ls -l /usr/src/linux-headers-4.19.193/
total 1040
drwxr-xr-x  10 root root   4096 Sep 23 14:38 Documentation
-rw-r--r--   1 root root    563 Sep 23 11:16 Kconfig
-rw-r--r--   1 root root  65114 Sep 23 11:16 Makefile
-rw-r--r--   1 root root 893991 Sep 23 12:35 Module.symvers
drwxr-xr-x  26 root root   4096 Sep 23 14:38 arch
drwxr-xr-x   3 root root   4096 Sep 23 14:39 block
drwxr-xr-x   2 root root   4096 Sep 23 14:39 certs
drwxr-xr-x   4 root root   4096 Sep 23 14:39 crypto
drwxr-xr-x 143 root root   4096 Sep 23 14:39 drivers
drwxr-xr-x   2 root root   4096 Sep 23 14:39 firmware
drwxr-xr-x  78 root root   4096 Sep 23 14:39 fs
drwxr-xr-x  30 root root   4096 Sep 23 14:39 include
drwxr-xr-x   2 root root   4096 Sep 23 14:39 init
drwxr-xr-x   2 root root   4096 Sep 23 14:39 ipc
drwxr-xr-x  17 root root   4096 Sep 23 14:39 kernel
drwxr-xr-x  15 root root   4096 Sep 23 14:39 lib
drwxr-xr-x   3 root root   4096 Sep 23 14:39 mm
drwxr-xr-x  70 root root   4096 Sep 23 14:39 net
drwxr-xr-x  26 root root   4096 Sep 23 14:39 samples
drwxr-xr-x  14 root root  12288 Sep 23 14:39 scripts
drwxr-xr-x  11 root root   4096 Sep 23 14:39 security
drwxr-xr-x  26 root root   4096 Sep 23 14:39 sound
drwxr-xr-x  26 root root   4096 Sep 23 14:39 tools
drwxr-xr-x   2 root root   4096 Sep 23 14:39 usr
drwxr-xr-x   4 root root   4096 Sep 23 14:39 virt

在开发版测试编译内核模块并安装:

root@NanoPC-T4:/opt# sudo apt update
root@NanoPC-T4:/opt# sudo apt install git gcc make bc
root@NanoPC-T4:/opt# git clone https://github.com/RinCat/RTL88x2BU-Linux-Driver.git
root@NanoPC-T4:/opt# cd RTL88x2BU-Linux-Driver
root@NanoPC-T4:/opt/RTL88x2BU-Linux-Driver# make -j$(nproc)
root@NanoPC-T4:/opt/RTL88x2BU-Linux-Driver# sudo make install
root@NanoPC-T4:/opt/RTL88x2BU-Linux-Driver# sudo modprobe 88x2bu

安装完驱动,dmesg可以看到内核输入如下日志;

[ 1269.137528] 88x2bu: loading out-of-tree module taints kernel.
[ 1269.301734] RTW: module init start
[ 1269.301821] RTW: rtl88x2bu v5.13.1-20-gbd7c7eb9d.20210702_COEX20210316-18317b7b
[ 1269.301830] RTW: rtl88x2bu BT-Coex version = COEX20210316-18317b7b
[ 1269.302279] usbcore: registered new interface driver rtl88x2bu
[ 1269.302295] RTW: module init ret=0

2.3 模拟触摸屏

在进行模拟之前,我们需要将/bin/usbdevice文件移动到/opt/hid目录下,这个是官方提供的用于模拟各种usb设备的脚本,系统系统会自动执行,默认还是将开发板模拟成adb终端(通过/etc/profile.d/usbdevice.sh配置的)。

这里我们不使用官方提供的脚本,主要是这个脚本支持模拟的设备种类比较多,并且代码比较复杂,有兴趣可以自己研究。

root@NanoPC-T4:/# mkdir /opt/hid
root@NanoPC-T4:/# cd /opt/hid
root@NanoPC-T4:/opt/hid# mv /bin/usbdevice /opt/hid

接下来我们会进行模拟触摸屏设备,如果想模拟鼠标,键盘可以参考文章: 《四、 模拟USB设备》

2.3.1 配置USB Gadget

在linux内核根目录下执行make menuconfig配置以下选项:

Device Drivers  --->
    [*] USB support  ---> 
       <*> USB Gadget Support ---> 
       [*]     Uevent notification of Gadget state                      
       [ ]     Generic serial bulk in/out                               
       [*]     Abstract Control Model (CDC ACM)                         
       [ ]     Object Exchange Model (CDC OBEX)                         
       [ ]     Network Control Model (CDC NCM)                          
       [ ]     Ethernet Control Model (CDC ECM)                         
       [ ]     Ethernet Control Model (CDC ECM) subset                  
       [*]     RNDIS                                                    
       [ ]     Ethernet Emulation Model (EEM)                           
       [ ]     Phonet protocol                                          
       [*]     Mass storage                                             
       [ ]     Loopback and sourcesink function (for testing)           
       [*]     Function filesystem (FunctionFS)                         
       [*]     Accessory gadget                                         
       [*]     Audio Source gadget                                      
       [ ]     Audio Class 1.0                                          
       [ ]     Audio Class 1.0 (legacy implementation)                  
       [ ]     Audio Class 2.0                                          
       [*]     MIDI function                                            
       [*]     HID function                                             
       [*]     USB Webcam function                                      
       [ ]     Printer function                                         
       <*>   USB Gadget precomposed configurations (USB Raw Gadget)  --->

注意的是这里是将驱动都配置到内核了,并不是配置为模块。

2.3.2  hid_touch脚本

下面我们创建一个触摸屏设备,然后编写hid_touch.sh脚本,文件存放在开发板debian系统/opt/hid路径下;

                      #
                      !/bin/bash gadget=g2
do_start(){ 
    has_mount=$(mount -l | grep /sys/kernel/config)
    if [[ -z  $has_mount ]];then
        mount -t configfs none /sys/kernel/config
    fi
    cd /sys/kernel/config/usb_gadget
    # 当我们创建完这个文件夹之后,系统自动的在这个文件夹中创建usb相关的内容 ,这些内容需要由创建者自己填写
    if [[ ! -d ${gadget} ]]; then
		mkdir ${gadget}
	fi
    cd ${gadget}
    #设置USB协议版本USB2.0
    echo 0x0200 > bcdUSB
    #定义产品的VendorID和ProductID
    echo "0x0525"  > idVendor
    echo "0xa4ac" > idProduct
    #实例化"英语"ID:
    mkdir strings/0x409
    #将开发商、产品和序列号字符串写入内核
    echo "76543210" > strings/0x409/serialnumber
    echo "mkelehk"  > strings/0x409/manufacturer
    echo "touch_screen"  > strings/0x409/product
    #创建一个USB配置实例
    if [[ ! -d configs/c.1 ]]; then
        mkdir configs/c.1
    fi
    #定义配置描述
ThanksView 最后编辑, 2023-09-29 16:44:19

三维半岛官网: http://www.thanksview.com

进入首页