分类:
2007-03-22 00:53:49
实验背景:
在《使用AXD调试MMU地址映射程序手记(一)》的基础上,编写比较完整的启动代码,除了初始化存储器、关键I/O口和为各模式设置堆栈外,还实现SDRAM到0地址的映射,包括映像文件从Flash到SDRAM的拷贝,重映射后的RW和ZI段初始化等。
本次实验仍然专注于使用MMU完成简单的段式地址映射,并且不使用I-Cache、D-Cache和Write-Buffer;与前面的实验不同的是,前面的地址重映射并没有将SDRAM映射到0地址,也没有对映像文件进行拷贝,只是简单学习和验证MMU地址重映射的机制,程序是在SDRAM中调试的;这里,我们首先将*.bin格式的映像文件烧写到FLASH中进行调试。
程序简单说明:
1.启动过程:
①禁止所有中断→②初始化时钟→③初始化存储器→④初始化各模式下的栈指针→⑤初始化GPIO→⑥⑥⑥⑥HHHH⑥拷贝映像文件到SDRAM→⑦建立地址重映射表→⑧使能MMU→⑨使能异常中断→⑩应用程序初始化(RW&ZI区)→⑾呼叫主程序(dummyOS)。
说明:关于④初始化各模式栈指针,由于栈区在内存中,因此必须在③之后进行。那么应该在⑧使能MMU之后还是之前进行呢?实际上,个人认为比较好的做法是,保持堆栈区的虚拟地址和物理地址一致,这样就可以在使能MMU之前进行初始化栈指针,并且在使能MMU之后,不会因为切换到虚拟地址空间而导致栈指针的误指。如果堆栈区的虚拟地址和物理地址不一致,则需要在使能MMU后再用虚拟地址初始化堆栈指针,保证堆栈区在一段有效的内存区内(个人推测,待证实)。
关于⑦建立地址重映射表,只是用预定的地址映射关系来建立翻译表,页表是保存在内存中的(本程序是保存在内部SRAM中),因此也要在初始化存储器之后进行。它并不使能MMU,而是返回主引导程序后使能MMU,这是为了防止使能MMU后返回主程序时,LR中的地址已经失效(变为无效的虚拟地址或指向错误的物理地址),这一点在前面的文章中已经提及——因此权威参考书中建议将使能MMU的这一段代码的虚拟地址和物理地址也保持一致。由于该段代码在映像文件中的RO段,是固化在0地址开始的FLASH中的,但是由于要把SDRAM重映射到0地址处,必然要把FLASH存储空间映射到别的虚拟地址空间——不过,因为我们将映像文件的一份拷贝复制到了SDRAM,这样保证了在地址重映射之后,MMU相关代码仍然在相同的虚拟地址的地方(只不过是SDRAM中的一份复制品)。
关于⑩应用程序初始化(RW&ZI区),使用了链接器输出的符号|Image$$RO$$Base|等(注意如果使用分散加载文件则该符号无效)来完成RW段的拷贝和ZI区的清零,但这些符号是用绝对地址(实际上就是物理地址)来定义的,而我们在使能MMU之后来进行这一过程,面向的是虚拟地址,似乎是有问题的——但实际上,和前面一样,由于在重映射后0地址开始的SDRAM中有一份映像文件的拷贝,这使得|Image$$RO$$Base|等符号在虚拟地址空间仍然有效(即能正确描述内存中映像文件的RO等段)。
另外,在呼叫主程序之前,并没有重新定义__user_initial_stackheap( )函数,是因为全部的程序都是在SVC模式下运行的,并没有切换到用户或系统模式。
2.实验平台中有32MB的NOR FLASH存储器,起始地址为0x0;有64MB的SDRAM,起始地址为0xa0000000。主要进行以下地址映射:
⑴将高32MB的SDRAM(起始地址为0xa2000000)重映射到0x0地址,因此包括中断向量表在内的映像文件也拷贝到这里;低32MB的SDRAM(0xa0000000开始)不变(虚拟地址和物理地址一致),用于设置堆栈区、初始化运行时RW和ZI区。
⑵将0地址开始的32MB的FLASH存储空间全部重映射到保留地址0x18000000开始的地址空间;
⑶256K内部SRAM(起始地址为0x5c000000),使其虚拟地址和物理地址保持一致,用来保存页表;
⑷其他要使用的地址空间如外围控制寄存器、LCD/USB控制寄存器等,使虚拟地址和物理地址保持一致。
这样,在工程中设置-ro-base = 0x00000000(加载到FLASH),-rw-base = 0xa0000000(低32MB的SDRAM区),指定-entry vector.o(vector)以及-first vector.o(vector),保证中断向量表放在最前面。这样进行地址映射的好处是,如果要将映像文件加载到SDRAM中进行调试,只需要修改-ro-base = 0xa0000000和-rw-base = 0xa1000000(都在低32MB的SDRAM空间),而不需要对源程序做任何修改。
......(图文细节见pdf文档)
至此,程序已经调试成功。在本程序中,进一步完善了启动代码的结构,并成功地将一段SDRAM空间映射到0地址处,同时完成了映像文件(包括中断向量表在内)的拷贝。这样就得到了一个PXA270处理器可以通用的启动代码,对于不同的硬件平台,只要在寄存器和GPIO等文件中改变其定义和初始化值即可;对于不同的实际应用,只要修改主程序dummyOS的内容和功能即可。
下一步的工作,是进一步完善代码结构,增强代码的可移植性和可读性,另外,对于启动过程中的细节进一步细化,包括处理器主频的设定,其他控制器时钟频率的设定,复位时对上电复位的判断(如果不是上电复位而是其他类型的如GPIO复位、硬件复位或看门狗复位等,则直接跳过存储器初始化,建立页表等步骤直接呼叫主程序dummyOS)等;还有就是对I-Cache和D-Cache、Write-Buffer和BTB等功能的使能设置,以提高系统性能。
————————————————抛砖引玉———————————————————
[注]如需转载,请注明作者及出处。