备注:若本文没有说明,cpu一般当powerpc处理。
cpu 访问nor flash来进行启动。
假设cpu上电后,从0xffff0000启动。但是uboot的链接地址为0xefff0000。然后生成uboot.bin文件
这时一定要注意存储地址、运行地址和编译地址的关系。
1.存储地址,又叫加载地址
即代码存放的位置
2.运行地址(有效地址)
代码运行的地址
3.编译地址(链接地址)
代码通过编译器生成的地址
刚开始汇编时mmu关闭,运行地址=存储地址都在0xffff0000范围
随后mmu打开运行c语言,运行地址=编译地址在0xefff0000范围。
即powerpc nor flash启动时,该开始运行地址不等于编译地址,后来运行到c语言运行地址=编译地址。当uboot从nor flash拷贝到ram后,运行地址=加载地址。
而arm nor flash启动就不同,运行地址根本不等于编译地址。当uboot从nor flash拷贝到ram后,运行地址=编译地址。
uboot.bin内容主要就是指令数据,而某些指令中的标号翻译成了编译地址。下图是flash中的uboot.bin主要内容。
存储地址 编译地址 指令
0xffff0000: 0xefff0000 b reset
0xffff0004: 0xefff0004 ...
0xffff0008: 0xefff0008 reset:
BMS为1时, 系统默认从地址0xFF80 0000 -- 0xFFFF FFFF启动, pc指针指向0xFFF0 0100(即从0xFFF0 0100取第一条指令),从nor flash中读取代码段的第一条代码 b reset。
注意此时的跳转语句,reset是个偏移量,跳转后的地址=pc+reset,跟存储位置没有关系,即位置无关的代码。如果第一句代码换成 ldr pc, = reset。这时跳转后的地址=链接地址(0xefff0000)+reset,肯定是错误的。
uboot分stage1和stage2,其中stage1主要是汇编语言写的,一般与位置无关;而stage2是C语言写的,其中含有很多静态符号表,肯定与位置相关。
ARM使用nor flash启动时一般都是汇编指令,没有用到函数指针和数组等静态符号表。运行c语言的时候已经到sdram。所以在flash中的uboot代码就是位置无关的,在ram中的uboot代码是位置相关的。
但是powerpc是个例外,uboot在nor flash中就已经运行C语言(cpu_init_f中init_laws对law_table初始化),用到了静态符号表,因此在flash中的uboot代码就是位置相关的,这时就要求编译地址和运行c语言时的有效地址相同(在cpu_init_f由于mmu已经开启,所以需要初始化bat表,建立0xefff0000-0xefffffff到0xffff0000-0xffffffff,这时通过运行地址映射成实际地址才能访问flash中的静态符号表)。
顺便说下x86的引导过程
系统启动时CS:IP=0xffff:0x0,cpu再这里执行jump far addr,跳转到BIOS映射的代码段。bios进行主机自检,接下来根据bios设置读取引导驱动器的引导顺序,依次检查直到找到可以引导的驱动器,然后调用驱动器磁盘的引导扇区进行引导。bios将所检查的第一个扇区载入内存,放在内存0x0:0x7c00处。如果扇区最后两个字节是"55 AA",此扇区就是引导扇区。
有了上面的基础,我们讲讲mpc8641是如何启动的
(1) 寻址方式是当前pc值加减偏移量
由于复位时 当BMS = 1,law寄存器默认为0xff800000即cpu core(soc)将EA直接送到local bus的数据总线上。
同时br寄存器给了nor flash片选控制信号,所以cpu可以正常访问nor flash。
b boot_cold ----> bl invalidate_bats----> bl clear_tlbs------>calulate absolute address in Flash and jump there
in_flash--->bl enable_ext_addr(set bat table,build MMU map)----> jump addr_trans_enabled func(turn on MMU)
在enable_ext_addr中我们将0xefff0000至0xefff0000+1M-1映射到0xffff0000至0xffff0000+1M-1(2)mmu开启后代码分析
存储地址 编译地址 指令
0xffff0xx0: 0xefff0xx0 addr_trans_enabled:
0xffff0xx4: 0xefff0xx4 ...
0xffff0xx8: 0xefff0xx8 ...
refi指令的意思是将addr_trans_enabled函数的编译地址赋给了pc计数器。此时我们从0xffff0000的范围变成了0xefff0000,实现了cpu跳转到addr_trans_enabled 函数
开启mmu后,后续的代码所用的地址(cpu使用的地址)均为运行地址范围为0xefff0000至0xefff0000+1M-1,mmu自动将运行地址映射到物理地址。其实外设访问的地址还是0xffff0000至0xffff0000+1M-1,但是代码所用的地址(cpu使用的地址)均为运行地址范围为0xefff0000至0xefff0000+1M-1
按照代码的执行顺序,分析addr_trans_enabled 。
bl l1dcache_enable ------>bl dcache_enable
bl cpu_init_f----------->bl board_init_f
cpu_init_f主要实现local access window的初始化
CPU core是怎么访问SOC上的各个功能模块的?比如eLBC控制器,DDR控制器,PCI控制器等等。通过LAW(Local Access Window)寄存器来配置。每个LAW寄存器将一段地址空间和相应的功能模块连接起来,从core出来的物理地址和各个LAW的地址进行比较,如果在某个LAW指定的地址空间,那么就将这个发送给该LAW指定的功能模块。
详细请参考我的另一篇文章powerpc memory和io访问原理
1. powerpc e600 core,cpu_init_f主要是init_law和setup_bats,根据law表重新初始化BAT寄存器。e600主要通过bat配置Local Access Window
2. powerpc e500 core,cpu_init_f由于没有bat表,只有init_tlb。e500主要通过pte配置Local Access Window
在board_init_f中调用init_func_dram操作DRAM Command Register (这时BAT表已经将CCSBAR映射了)对sdram进行初始化
这里我另外提下sdram这一块,sdram和mmu初始化不是一个概念。
现代的处理器(SoC)或DSP都内建有内存控制器,它是外部SDRAM、FLASH、EEPROM、SRAM等内存的控制接口,BAT和TLB是位于“内存管理单元(MMU)”内部,而SDARM相当于外部内存。至此我也终于明白uboot下cpu_init_f和board_init_f的区别。cpu_init_f是对soc的初始化,而board_init_f是对board的初始化。
首先在enale_ext_addr中,就设置bat,映射了sdram空间
在cpu_init_f中又重新映射了sdram空间,可是直到board_init_f中才对sdram空间进行初始化。
所以初始化之前cpu可以操作那个空间地址,但是sdram控制器根本没有启动。
只有初始化以后cpu才能对sdram访问操作。
在board_init_f中调用relocate_code,就不返回了。
relocate_code在Start.S中定义
存储地址 编译地址 指令
0xffff0xx0: 0xefff0xx0 relocate_code:
0xffff0xx4: 0xefff0xx4 ...
0xffff0xx8: 0xefff0xx8 bl board_init_r
当函数调用后uboot.bin放到了sdram中了
此时存储地址 (加载地址)=有效地址(运行地址)
存储地址 编译地址 指令
0x00000xx0: 0xefff0xx0 addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
0x00000xx4: 0xefff0xx4 mtlr r0
0x00000xx8: 0xefff0xx8 blr
blr功能是将 lr赋值给 PC指针,即实现了跳转,正好为 SDRAM中 in_ram标号的位置。 对于 ppc ,在 SDRAM 中运行的代码由于运行地址(有效地址)和编译地址(链接地址)不一致,对于函数指针 / 数组首地址这些静态符号表必须通过GOT表进行重定位以便能够正确解析相关符号,这里不再细讲了,可以参考我的资源:POWERPC UBOOT.pdf有章关于pic。
既然讲了那么多地址,顺便讲下逻辑地址、线性地址、虚拟地址和物理地址。
一般这么多地址同时出现是因为开启MMU的缘故
虚拟地址顾名思义就是程序产生的有段选择符和段内偏移两部分组成的地址,cpu core使用的地址。
逻辑地址一般指程序产生的段内偏移地址
线性地址是MMU映射过程中的中间地址。
物理地址就是硬件地址,即PA
另见:http://xiatsinggood.blog.163.com/blog/static/20517712620134410573388/
参考:两种实现PPC地址重映射的方案
http://blog.csdn.net/lanmanck/article/details/5304212
从反汇编来看U-boot在PPC架构下的PIC(位置无关程序)设计
http://blog.csdn.net/sailor_8318/article/details/4852691
http://blog.csdn.net/xiaoxiaomuyu2010/article/details/8275091
MPC8314(e300核)uboot调试