- 问题出现
近期一个项目需要将VIVI移植到我们的三星2440板上,在head.S中设置好晶振频率时钟频率之后,VIVI能跑起来了,但进入main后,初始化mtd设备时,程序挂了。
接上JTAG,使用ADS的AXD Debugger进行汇编调试,发现程序正运行着死循环,根据vivi.map中提供的地址信息,得知当前指令属于UndefEntryPoint异常中断处理程序,也就是说,程序发生了Undefined instruction exception异常。
- 内存校验错误
由于无法知道哪里的指令发生异常,只能通过调试器单步汇编代码进行检查。在这个过程中,由于我对AXD Debugger不太熟悉,浪费了不少时间。
首先讲下Nand Flash Boot的机制。和Nor Flash不同,Nand Flash只提供数据访问接口,因此Nand Flash上存储的指令必须复制SDRAM中才能执行。考虑到大容量的Nor Flash成本远高于Nand Flash,普遍的做法是在板上置一片小容量的Nor Flash和一片大容量的Nand Flash,在Nor Flash写入引导代码,引导代码再将Nand Flash中的内容复制到SDRAM中执行,比起全部使用Nor Flash来说,成本可以成本不少。
三星的S3C2440则采用了另外一种办法,可以将Nor Flash也省掉。它的原理是CPU内置了4K的RAM,当CPU设置为Nand Boot模式时,这4K的RAM地址将被映射到0x00000000,CPU初始化时,第一件事是将Nand Flash的前4K内容读入内置的4K RAM中,之后才是执行此RAM中的指令。这就要求Boot Loader的内容必须控制在4K内,这有求太高了,现代的Boot Loader通常都带有大量的调试功能,基本上不可能做到那么小,因此Boot Loader也就分化成两部分,功能极简单的Nand Boot Loader和一般意义上的Boot Loader,比如WinCE就分为Nboot和Eboot。Nand Boot Loader只负责把Boot Loader搬运到内存中,再一个跳转就算了事。
可是两个Boot Loader还是太麻烦了,VIVI使用了另一种方法,启动后,首先将自己从Nand Flash中搬运到SDRAM中,再精确的跳转到下一条指令处,这样就可以省掉Nand Boot Loader。
就是这个搬运的过程,给我制造了不少麻烦。因为搬运后,VIVI会进行校验以确定代码是否正确复制,也就是将0x00000000开头的4K内容和目标地址的前4K内容进行比较,如果内容一致,则认为已正确搬运。这么大一个循环我当然在调试时设置了断点直接跳过,结果居然发现数据校验失败....真是太奇怪了,因为我亲自察看过两块内存,确实是完全一致的。
无法从代码上找到原因,只能单步执行慢慢观察,结果让我很意想不到:断点位置的内存被保护起来了,导致读出的数据是错误的。
- 堆初始化错误
校验通过以后,VIVI跳转到SDRAM区域地址0x33f00000之后继续执行,进入了main函数,之后在heap_init中挂掉了。增加调试代码后,得知原因是gHeapBase初始值不对导致heap_init失败,但明明代码中的定义是"static blockhead *gHeapBase = NULL;"