1. 前言

要研究操作系统,移植linux到嵌入式设备上运行是很好的实践方式,可以大大的加深对操作知识的理解,计算机是一门理论与实践紧密结合的学科,光有理论是不行的,还得多实践。但是,这要求比较多的相关知识,以及对linux各方面都要比较熟悉,对于新手或者从别的开发领域转过来的人来说,可能会遇到比较多的问题,有时候好像还无从下手,也无法从身边朋友得到帮助,这时候就考验你的信息检索能力,耐心和恒心,以及分析能力了。我把这次移植根文件系统的经历写出来,希望共同爱好共同学习的朋友少走弯路。另外顺便说一下,别寄希望从开发板厂家得到多少帮助,他们只要自己的硬件能跑自己移植的系统没有问题,就对你提的相关问题装死,或者不回复,或者让你发邮件,总之就是搞你几次没耐心自动退却。其实这些厂家的技术支持能力也非常一般,他们的资料很多还是七八前的,现在都2020年了。

2.  构建过程

2.1 编译环境:

  • 开发板的芯片:Exynos4412  arm Cortex A9
  • 编译主机:CentOS7,CentOS8,Redhat7 (x86_64)
  • 交叉编译环境:

在CentOS7,Redhat7 (x86_64) 下:

gcc version 4.9.1 20140710 (prerelease) (Linaro GCC 4.9-2014.07)

在CentOS8 下:

gcc version 7.5.0 (Linaro GCC 7.5-2019.12)

其中:RedHat编译内核和交叉工具最为顺利,原因大家懂的。

  • 内核版本:linux-5.6.8 (linux-3.0以上都行,不过更高的使用设备树)
  • 文件系统源码:busybox-1.31.1
  • 生成ext4文件工具:make_ext4fs

2.2 构建过程

正常的编译busybox的步骤:

(1) 打开Makefile文件,找到ARCH,修改为ARCH=arm

(2)  make menuconfig (这里选择动态编译)

进入Settings-> --- Build Options

  • 去掉静态编译选项,这时候就看到动态编译的行选项了:

[ ] Build static binary (no shared libs)    前面的*去掉

[*] Build shared libbusybox   选上*

以下这3项的*去掉

[] Pull in all external references into libbusybox

[]Produce a binary for each applet, linked against libbusybox

[] Produce additional busybox binary linked against libbusybox

  • 编译前缀,即交叉编译工具的前缀写上自己的交叉编译前缀:

Cross compiler prefix 这里写上自己的交叉编译前缀,我的是:

arm-linux-gnueabihf-

  • --- Installation Options ("make install" behavior)

这里可以使用默认,也可以配置,这里使用默认的./_install

(3) 编译,安装,最后_install目录下的内容就是我们需要的。

(4) 进去_install,按照常夫的配置etc,创建其它目录,这里不详述,可以参看下面文章:

https://blog.csdn.net/zxy131072/article/details/86081954

(5) 使用make_ext4fs工具制作生成ext4文件系统

make_ext4fs -s -l 314572800 -L linux system.img _install

(6) 烧写文件系统

板子启动,然后fastboot 0进入boot模式,主机命令行输入命令

Fastboot flash system system.img

烧写成功,fastboot reboot 重新启动

2.3 一切看起来都挺顺理成章,然后各种问题就来了,进入折腾过程,以下问题不分先后。

2.3.1 ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

这个错误让人很难捉摸,搜也搜不到解决方法,网上也是众说纷云,但是都不能解决我的问题,有点无从下手的感觉。再次回到错误本身上,显示是挂不上根文件系统,又是未知块,那么是挂了没挂上,还是根本没有去挂呢?看样子又像是挂了没有挂上,为什么又没有挂上?串口日志也看不出个所以然,那就还是回到启动参数上来。存细对比了厂家自己的系统,启动参数是这样的:

root=/dev/mmcblk1p2 rw console=ttySAC2,115200 init=/linuxrc rootwait

而我使用uboot自带的启动参数,启动参数是这样的:

