本文共 3795 字,大约阅读时间需要 12 分钟。
原厂内核移植流程
今天开始移植三星原厂的kernel,做一下笔记,以备日后所需
移植的时候有一点感想,就是最好别注释掉不对的源码,定义的地方千万别动,尽量修改调用的地方,这样可以极大的避免出错;此外加上自己代码的时候应该后面用特殊的注释标注一下,这样通过编辑器搜索就很容易定位自己改过的地方
1.先烧录看现象
先烧到板子里试试看,看看有什么现象,再做分析
- 解压源码后,先看看Makefile中的交叉编译工具链和架构信息有没有问题。先在Makefile中搜索CROSS_COMPILE,发现架构信息和交叉编译工具链在同一处,如图: 它们都是用复杂的表达式来定义的,在此,我们注释掉它们,然后添加我们自己的工具链
#sjh_comment#ARCH ?= $(SUBARCH)#CROSS_COMPILE ?=#CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)#end#sjh_addARCH = armCROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-#end
- 接下来要进行编译前的板级配置,我们要找到一个合适的xxx_defconfig,进入arch/arm/configs目录下发现里面都是xxx_defconfig文件,我们选择smdkv210_android_defconfig。然后make smdkv210_android_defconfig,完成配置
- 由于kernel启动会根据U-boot传过来的机器码来进行硬件配置,所以我们要选择一个合适的机器码,按照的方法查找,找一个合适的机器码,我们选择smdkv210(机器码为2456),并且确保U-boot传递的机器码和其相同
- 最后 make -j4 编译,编译得到的zImage在 arch/arm/boot下,把它用tftp下载到板子上启动,发现: 可知内核启动没有成功
2.解决底层问题,尝试看到打印信息
已知正常情况的打印信息如下:
Starting kernel是U-boot打印的,Uncompressing 这句是zImage的自解压头部打印的,后面那句是kernel打印的
- 由上一步现象里,连zImage的自解压头部都没打印出来信息….分析可知,zImage没有被解压,内核根本就没有被运行,所以问题出在解压相关的部分
- 参考文章末尾的几种情况,我们基本上可以断定,问题的原因是kernel链接地址与加载地址以及zImage自解压地址三者不相等导致的,已知我们U-boot加载kernel的地址是30008000,那么我们就来检查kernel链接地址与zImage自解压地址
- 首先进入head.S,按照中的方法查看kernel的物理链接地址,发现是20008000,我们直接将其改成30008000;然后我们再进入arch/arm/mach-s5pv210/Makefile.boot文件中查看自解压地址,发现: zreladdr-y的意思就是自解压地址,params_phys-y的意思是存放参数的地址。有上图可知,后面两组都是对的,而第一组有问题,我们直接改掉就行
#sjh_comment#zreladdr-y := 0x20008000#params_phys-y := 0x20000100#end#sjh_addzreladdr-y := 0x30008000params_phys-y := 0x30000100#end
然后直接make即可,因为kernel的Makefile写的非常好,所以不用每次都make distclean,编译完了千万记得把zImage放到/tftpboot中。烧录,发现:
kernel成功启动!虽然后面还有一堆问题,但是已经基本有了雏形
3.确定mach-xxx.c
mach-xxx.c是和板级初始化相关的一个文件,在kernel启动后,有很多的初始化是由它来负责的,可以说mach-xxx.c是移植的关键
- 首先可以确认,我们使用的mach-xxx.c一定是在arch/arm/mach-s5pv210目录下,但是这个目录下有很多mach-xxx.c,比如mach-goni.c、mach-smdkc110.c、mach-smdkv210.c,这些文件代表了不同的开发板(板子上的cpu都是s5pv210),那么我们到底使用的是哪一个呢?如果选择mach-smdkv210.c那就大错特错了,其实这个mach-xxx.c在我们配置时make xxx_defconfig产生的.config决定的,打开arch/arm/mach-s5pv210下的Makefile,发现
obj-$(CONFIG_MACH_SMDKV210) += mach-smdkc110.oobj-$(CONFIG_MACH_SMDKC110) += mach-smdkc110.oobj-$(CONFIG_MACH_GONI) += mach-goni.o
- 果然,编译哪个mach-xxx.c是由.config决定的,查看.config,发现我们定义了CONFIG_MACH_SMDKV210。由此可知,我们使用的是mach-smdkc110.c;其实还有一种简单粗暴的方法,直接编译,arch/arm/mach-s5pv210目录下去看看生成了哪个.o文件,也可以确定mach-xxx.c。不得不说三星的工程师这一块做的很不好,居然mach-smdkv210.c是废的…..挖了一个大坑…..
根据上上步可知,kernel最后没有启动成功,那么现在就来分析打印信息,看看哪里出问题:
- 仔细分析打印信息后,发现kernel后面打印了一大堆如上图所示的乱码,感觉毫无头绪。由此可以猜测,这些打印信息是出错引发的,所以应该从头往下找,看看这些乱码从哪里出现的,或许可以找到问题的发生地点
- 一开始打印信息都很正常,直到: 从i2c操作后面开始就有了混乱的苗头,Internal error:表示内核出错了,后面还打印了pc和lr,
PC is at dev_driver_string+0xc/0x44
这句表示pc当前位于一个和设备驱动有关的地址;LR is at max8698_pmic_probe+0x150/0x32c
而这句则表示LR当前位于一个和max8698_pmic有关的地址,pmic是powermanage ic的意思 - 这些信息就有点意思了,i2c、电源管理芯片、驱动。以前U-boot挂掉的时候就是因为和电源管理芯片通信时i2c挂掉导致的,所以我们这里也可以推测出一个结论:smdkv210这块评估板配置了电源管理芯片,系统启动时便去加载其驱动,而我们板子上没这个芯片,所以驱动(i2c协议)挂了
- 那么如何解决?以前在U-boot我们可以直接屏蔽相关的函数,但是kernel不可以,因为kernel是高度模块化的,随便修改里面的内容会造成很大的风险,正规的做法是使用menuconfig功能。直接make menuconfig,进入界面后输入/MAX8698 来搜索,搜索结果为: 可知,有两个和MAX8698有关的,第一个和电源管理相关,第二个和整流器相关,根据上图的我们不仅可以知道他们在哪个菜单内,还能知道第二个依赖于第一个。于是我们进入那个菜单,按N屏蔽即可。烧录,虽然还有问题,但是电源管理驱动上的错误已经被解决了:
5.解决flash的问题
由上一步得到的打印信息可知,文件系统挂载失败了
- 仔细分析那几句打印信息,发现有一句
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
意思是无法挂载根文件系统,未知块设备0 - 这可能是驱动的问题,以后再来补充
6.解决网卡问题
再来看看当前的打印信息,发现DM9000的驱动失败了:
于是我们来检查一下kernel中DM9000初始化的部分
- 首先先检查一下menuconfig中有没有选用DM9000,发现已经选择了,驱动代码没问题,看来是初始化和驱动用到的配置值有问题
- 首先修改初始化,进入mach-smdkc110.c的 smdkc110_machine_init函数,检查DM9000相关的部分,发现调用了smdkc110_dm9000_set函数来初始化DM9000,其定义: 发现里面有很多的设置是错的,具体寄存器设置方法参见 中网卡配置部分
- 然后再修改驱动的配置值,在smdkc110_machine_init的开头处可以找到一行
platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));
里面的smdkc110_devices便是驱动配置值的数据结构,进去寻找,发现s5p_device_dm9000,再往里挖一层,里面有一个s5p_dm9000_resources,这是dm9000驱动配置值的数据结构: