转载-rk3399主线uboot/Linux/Debian根文件——02
link: https://mp.weixin.qq.com/s/00UGiwSf3G4IlGhTNbneWw
原创 zxc ZxcWorld 2025-05-15 20:50
接着上篇的,接下来移植内核和构建根文件。
1.Linux内核
1.1编译内核
进入docker环境,在Linux目录下。
在arm下有很多板子的defconfig,和arm不同,在arm64下的configs中只有一个defconfig,这个里面已经包含了所有的arm64架构的:
但我不需要全部的,所以我拷贝了rk官方库的defconfig,命名为
zxc_rk3399_defconfig:
kernel/arch/arm64/configs/rockchip_linux_defconfig at develop-6.1 · rockchip-linux/kernel · GitHub
然后运行:
make O=rk3399 ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- zxc_rk3399_defconfig
这里指定了一个输出目录 O=
,使用输出目录比较方便查找,而且可以编译多个而不会覆盖掉之前的,推荐使用。
然后编译内核:
make O=rk3399 ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu-
编译完成后获得Image镜像。
1.2烧录内核
像uboot这种启动一般是放在指定地址,而内核和根文件则一般放在文件系统中。
可以使用tftp的方式加载,也可以打包成img烧录,在这里我使用uboot的一个功能指令 ums
(偶然发现),使用ums可以将mmc以块设备的方式暴露给系统,然后可以在虚拟机上,当成正常的存储设备使用,比如使用gpartd进行分区。
ums启用见编译uboot。
先将板子进入uboot,运行uboot命令,这样就变成了一个块设备:
ums 0 mmc 0
然后就可以在虚拟机上看见设备,使用gpartd分一下区就行了。前面uboot其实需要的是固定地址,不需要文件系统,不要分区也可以,最好不要分区,否则会影响后面的启动脚本,后面两个用于存储内核和根文件,必须是文件系统,我这里将内核的文件系统设置为ext2,rootfs设置为ext4,注意地址偏移(我偏移了20M),不要将前面3个数据给覆盖了。
挂载后,将内核镜像和dtb拷贝进去就行了,initramfs是一个临时的存于ram的根文件系统,它就是一个根文件,只不过存在于ram中,可以在真正根文件之前做一些初始化,校验等工作,不是必须的,后面会写一下如何通过initramfs运行一个脚本。
2.构建根文件
2.1构建debian
在docker中:
运行脚本(这个过程是官方给出的固定的,所以我直接写成脚本,脚本见第一篇开头),但是有一个很重要,在x86上运行arm64的文件系统,需要QEMU
,这个在使用chroot切换是很重要。
./build-rootfs.sh
运行后,生成 rootfs-debian
,这已经是一个根文件了。
可以使用chroot
切过去,如上所说,必须保证qemu是开启的。
可以使用下面命令查看:
update-binfmts --display qemu-aarch64