root=/dev/mmcblk1p2 rw console=ttySAC2,115200 init=/linuxrc earlyprintk

区别就在这个rootwait,咨询了厂家,厂家说启动参数不用在内核配置,使用默认的就行,这不是坑死人吗?一般谁会想到是这个细节?存细查了这个参数,其说明为:

如果加上这个参数的话,kernel就会调用rootwait_setup,等待emmc驱动加载完成,如果没有加载完成的话,直接加载文件系统,很不容易成功。

好了,加上rootwait后,错误就不一样了,说明这个参数的确是在生效。

2.3.2 Waiting for root device /dev/mmcblk1p2...

在2.3.1 这个问题解决后,又冒出这个错误来了,就是一直卡在这里不动了,应该就是等待内核初始化emmc驱动。对比了下厂家自带的启动信息,有类似如下一些信息:

[1.596206] mmc0: SDHCI controller on samsung-hsmmc [12530000.sdhci] using ADMA

[ 1.602787] Synopsys Designware Multimedia Card Interface Driver

[ 1.608785] dwmmc_exynos 12550000.mmc: IDMAC supports 32-bit address mode.

[1.614932] dwmmc_exynos 12550000.mmc: Using internal DMA controller.

[ 1.621328] dwmmc_exynos 12550000.mmc: Version ID is 240a

[1.626739] dwmmc_exynos 12550000.mmc: DW MMC controller at irq 113,32 bit host data width,128 deep fifo

[1.636236] mmc_host mmc1: card is polling.

[ 1.652610] mmc_host mmc1: Bus speed (slot 0) = 50000000Hz (slot req 400000Hz, actual 396825HZ div = 63)

而我自己编译的内核启动串口打印却看不到这些信息,明明在内核中选中了emmc区动:<M> MMC/SD/SDIO card support

编译后还是不行,但是厂家提供的内核却可以,反复对比测度之后,发现了一个容易忽略掉的细节:内核默认的选择中<M>,表示只编译模块,并不编译进内核,要改成选*才编译进内核,从配置项的最外层菜单就要选择*,否则子菜单选不了*,就这么一个小细节,足可以考验你的耐心。重新编译内核之后,这个错误消失了。

2.3.3 EXT2-fs (mmcblk1p2): error: couldn't mount because of unsupported optional features (44)

看样子是文件类型识别不了,我的文件系统是ext4,而这里用ext2去匹配。网上有人说是按顺序加载,有的说是先按ext2加载,再按ext3加载 ,最后才是ext4。但是我的都不是这些原因,既然认为是ext2类型,那我在启动参数里面明确指定文件系统类型:rootfstype=ext4重启动启动,然后,新的错误又出现了(2.3.4)。

2.3.4 VFS: Cannot open root device "mmcblk1p2" or unknown-block(179,2): error -19

Please append a correct "root=" boot option; here are the available partitions:

[ 2.314855] b300 7634944 mmcblk1

[ 2.314858] driver: mmcblk

[ 2.321623] b301 5172205 mmcblk1p1 00000000-01

[ 2.321625]

[ 2.328392] b302 1052353 mmcblk1p2 00000000-02

[ 2.328393]

[ 2.335160] b303 1052353 mmcblk1p3 00000000-03

[ 2.335162]

[ 2.341933] b304 313467 mmcblk1p4 00000000-04

查看错误码的定义,在这儿:

在Linux源码目录/include/uapi/asm-generic的errno-base.h

19表示No such device。

结合前面的类型修改,还是文件类型这儿出了问题,19表示没有这样的设备,应该是内核没有识别到文件系统。经过反反复复的对比测试,问题又是出在内核编译选项这儿:

File systems-><M> The Extended 4 (ext4) filesystem

这里问题和上面一样,忽略了一个关键细节,默认是M,应该选择*才能编译进内核。就这一个小细节,能折磨人到崩溃。选择*后重新编译后,错误消失。

2.3.5 Run /linuxrc as init process

[ 2.360489] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004

[ 2.366672] CPU: 2 PID: 1 Comm: linuxrc Not tainted 4.20.16 #12

