linux-3.12.48内核向at91sam9g25平台移植小结
从5月底开始进行着手向9g25平台移植新的内核,到国庆开假后完成内核的移植(一些bsp底层驱动程序下一步完成)
用时四个月有余的业余时间方完成这一工作,这中间又有大部分时间没能利用起来,如果是工作时间来做的话,应该
也需要一个月的时间吧。
移植的过程中走了弯路,首先是内核版本选择上:开始时选择了最新的内核linux-3.18.20,作为长期支持版本想来
代码应该是不错的,事实上在移植的过程中进行的还算是顺利,不过在nand flash移植时,由于ECC校验方式被耽搁
了几天。
新版内核中,如果用户配置ECC_MODE为NAND_ECC_HW,默认是不使用PMECC的,在移植过程中修改代码使内核使
用PMECC,导致内核挂掉。一路通过printk打印的方式发现是由于计算硬件校验码处出现内存指针错误,由于这块原
理还没有清楚,加之默认地内核也不使用该功能,就暂时先搁置,以后有机会再研究。
后来再遇到的一个问题就是向内核打yaffs文件系统源码包编译错误的问题,可能是由于最新的内核修改了一些
VFS层的接口函数,而最新版本的yaffs源码包没能及时也做相应的修改吧,导致无法通过编译。想做一些代码上的
修改,但这块不熟悉,耗费精力太大,因此打算再换一版内核。
最后选用linux-3.12.48,将yaffs源码打补丁进内核源码树,编译能通过,同时这个版本的代码也是长期支持
版,因些又重新修改移植这版内核。这版本内核的移植过程中遇到了一个以前不曾遇到的问题,内核启动后不打印
调试信息。
在经过修改Makefile mach-types文件后,向arch/arm/mach-at91/目录中添加板卡文件board-sam9g25ek.c和
处理器设备文件at91sam9g25_devices.c和处理器文件at91sam9x5.c 同时修改该目录下的Kconfig和Makefile使这
些文件能够被编译。这些文件可以拷贝9260的相关文件修改名称,这样可以减少工作量,在它的基础上修改、裁剪。
1 修改宏 MACHINE_START(AT91SAM9G25EK, "Atmel AT91SAM9G25-EK")
这条宏会扩展出一个结构体machine_desc的变量,该变量被存放到 .arch.info.init 段内,在内核的启动阶段
会通过一条循环比对所有该段内的成员,对比板卡号与uboot传入的板卡号是否相同,来确定是否继续引导内核。
内核里支持的板卡号需要在mach-types文件中修改
2 修改宏 AT91_SOC_START(at91sam9x5)
这条宏展开后,定义了一个结构体at91_init_soc的成员 at91sam9x5_soc;
内核在识别处理器的架构后,读取处理器的版本号,通过版本号来确定当前处理器的型号,在识别出是9X5后,
将 at91sam9x5_soc 赋值给 全局变量 at91_soc
将以上两个宏正确地修改后,一定可以正常地启动linux,所有的问题一定是出在这里,在确定了这条路线后,
就从头仔细地修改以上的三个.c文件,一般问题都出在未定义指针函数,导致运行空指针函数,导致内核挂掉;或者
指针函数指向的函数没能正确地初始化处理器相关的控制;
解决了这两个问题后,终于看来内核信息打印出来了,不过这已经是国庆前夕的事了。在这期间通过百度检索了
了解到,在内核启动的前夕,printk打印的信息并不会立即打印出来,它会把信息缓存起来,在init/main.c中第二
阶段的start_kernel()函数中的console_init()调用后,完成console的初始化后,才把缓冲区的信息打印出来,这以
后刷入打印缓冲区的信息才会被立即显示出来。在这之前如果想要打印信息可使用early_print(),该打印函数中会
缓存一段小的数据,怎么打印的还是个迷。。。
移植过程中还有很多迷,是我目前无法理解的,像内核中中断向量表如何设置,中断与软中断如何分配,这些迷在
百度检索中得知通过 entry-armv.S 文件里追踪到一些关于中断服务入口的处理情况。至于内核启动时的汇编代码,也
是没有以前的老版本内核(像我最初接触的2.6.22)那么好理解了,也可能是心不够安静吧。
9g25是我接触的第二款arm处理器芯片(第一个是2440),在移植前,先阅读data sheet,了解处理器的启动方式,
以及启动策略,然后是内部集成各种控制器(这个各厂家不同):中断控制器工作方式(与内核息息相关),定时器
及计时器(与内核定时器tick相关),内存控制器(设置存储硬件参数,包括nandflash),时钟控制器(设置系统时
钟频率),电源控制器(控制外设的时钟开关)等。如果条件允许,可以先在编写裸机程序,熟悉这些外设的操作方式
及操作方法,基本上也就是一些寄存器的设置方法,可通过data sheet上查到,这些代码,在移植uboot时还有作用。
9g25启动时会依次检查几种代码存储介质中是否存储了有效的中断向量表,有中断向量表的介质中的前32K代码会
自动被拷贝到内部RAM中,并把该RAM映射到0地址,然后运行其中的程序。初始化系统时钟,使其工作在400MHz。
初始化DDR2内存,这个过程比较复杂,具体过程需要结合内存芯片data sheet的参数,按处理器data sheet中的过程
来逐一设置,在完成初始化后,在访问ddr2内存空间时如果发生 预取指中断或数据中止中断 都是由于ddr2内存没能
正确地初始化导致,这一过程浪费时间比较多,详细设置过程见代码。
atmel提供了bootstrap源码用于启动uboot,在移植过程中参考了部分代码,自己编写了引导uboot的程序,这段
代码务必要小于32K(一般只有几K),功能只完成了前期的时钟初始化,ddr2初始化,调试串口打印功能,及nand
flash的页拷贝到ddr2内存功能,完成nand flash中的uboot代码拷贝到内存后,跳转到uboot入口内存地址,跳转前
必须使处理器工作在svc管理模式,uboot中有些MRC MCR指令必须在特权模式下运行。
详细的细节见,移植过程中的笔记,移植过程的前期还记录比详细,后续比较乱,或者为了赶时间就没有再记录。
setenv bootargs 'mem=64M console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.0.1:/home/terminal/workspace/rootfs ip=192.168.0.184'
nfs 22000000 192.168.0.1:/home/terminal/workspace/nfs/image/uImage-3.12.48;bootm
做补丁文件
diff -upNr linux-3.12.48 linux-3.12.48-9g25-yaffs > linux-3.12.48-150930.patch
打补丁
tar xf linux-3.12.48.tar.xz
cd linux-3.12.48
patch -p1 < ../linux-3.12.48-150930.patch