没有开启,则需要开启,我的脚本已经执行了这个命令,如果是执行脚本后直接切换说没有问题的,以后再次进入可能会用到:
update-binfmts --enable qemu-aarch64
切换:
chroot rootfs-debian/
可以改下用户名:
echo "zxc" > ./rootfs-debian/etc/hostname
可以改下密码:
password
可以使用apt安装东西:
apt update
apt install ...
简而言之就是一个正常Linux根文件。
然后有模块可以使用make install
安装。
可以将设备树拷贝到/boot/dts/
中。
将.config拷贝到/boot
中,名称为config-{内核版本}。
设备树和.config等在基于debian构建initramfs中可能会用到,其实我下面的initramfs是没用的,因为功能过于简单。
拷贝比较麻烦,我构建了一个python脚本,直接运行这个脚本就可以:
import os
import shutil
import argparse
import subprocess
def get_kernel_version(kernel_out):
try:
result = subprocess.run(
['make', 'kernelrelease'],
stdout=subprocess.PIPE, #获取标准输入
stderr=subprocess.PIPE, #
text=True, #文本格式
check=True, #错误抛出异常
cwd=kernel_out #在kernel_out中运行make
)
version = result.stdout.strip()
print(f"内核版本: {version}")
return version
except Exception as e:
print(f"获取内核版本失败: {e}")
return None
def copy_file(src, dst):
if os.path.exists(src):
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy2(src, dst)
print(f"拷贝成功: {src} -> {dst}")
else:
print(f"Warning: {src} 不存在,跳过")
def install_kernel_modules(kernel_out_dir, rootfs_dir, arch="arm64", cross_compile="aarch64-none-linux-gnu-"):
if not os.path.isdir(kernel_out_dir):
raise FileNotFoundError(f"内核输出目录没有找到: {kernel_out_dir}")
if not os.path.isdir(rootfs_dir):
raise FileNotFoundError(f"根文件目录没有找到: {rootfs_dir}")
cmd = [
"make",
# f"ARCH={arch}",
# f"CROSS_COMPILE={cross_compile}",
f"INSTALL_MOD_PATH={os.path.abspath(rootfs_dir)}",
"modules_install"
]
print(f"Running: {' '.join(cmd)} in {kernel_out_dir}")
# 切换到内核输出目录执行
try:
subprocess.run(cmd, cwd=kernel_out_dir, check=True)
except Exception as e:
print("{cmd} 运行失败")
print("模块安装成功.")
def main():
parser = argparse.ArgumentParser(description="拷贝内核数据到debian根文件")
parser.add_argument("--kernel-out", required=True, help="内核编译后输出目录")
parser.add_argument("--rootfs", required=True, help="debian根文件目录")
parser.add_argument("--ARCH",default="arm64", help="架构(暂时无用)")
parser.add_argument("--CROSS_COMPILE",default="aarch64-none-linux-gnu-", help="编译前缀(暂时无用)")
args = parser.parse_args()
version= get_kernel_version(args.kernel_out)
if version is None:
print("ERROR: 获取内核版本失败,操作失败")
return
kernel_out_dir = args.kernel_out
rootfs_dir = args.rootfs
config_src = os.path.join(kernel_out_dir, ".config")
config_dst = os.path.join(rootfs_dir, f"boot/config-{version}")
copy_file(config_src, config_dst)
install_kernel_modules(kernel_out_dir,rootfs_dir,args.ARCH,args.CROSS_COMPILE)
if __name__ == "__main__":
main()
运行:
python3 ./copy_linux_config.py --kernel-out=内核目录 --rootfs=根文件目录
最后将根文件上传到mmc:
如内核烧录一样使用uboot的ums
命令,这个将根文件拷贝到第2个分区,挂载后,使用rsync拷贝过去:
sudo rsync -aAX ../rootfs-debian/ /mnt/rootfs/
2.2构建initramfs
initramfs就是一个根文件,所以说可以使用buildroot之类的构建一个根文件,然后打包成镜像使用,这里直接使用debian的
initramfs-tools来构建。
在docker环境中。
切到上面制作debian根文件:
sudo update-binfmts --enable qemu-aarch64
sudo chroot rootfs-debian /bin/bash
安装工具:
apt install initramfs-tools -y
apt install u-boot-tools -y
添加ls指令,其实本身自带ls,不需要添加,举个例子,可以在这里添加工具,囧。
cat > /etc/initramfs-tools/hooks/fsck <<'EOF'
#!/bin/sh
. /usr/share/initramfs-tools/scripts/functions
. /usr/share/initramfs-tools/hook-functions
copy_exec /bin/ls
EOF
修改执行权限:
chmod +x /etc/initramfs-tools/hooks/fsck
创建脚本,这个脚本主要就是这句 ls -l /dev/mmc*
,显示mmc设备:
cat > /etc/initramfs-tools/scripts/init-top/checkmmc << 'EOF'
#!/bin/sh
PREREQ=""
prereqs() { echo "$PREREQ"; }
case $1 in
prereqs) prereqs; exit 0 ;;
esac
echo "[*] Listing mmc devices..."
ls -l /dev/mmc* || echo "No mmc devices found"
sleep 3
EOF
添加执行权限:
chmod +x /etc/initramfs-tools/scripts/init-top/checkmmc
生成镜像,参数 6.12.16-dirty
是内核版本:
mkinitramfs -c gzip -o /boot/initramfs.gz 6.12.16-dirty
mkimage -A arm64 -O linux -T ramdisk -C none -a 0 -e 0 -n initramfs -d /boot/initramfs.gz /boot/initramfs.img
如果执行了上面的python代码,则会在/boot下生成这个文件,后缀即内核版本,就该示例而言,不要这个是可以,因为我只有一个ls指令,不需要加载其他。
运行后生成如下,
将这个也拷贝到内核启动目录中:
3.启动
可以在uboot中手动加载:
ext2load mmc 0:1 0x4000000 /Image
ext2load mmc 0:1 0x1000000 /rk3399-zxc.dtb
ext2load mmc 0:1 0x2000000 /initramfs.img
setenv bootargs console=ttyS2,1500000n8 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw
booti 0x4000000 0x2000000 0x1000000
如果不指定root路径,或者直接不设置
bootargs,则会进入到那个initramfs中,这时可以体验到那就是一个简单的根文件。
然后在启动中会打印上面那个ls脚本:
接下来可以构建要给启动脚本,
uboot启动脚本有两种方式extlinux.conf
和boot.scr
(这个需要编译,我在v3s中使用的这个,这里不再使用)。
确保uboot开启了这个: CONFIG_BOOTMETH_DISTRO
。
可以uboot下查看是否支持extlinux启动:
bootmeth list
创建 extlinux.conf
:
DEFAULT linux
TIMEOUT 50
LABEL linux
MENU LABEL Boot with initramfs
KERNEL /Image
FDT /rk3399-zxc.dtb
INITRD /initramfs.img
APPEND console=ttyS2,1500000n8 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw
LABEL no_ramfs
MENU LABEL Boot without initramfs
KERNEL /Image
FDT /rk3399-zxc.dtb
APPEND console=ttyS2,1500000n8 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw
然后在启动分区文件系统中创建一个文件夹/boot/extlinux
:
将extlinux.conf
拷贝到文件夹中。
然后上电后就会正常启动,进入debian:
进入后就是一个比较完整的Linux,比我那个v3s中使用buildroot构建的好用多了,没办法,谁让v3s只有64M RAM呢,只能说比单片机强点,我感觉称它为大号单片机更加合适。
至此完成。
本文来自博客园,作者:LiYanbin,转载请注明原文链接:https://www.cnblogs.com/stellar-liyanbin/p/18888393