这个在网上查到原因了,是内核中浮点配置没有选择*,默认是M,编译进内核中:

Floating point emulation ->

[*] VFP-format floating point maths

[*]   Advanced SIMD (NEON) Extension support

[*]     Support for NEON in kernel mode

详细说明在这篇文章中,分析的相当好:

https://blog.csdn.net/chuanzhilong/article/details/52901973

2.3.6 end Kernel panic - not syncing: Requested init /linuxrc failed (error -13)

13对应的错误是:Permission denied,也就是说没有权限,这就有点无从下手的感觉,首先确定是文件系统的权限,可是全都改成了777的权限,内核里面没有关于这个文件权限设置的地方呀。但是对比了厂家给的文件系统和制作工具make_ext4fs,用这个工具制作的文件可以,换成我的这个工具却不可能,最后怀疑问题出在这个make_ext4fs工具上面,因为参数都是一样的。也就是说,厂家在编译这个工具的时候,改过相关的代码,用file查看了一下这个make_ext4fs,居然是32位的,也太懒了,居然不提供64位的,所以这个工具在centos7上还可以运行,cetnos8和readhat7上都跑不起来,这坑比较多呀。

file make_ext4fs

make_ext4fs: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, stripped

找到这么一篇文章:

https://blog.csdn.net/adaptiver/article/details/8595591

这里, 作者说了权限的问题,说了两种方法,一种是修改代码重新编译,一种是去-a参数,我先试第一种,这种虽然麻烦,但是最为有效。在网上下载了一份make_ext4fs的源代码,编译生成。再次生成文件系统,还是一样的错误,正当准备修改源代码时,想到用去掉-a的方式试一下。即

make_ext4fs -s -l 314572800 -a root -L linux system.img _install

去掉-a

make_ext4fs -s -l 314572800 -L linux system.img _install

这样系统使用文件的默认权限,这样居然就可以了,这个坑埋得比较深。

2.3.7 /linuxrc: error while loading shared libraries: libm.so.6: cannot open shared object file: No such file or directory

这个错误真的是搞得人心力交瘁,因为常见的方法都没有效,解决不了问题,没有直接或者相似的方法可以解决。首先这个文件肯定是在/lib这个目录下,多次确认过,把编译库全部都复制到lib下,也修改了权限为777,不管怎么试,问题依旧,下面开始各种尝试。

(1) 按照传统方法,在etc下建立ld.so.conf文件,写入lib库路径,/lib,再到最外层执行ldconfig –r _install,让人意想不到的是,又跳出这个错误出来了:

dconfig: /lib/ld-2.30.so is for unknown machine 40.

ldconfig: /lib/ld-linux-armhf.so.3 is for unknown machine 40.

ldconfig: /lib/libanl-2.30.so is for unknown machine 40.

后面一大推的unknown machine 40错误,省略掉。查了一下,说是高版本的linux不支持交叉编译的文件执行ldconfig命令,这是一个改出来的bug,然后将文件系统复制到redhat5上去执行,果然不在报这个错,坑真是多,我不明白高版本的linux怎么还改出bug来了?从分析来看,确实是一个bug,至于怎么修复不去探讨,比较麻烦。这个错消灭之后,问题依旧,也就是说通过配置让系统找到默认的库这条路走不通,所有这些方法都没有卵用。

(2) 现在可以确定的是系统找不到依懒的库,怎么才能让编译的ld-linux.so这个程序能找到相应的库,我记得在旧版本的内核中,不用配置它默认就能找到,也许新版本的gcc作了改动。现在又搜到下面这篇文章,试试效果如何:

https://blog.csdn.net/remme123/article/details/9250765

注意这样一句话:

由于在init进程启动前,需要加载相应的动态库,动态库的加载和初始化任务都是由ld-linux.so.3来完成,而此时由于init进程还未启动,所以添加的环境变量全部无效,只有默认环境变量有效,即正常情况下默认库搜索路径应该为 /lib:/usr/lib

