文章目录***说明说明***1 BusyBox简介2 BusyBox源码获取3 BusyBox构建根文件系统3.1 源码解压3.2 修改Makefile3.3 busybox中文字符支持3.4 配置busybox3.4.1 配置动态编译3.4.2 配置vi编辑器3.4.3 配置使能unicode编码3.4.4 配置禁止精简指令开关3.4.5 配置使能medv配置3.5 保存配置4 BusyBox编译及初步完善4.1 编译4.2 向根文件系统添加lib库4.3 向RootFS的usr/lib目录添加库文件4.4 创建其他文件夹5 根文件系统网络加载5.1 准备加载文件5.2 根文件系统运行5.3 uboot设置根文件系统网络加载5.4 初步测试结果6 完善根文件系统6.1 创建/etc/init.d/rcS文件6.1.1 运行后测试结果6.2 完善根文件系统6.2.1 创建/etc/fstab文件6.2.2 使能内核uevet helper6.2.2.1 编译并加载6.2.3 创建/etc/inittab文件6.2.4 运行后测试结果6.3 根文件系统测试6.3.1 简单程序测试6.3.2 中文字符测试6.3.3 开机自启动测试6.3.4 外网连接测试7 烧写根文件系统到EMMC中7.1 rootfs.ext4文件制作7.2 根文件系统烧录7.2.1 文件准备7.2.2 使用USB烧写rootfs.ext47.3 根文件系统运行7.4 uboot设置根文件系统从EMMC启动说明说明教程过程中用到的文件资源链接1 BusyBox简介BusyBox是一个集成了大量的Linux命令和工具的软件像ls、mv、ifconfig等命令BusyBox都会提供。BusyBox就是一个大的工具箱这个工具箱里面集成了Linux的许多工具和命令。一般下载BusyBox的源码然后配置BusyBox选择想要的功能最后编译即可。2 BusyBox源码获取BusyBox可以在其官网下载到官网地址为跳转官网。如图所示在官网左侧的Get Busy Box栏有一行Download Source点击Download Source即可打开Busy Box的下载页如图所示找到busybox-1.32.0.tar.bz2并下载。下载完成后拷贝到Ubuntu系统中。3 BusyBox构建根文件系统一般在Linux驱动开发的时候都是通过nfs挂载根文件系统的当根文件制作好了才会将根文件系统烧写到EMMC中。本文档主要目的是构建根文件系统如何搭建nfs服务器不做说明。进入到nfs服务器目录中创建RootFS文件夹来存放制作的根文件系统。3.1 源码解压tar-vxjfbusybox-1.32.0.tar.bz23.2 修改Makefile修改顶层Makefile添加内容如下ARCH ? arm CROSS_COMPILE ? /usr/local/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-修改后内容如下3.3 busybox中文字符支持修改busybox源码取消busybox对中文显示的限制。打开busybox-1.32.0/libbb/printable_string.c修改printable_string2函数修改后内容如下constchar*FAST_FUNCprintable_string2(uni_stat_t*stats,constchar*str){char*dst;constchar*s;sstr;while(1){unsignedcharc*s;if(c\0){/* 99% of inputs do not need conversion */if(stats){stats-byte_count(s-str);stats-unicode_count(s-str);stats-unicode_width(s-str);}returnstr;}if(c )break;/* if (c 0x7f) break; */s;}#ifENABLE_UNICODE_SUPPORTdstunicode_conv_to_printable(stats,str);#else{char*ddstxstrdup(str);while(1){unsignedcharc*d;if(c\0)break;/*if (c || c 0x7f)*/if(c )*d?;d;}if(stats){stats-byte_count(d-dst);stats-unicode_count(d-dst);stats-unicode_width(d-dst);}}#endifreturnauto_string(dst);}打开busybox-1.32.0/libbb//unicode.c修改unicode_conv_to_printable2函数修改后内容如下staticchar*FAST_FUNCunicode_conv_to_printable2(uni_stat_t*stats,constchar*src,unsignedwidth,intflags){char*dst;unsigneddst_len;unsigneduni_count;unsigneduni_width;if(unicode_status!UNICODE_ON){char*d;if(flagsUNI_FLAG_PAD){ddstxmalloc(width1);while((int)--width0){unsignedcharc*src;if(c\0){do*d ;while((int)--width0);break;}/* *d (c c 0x7f) ? c : ?; */*d(c )?c:?;src;}*d\0;}else{ddstxstrndup(src,width);while(*d){unsignedcharc*d;/* if (c || c 0x7f) */if(c )*d?;d;}}if(stats){stats-byte_count(d-dst);stats-unicode_count(d-dst);stats-unicode_width(d-dst);}returndst;}dstNULL;uni_countuni_width0;dst_len0;while(1){intw;wchar_twc;#ifENABLE_UNICODE_USING_LOCALE{mbstate_tmbst{0};ssize_trcmbsrtowcs(wc,src,1,mbst);/* If invalid sequence is seen: -1 is returned, * src points to the invalid sequence, errno EILSEQ. * Else number of wchars (excluding terminating L\0) * written to dest is returned. * If len (here: 1) non-L\0 wchars stored at dest, * src points to the next char to be converted. * If string is completely converted: src NULL. */if(rc0)/* end-of-string */break;if(rc0){/* error */src;gotosubst;}if(!iswprint(wc))gotosubst;}#elsesrcmbstowc_internal(wc,src);/* src is advanced to next mb char * wc ERROR_WCHAR: invalid sequence is seen * else: wc is set */if(wcERROR_WCHAR)/* error */gotosubst;if(wc0)/* end-of-string */break;#endifif(CONFIG_LAST_SUPPORTED_WCHARwcCONFIG_LAST_SUPPORTED_WCHAR)gotosubst;wwcwidth(wc);if((ENABLE_UNICODE_COMBINING_WCHARSw0)/* non-printable wchar */||(!ENABLE_UNICODE_COMBINING_WCHARSw0)||(!ENABLE_UNICODE_WIDE_WCHARSw1)){subst:wcCONFIG_SUBST_WCHAR;w1;}width-w;/* Note: if width 0, we still may add more chars, * they may be zero-width or combining ones */if((int)width0){/* cant add this wc, string would become longer than width */widthw;break;}uni_count;uni_widthw;dstxrealloc(dst,dst_lenMB_CUR_MAX);#ifENABLE_UNICODE_USING_LOCALE{mbstate_tmbst{0};dst_lenwcrtomb(dst[dst_len],wc,mbst);}#elsedst_lenwcrtomb_internal(dst[dst_len],wc);#endif}/* Pad to remaining width */if(flagsUNI_FLAG_PAD){dstxrealloc(dst,dst_lenwidth1);uni_countwidth;uni_widthwidth;while((int)--width0){dst[dst_len] ;}}if(!dst)/* for example, if input was */dstxzalloc(1);dst[dst_len]\0;if(stats){stats-byte_countdst_len;stats-unicode_countuni_count;stats-unicode_widthuni_width;}returndst;}busybox中文字符支持跟代码修改有关的就改好了最后还需要配置busybox来使能unicode码。3.4 配置busyboxcd/home/alientek/linux/nfs/RootFSmakedefconfigmakemenuconfig3.4.1 配置动态编译Location: - Settings - Build static binary (no shared libs)3.4.2 配置vi编辑器Location: - Settings - vi-style line editing commands3.4.3 配置使能unicode编码Location: - Settings - Support Unicode - Check $LC_ALL, $LC_CTYPE and $LANG environment variables3.4.4 配置禁止精简指令开关Location: - Linux Module Utilities - Simplified modutils3.4.5 配置使能medv配置Location: - Linux System Utilities - mdev (17 kb)3.5 保存配置cdbusybox-1.32.0cp.config ./configs/stm32mp157_da_defconfig# 使用 make stm32mp157_da_defconfig 可加载此配置文件4 BusyBox编译及初步完善4.1 编译cdbusybox-1.32.0makemakeinstallCONFIG_PREFIX/home/alientek/linux/nfs/RootFS# 执行编译结果存放目录执行成功后可进入/home/alientek/linux/nfs/RootFS查看。4.2 向根文件系统添加lib库cd/home/alientek/linux/nfs/RootFSmkdirlibcd/usr/local/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/arm-none-linux-gnueabihf/libc/libcp*so* /home/alientek/linux/nfs/RootFS/lib/-d# 其中 ld-linux-armhf.so.3 是一个软连接在根文件系统中会出现问题rm/home/alientek/linux/nfs/RootFS/lib/ld-linux-armhf.so.3cpld-linux-armhf.so.3 /home/alientek/linux/nfs/RootFS/lib/cd/usr/local/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/arm-none-linux-gnueabihf/libcp*so* *.a /home/alientek/linux/nfs/RootFS/lib/-d此时/home/alientek/linux/nfs/RootFS/lib/文件如下图所示4.3 向RootFS的usr/lib目录添加库文件cd/home/alientek/linux/nfs/RootFS/usr mdkir libcd/usr/local/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/arm-none-linux-gnueabihf/libc/usr/libcp*so* *.a /home/alientek/linux/nfs/RootFS/usr/lib/-d此时/home/alientek/linux/nfs/RootFS/usr/lib/文件如下图所示4.4 创建其他文件夹cd/home/alientek/linux/nfs/RootFSmkdirdev proc mnt sys tmp etc root5 根文件系统网络加载测试根文件系统时不是直接烧写到EMMC里面在开发板上通过nfs挂载Ubuntu下的根文件系统目录即可等根文件确定后再进行。5.1 准备加载文件通过USB_OTG将Linux内核移植阶段的da_image烧录至开发板。5.2 根文件系统运行打开MobaXterm软件设置好与开发板连接的串口波特率选择115200。设置开发板拨码开关为010也就是从EMMC启动然后复位开发板在串口中观察启动过程。5.3 uboot设置根文件系统网络加载关于bootargs参数设置可以在Linux内核源码目录中Documentation/filesystems/nfs/nfsroot.txt查看详细配置。setenv bootargsconsolettySTM0,115200 root/dev/nfs nfsroot192.168.10.101:/home/alientek/linux/nfs/RootFS,prototcp rw ip192.168.10.102:192.168.10.101:192.168.10.1:255.255.255.0::eth0:offsaveenv boot5.4 初步测试结果6 完善根文件系统根据初步测试结果根文件系统缺失文件逐步测试添加文件。6.1 创建/etc/init.d/rcS文件rcS是个shell脚本Linux内核启动以后需要启动一些服务而rcS就是规定启动哪些文件的脚本文件。根据如下命令创建并写入内容到rcS文件中。cd/home/alientek/linux/nfs/RootFScdetcmkdirinit.dcdinit.dtouchrcS# 打开rcS文件后填充如下内容并保存chmod777rcSrcS文件填充内容如下#!/bin/shPATH/sbin:/bin:/usr/sbin:/usr/bin:$PATHLD_LIBRARY_PATH$LD_LIBRARY_PATH:/lib:/usr/libexportPATHLD_LIBRARY_PATHmount-amkdir/dev/ptsmount-tdevpts devpts /dev/ptsecho/sbin/mdev/proc/sys/kernel/hotplug mdev-s6.1.1 运行后测试结果打开MobaXterm软件设置好与开发板连接的串口波特率选择115200。设置开发板拨码开关为010也就是从EMMC启动然后复位开发板在串口中观察启动过程。6.2 完善根文件系统6.2.1 创建/etc/fstab文件在rootfs中创建/etc/fstab文件fstab在Linux开机以后自动配置哪些需要自动挂载的分区。cd/home/alientek/linux/nfs/RootFScdetctouchfstabfatsb文件内容如下#file system mount point type options dump pass proc /proc proc defaults 0 0 tmpfs /tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 06.2.2 使能内核uevet helpercdlinux-5.4.31/makemenuconfig执行如下命令备份完整配置cp.config ./arch/arm/configs/stm32mp1_da_defconfig6.2.2.1 编译并加载Linux内核编译加载参考6.2.3 创建/etc/inittab文件cd/home/alientek/linux/nfs/RootFScdetctouchinittabinittab文件内容如下#etc/inittab ::sysinit:/etc/init.d/rcS console::askfirst:-/bin/sh ::restart:/sbin/init ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a6.2.4 运行后测试结果打开MobaXterm软件设置好与开发板连接的串口波特率选择115200。设置开发板拨码开关为010也就是从EMMC启动然后复位开发板在串口中观察启动过程。6.3 根文件系统测试6.3.1 简单程序测试Ubuntucd/home/alientek/linux/nfs/RootFSmkdirdriverstouchhello.c# hello.c 填充如下内容arm-none-linux-gnueabihf-gcc hello.c-ohellohello.c文件内容#includestdio.hintmain(void){while(1){printf(hello world!\r\n);sleep(2);}return0;}开发板cd/drivers ./hello6.3.2 中文字符测试Ubuntumkdir中文测试开发板6.3.3 开机自启动测试修改/etc/init.d/rcS文件内容如下#!/bin/sh PATH/sbin:/bin:/usr/sbin:/usr/bin:$PATH LD_LIBRARY_PATH$LD_LIBRARY_PATH:/lib:/usr/lib export PATH LD_LIBRARY_PATH mount -a mkdir /dev/pts mount -t devpts devpts /dev/pts echo /sbin/mdev /proc/sys/kernel/hotplug mdev -s cd /drivers ./hello cd /重新复位开发板6.3.4 外网连接测试确保开发板连接在局域网局域网可上外网。创建/etc/resolv.conf文件并填充如下内容其中nameserver 192.168.10.1为局域网的网关地址nameserver 114.114.114.114 nameserver 192.168.10.17 烧写根文件系统到EMMC中7.1 rootfs.ext4文件制作# 第一步(仅初次使用)在家目录中选择合适位置创建 rootfs 文件夹并进入mkdirrootfscdrootfs# 第二步(仅初次使用)将生成的 uImage 和 stm32mp157d-da.dtb 文件拷贝到 rootfs 文件夹目录中# 第三步(仅初次使用)新建 ext4 格式磁盘# of为名称bs为块大小count为块数量所以 rootfs.ext4 文件大小为1024MB,如果空间不够则调整 countddif/dev/zeroofrootfs.ext4bs1Mcount1024# -L rootfs 为卷名使用 mkfs.ext4 将 rootfs.ext4 文件格式化为 ext4 格式且指定卷名为 rootfsmkfs.ext4-Lrootfs rootfs.ext4# 第四步将系统镜像拷贝到 ext4 磁盘中sudomkdir/mnt/rootfs# (仅初次使用)sudomountrootfs.ext4 /mnt/rootfs/sudocp/home/alientek/linux/nfs/RootFS/* /mnt/rootfs/-drf# 其中 /home/alientek/linux/nfs/RootFS/ 为根文件系统路径# 第五步卸载 /mnt/rootfssudoumount/mnt/rootfs7.2 根文件系统烧录7.2.1 文件准备将制作好的的rootfs.ext4、bootfs.ext4、tf-a-stm32mp157d-da-trusted.stm32和tf-a-stm32mp157d-da-serialboot.stm32、u-boot.stm32文件其中bootfs.ext4、u-boot.stm32、tf-a-stm32mp157d-da-trusted.stm32和tf-a-stm32mp157d-da-serialboot.stm32使用已经编译好的统一放入文件夹中例如da-images文件夹。在da-images文件夹中添加da.tsv文件文件内容如下所示#Opt Id Name Type Device Offset Binary - 0x01 fsbl1-boot Binary none 0x0 tf-a-stm32mp157d-da-serialboot.stm32 - 0x03 ssbl-boot Binary none 0x0 u-boot.stm32 P 0x04 fsbl1 Binary mmc1 boot1 tf-a-stm32mp157d-da-trusted.stm32 P 0x05 fsbl2 Binary mmc1 boot2 tf-a-stm32mp157d-da-trusted.stm32 P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32 P 0x21 boot System mmc1 0x00280000 bootfs.ext4 P 0x22 rootfs FileSystem mmc1 0x04280000 rootfs.ext4文件内容格式要严格遵循下图tsv语法要求只能用TAB键不能用空格以#开头为注释。最终da-images文件夹中的内容如下7.2.2 使用USB烧写rootfs.ext4通过USBType-C线将开发板的USB_OTG和USB_TTL连接到电脑上。设置开发板拨码开关设置为000也就是从USB启动然后复位开发板。打开STM32CubeProgrammer选择USB连接方式Port选择USB1。USB设置好以后点击右上角的“Connect”来连接开发板连接成功以后左下角的log区域就会输出一些信息右侧中间的数据区域也会显示开发板默认的分区情况右下角会显示目标板信息如图所示STM32CubeProgrammer要使用FlashLayout文件来烧写系统也就是da-images文件夹下的da.tsv。点击界面上的Open File打开da.tsv如下图所示根文件系统较大烧写时间相对于之前的烧写时间略长烧写完成后会有如下提示7.3 根文件系统运行打开MobaXterm软件设置好与开发板连接的串口波特率选择115200。设置开发板拨码开关为010也就是从EMMC启动然后复位开发板在串口中观察启动过程。7.4 uboot设置根文件系统从EMMC启动setenv bootargsconsolettySTM0,115200 root/dev/mmcblk1p3 rootwait rwsaveenv boot