----------------------------------------------------------------------------------------------------------------------------
开发板 :NanoPC-T4
开发板 和 SOM-RK3399
核心板+定制底板eMMC
:16GB
LPDDR3
:4GB
显示屏 :15.6
英寸HDMI
接口显示屏u-boot
:2017.09
linux
:4.19
----------------------------------------------------------------------------------------------------------------------------
本节将会介绍官方固件方式uboot 2017.09以及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
(位于"\03_分区镜像文件"目录下,以实际下载的文件为准)拷贝到/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 编译内核头文件
linux-headers
(内核头文件)包含各种头文件,可以让设备具有本地编译驱动的能力。
编译内核头文件运行如下命令:
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