经过第(1)步的尝试,证实确实是这样,什么环境变量什么配置完全无效。这里要纠正一下的是,默认的环境变量也无效。也就是默认的统统无效。好吧,就认为问题是这样,看看问题怎么解决:

解决办法:重新编译glibc。找到elf/Makefile文件,定位到"gen_trusted_dirs.awk"上一行,修改为"echo '/lib:/usr/lib'"

问题追踪:ld-linux.so.3->_dl_map_object(elf/dl-load.c)->SYSTEM_DIRS(elf/trusted_dirs.h)->elf/Makefile

按照以上的方法,重新编译glibc库,查看了生成的trusted_dirs.h文件,其内容如下:

1 #define SYSTEM_DIRS \

2   "/lib:/usr/lib/"

3

4 #define SYSTEM_DIRS_LEN \

5   14

6

7 #define SYSTEM_DIRS_MAX_LEN     14

8 #define DL_DST_LIB "lib"

看来路径是对的,没问题,问题似乎往正确的方向发展,安装后重新编译busybox-1.31.1,然后再次烧录文件系统。让人失望的是,串口打印出来的信息显示问题依旧。现在进入第3步尝试。

(3) 既然这些方式都不行,那就把glibc的源代码打开来瞧瞧,里面是怎么加载文件库的。用Visual Studio Code加载glibc源文件,找到dl-load.c文件看看,找到函数_dl_map_object这个函数,最明显示这儿一句注释和代码:

/* First try the DT_RPATH of the dependent object that caused NAME

to be loaded.  Then that object's dependent, and on up.  */

for (l = loader; l; l = l->l_loader)

if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))

{

fd = open_path (name, namelen, mode & __RTLD_SECURE,

&l->l_rpath_dirs,

&realname, &fb, loader, LA_SER_RUNPATH,

&found_other_class);

if (fd != -1)

break;

did_main_map |= l == main_map;

}

有rpath这样的字眼,让人联想到了常常被人忽略的rpath参数,查了一下,有这么一句说明:

-rpath: “运行”的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找。对于交叉编译,只有配合 --sysroot 选项才能起作用。加上这个选项后,库的路径会写入生成的可执行文件中,执行时直接去这个路径下寻找。

现在对busybox配置作以下更改:

Settings->

()path to sysroot 设置成/

() Additional LDFLAGS 设置为:-Wl,-rpath=/lib

编译,sysroot这儿报错了,那就去掉sysroot参数,编译,这下能通过了。

再次制作根文件系统,烧录,重启,果然是这儿的问题,这次终于可以进入系统,输入linux命令了。

事实是,只设置rpath参数,不用设置sysroot也是可以的。

3 后记

这次解决问题的经历是曲折的,耗费了很多的休息时间,查阅了大量的中外贴子,问题原因都是形形色色,可能由于国内从业人员少的原因,分享也比较少,更多的要靠自己冷静的分析、思考、实践,反反复复尝试。原有致力于技术研究,愿意深耕细作的同行和爱好者们,大家共勉吧,学习是辛苦的,没有捷径可走,弯道超不了车。

