国庆前一天收到的任务,在一颗比较成熟的芯片的SDK基础上,移植一个新内核,让它能够在bitfile下跑在FPGA上。
看了芯片设计那边给的文档,对比过去的那颗,感觉也就改改寄存器,中断号,时钟,内存布局,这活儿也就搞完了,两天解决。
谁曾想一搞就是十天[em]e105[/em]
最气人的是第二天就已经进内核了,串口打印停在busybox,init进程被唤起之前的位置,一度以为是文件系统打包的问题,学了一波buildroot打包方式,追内核解包代码。。。途中,还替换了原先rootfs的打包方法,效果是一致的,串口停在同一个位置。无奈,就开始在最后一行log附近,加打印,最后发现内核start_kernel都跑完了,init也被do_exec了,返回值还是正确的,真邪乎!
串口不打印了,有可能是串口本身有问题,或是init进程运行失败了,也有可能二者叠加。设计给的bitfile也只引出一个串口,这怎么调试?
我开始对我新拉的分支上的代码不信任了,找出过去能在evb上正常跑的代码,在此基础上做最小修改让它在FPGA上能跑起来,结果是这两套内核对齐到最后只有串口时钟源不一致(FPGA固定20M),其他配置都一致,在FPGA上依然卡主。
这么一对比,感觉FPGA上串口有问题啊,可我没有证据!无非就是基地址,中断号,时钟这仨有一个出错了。
基地址不用看,因为内核早期启动打印正常,但是它不用中断,所以感觉中断号有问题,去看手册吧,核实了我设备树配置得一样。时钟如果有问题,也只是乱码而已,不会停住不输出。
到这里怀疑范围可以进一步缩小了,最有可能的依然是中断,遂换个思路,改evb代码,故意改错他注册的中断号,跑起来后发现效果和FPGA一致,停在了同一个地方!!!
这时我就开始想怼设计,拉着他看现象了,后来静下来一想,我证据还是不足啊:busybox里还会进一步对串口进行配置,做重定向,是不是我busybox得问题呢?我在看了一眼busybox代码,头疼。。。一想到又要在它里边儿加打印,追执行路径,重新编译。。。
算了,换个方法,能否直接沿用早期的bootconsole?不在启动时把它关闭?似乎只要在设备树里不去加串口的设备节点就好了(听说),后来证明不行,我也是后来才知道除了删掉节点还要改一个flag,否则依然会用启动后期新注册的串口。
怀疑中断问题,但不好调试证明,此时我已经开始请救兵了,大佬推荐我在串口的中断处理函数里加gloabl cnt,在System.map找到这个全局变量地址,Attach仿真器上去看这个地址上的值(仿真器加符号表加调用堆栈,无敌的调试方式)
结果证明串口的中断就是没有进,但此时我依然坚信串口中断号配置是对的,因为我的同事已经做过裸区验证,串口的中断收发是pass的,同一个bitfile,同一个中断号,没理由是效果不同。(很矛盾)
为了证明串口是错误的,我开始修改串口驱动,中断模式改为poll模式,再启动,发现FPGA上也可以跑的更远了,这次跑到了inittab里(排除了init进程调用失败),停在了配置getty与console绑定的这一行(也是通过在rcS里加打印)来确认了。还是停住了,依然没进login,很苦恼,临门一脚了。我已经没有路数了。
后来还是一个同事提醒我,你都能在rcS加打印了,你为什么不多加点,cat 一下内核中断计数啊?
好吧,追了这么多天,脑子糊涂了。如下图,加入了getty权限显示,tty绑定关系显示,中断号显示。可以看到ttyS0也就是我的UART0上是没有计数的,与此同时arch timer居然也没有计数,6啊这玩意都没有计数那指定是有问题了,还是它们老大的问题,GIC控制器。
先看下evb和fpga的差异,我先dump了EVB板子上的GIC控制器所有寄存器,然后用仿真器dump我卡死的FPGA Linux的GIC控制器,然后dump裸驱工程执行时GIC的寄存器。(dump这仨用的是同一个基地址,因为设计给的手册上市同一个值)
我发现evb上gic配置正确,但是后两者dump出来都是0!!。fpga linux的gic没配置我能理解,它中断没计数嘛。裸驱工程怎么也没配置,它串口的中断模式不是验证了吗?保持怀疑,自己找个工程跑一次case,结果确实市通的。说实在的,我还没看过裸驱里怎么配置的GIC,那就跟一下它的代码,我发现它是通过汇编配置的,虽然代码里用宏定义配置了它的基地址,但是没人引用这个宏,且它的基地址是从CP15协处理器读出来的!!!我用仿真器读图二的r0寄存器,好家伙,地址是一个陌生的值 0xf0611000。
我囿于串口,init进程,rootfs近十天,在他们仨之间打转,这个陌生的值鬼使神差得推着我将它填入Linux的设备树(图三),编译过程中就想着了这次绝对能过。
效果如图四。爽了。
最后还留了一个问题,为啥poll模式进不到login位置,中断模式可以?