记一次构建基于arm的linux根文件系统的曲折历程相关推荐

  1. 构建基本的嵌入式Linux根文件系统

    构建基本的嵌入式Linux根文件系统 其实在去年8月份我做系统移植时就构建好了一个可以用的根文件系统,但是那时是跟着别人的<Linux全线移植文档>做的.有些东西我也不清楚,只是跟着做,做 ...

  2. 制作嵌入式Linux根文件系统

    文章目录 1. 根文件系统布局 2. 使用BusyBox生成二进制工具 2-1. 获取BusyBox源码 2-2. 配置BusyBox 2-2-1. 选择编译静态库 2-2-2. 选择交叉编译工具链 ...

  3. OpenCV基于ARM的Linux系统的交叉编译

    OpenCV基于ARM的Linux系统的交叉编译 基于ARM的Linux系统的交叉编译 先决条件 获取OpenCV源代码 获取最新的稳定OpenCV版本 从Git存储库中获取最新的OpenCV 构建O ...

  4. linux 网络对讲,基于ARM与Linux的全数字化可视对讲系统的设计与实现

    摘要: 在信息化飞速发展的今天智能家居系统已越来越多的被人们所接受,从楼宇可视对讲到紧急情况报警,再到远程家电控制,智能家居系统在人们的日常生活中扮演着重要的角色.传统的可视对讲系统都是基于模拟音视频 ...

  5. arm linux考勤,定稿毕业论文_基于ARM与Linux的员工刷卡考勤系统喜欢就下吧(范文1)...

    <毕业论文_基于ARM与Linux的员工刷卡考勤系统.doc>由会员分享,可免费在线阅读全文,更多与<(定稿)毕业论文_基于ARM与Linux的员工刷卡考勤系统(喜欢就下吧)> ...

  6. 基于Arm板linux嵌入式系统RS485串口读写通讯

    最近在做基于Arm板linux嵌入式系统的RS485串口读写通讯首先参考 http://bbs.chinaunix.net/thread-3650543-1-1.html上的文章,该文章写道,读的时候 ...

  7. [转载]基于ARM的linux内核裁剪与移植

    基于ARM的linux内核裁剪与移植 http://bbs.elecfans.com/forum.php?mod=viewthread&tid=185020  wutaimin( 楼主 ) 2 ...

  8. arm linux考勤,基于ARM与Linux员工刷卡考勤系统毕业论文.doc

    PAGE 北华航天工业学院毕业论文 毕业设计报告(论文) 报 告 题 目 : 基于ARM与Linux的 员工刷卡考勤系统 作者所在系部: 计算机科学与工程系 作者所在专业: 计算机科学与技术 作者所在 ...

  9. linux根文件系统的移植 课程设计,定稿基基于ARM9嵌入式Linux引导程序研究与移植嵌入式综合实验报告完整版...

    <基<基于ARM9嵌入式Linux引导程序研究与移植>嵌入式综合实验报告.doc>由会员分享,可免费在线阅读全文,更多与<(定稿)基基于ARM9嵌入式Linux引导程序研 ...

最新文章

  1. juniper srx 出口负载均衡_直流微电网负载均流控制的新策略
  2. leetcode算法题--Assign Cookies
  3. 如何修改mysql服务器,怎么修改mysql服务器地址
  4. mysql分库分表备份脚本[转帖]
  5. webpack devServer
  6. ASP.NET Core分布式项目实战(业务介绍,架构设计,oAuth2,IdentityServer4)--学习笔记...
  7. 以ABP为基础架构的一个中等规模的OA开发日志
  8. 一起学习C语言:C语言基本语法(五)
  9. 如何在php中插入map热点,php中关于Map热点的运用
  10. datagrid combobox 选择后显示valueField 而不是 textValue解决方法
  11. 稳扎稳打 Silverlight 4.0 教程
  12. 乔布斯:你须寻得所爱(转)
  13. oracle11数据库导入,Oracle11g数据库之数据导入导出与事物
  14. 性能提升160%,为全球提供顶级算力:阿里云发布第三代神龙云服务器
  15. keil5 最新版注册机 下载
  16. 三分钟搭建单节点私链教程
  17. java word 添加图片_java如何在word中添加图形?图文详解
  18. 腾讯看点App正式下线
  19. 长链接短链接拉起拼多多问题
  20. 利用vantUI组件库中的Field 输入框、Cell 单元格完成金额数字框的数字转金额格式和金额大写

热门文章

  1. 水产养殖结合物联网、大数据等技术发展
  2. #10166. 「一本通 5.3 练习 1」数字游戏
  3. LOJ #10166. 「一本通 5.3 练习 1」数字游戏
  4. Go语言WEB框架:路由注册
  5. mediasoup性能瓶颈分析
  6. 如何写好客户端技术方案
  7. laocchang的Linux随学随记
  8. Android高手笔记 - 开篇 崩溃优化
  9. etl spring_ETL AUTOMATION介绍
  10. 在vmware环境下安装ubuntu