第一部分:U-Boot概述
Bootloader(引导加载程序)是操作系统运行前执行的第一段程序,其作用是初始化硬件设备,建立内存空间映射表,为最终调用系统内核建立适当的系统软硬件环境.嵌入式系统一般没有通用的Bootloader,不同的系统硬件组成结构对应不同的代码,因而,针对特定的硬件平台,需要对Bootloader进行移植.在嵌入式系统中,常见的引导加载程序有U-Boot,Red Boot和BLOB等.其中U—Boot功能最多,灵活性最强,能够支持PowerPC,ARM,MPIS,X86体系架构的上百种开发板,引导加载Linux,VXWorks,QNX等多种操作系统,有丰富的开发调试文档资料与强大的网络技术支持。我将以自己接触到的MPC8641HPCN开发版上的U-Boot为例,来讨论U-Boot的实现机制!
U-Boot是遵循GPL版权协议的自由软件,具有和Linux源文件相似的目录结构.在相关目录下分别存放不同的源码,这些源码是通过GCC和Makefile组织编译的,可以很方便地在不同的硬件平台上进行移植.顶层目录下的Makefile设置各类开发板的定义,递归地调用各级子目录下的Makefile,源码结构可查看顶层目录下的readme文件。
关于U-Boot的详细信息参考:http://www.denx.de/wiki/U-Boot
各个版本的U-Boot的下载网址:http://ftp.denx.de/pub/u-boot/
从2008年末开始,U-Boot的按照固定的时间间隔发布新的版本,大概是每隔3个月一个版本,版本名称采用YYYY.MM(即年.月)的格式。例如我讨论的U-Boot版本是u-boot-2010.09.tar.bz2
之所以选这个版本,没有别的意思,仅仅是喜欢而已。大家如果发现我的分析有什么问题,
请给我留言或者email:cwsun@mail.ustc.edu.cn。
第二部分 基于MPC8641HPCN开发板的Uboot编译
利用我建立的基于PowerPC的交叉编译器(
参考:http://blog.sina.com.cn/s/blog_70dd16910100y7vj.html)来编译基于MPC8641HPCN开发板上UBoot,由于u-boot-2010.09版本已经包含支持MPC8641HPCN的源码,这个编译过程非常简单,只要使用以下命令即可:
$tar xvf u-boot-2010.09.tar.bz2
$make CROSS_COMPILE=powerpc-tom-linux-gnu- MPC8641HPCN_config
$make CROSS_COMPILE=powerpc-tom-linux-gnu-
备注:下面的叙述我不加注释的话,默认的都是在u-boot-2010.09目录中。
编译完的效果如下:
然后把u-boot.bin烧写到基于MPC8641HPCN的模拟器上来加载我们编译的Linux-2.6.38-smp内核映象,示意图如下:


备注:在include/config/包含着U-Boot版本所支持的各个开发板的配置文件,这些配置文件定义了CPU的体系结构、外围设备的配置信息、内存映射、以及U-Boot的功能定制等等。它们都是一个供参考的范本,我们可以参考README文件获取更多这方面的信息。
由于我选择的这个U-Boot版本已经支持MPC8641HPCN开发板,所以在include/config/目录下存在MPC8641HPCN.h文件。这因为如此,我才可以不对U-Boot源码做任何修改就可以用上述的命令进行编译。
另外我的交叉编译器自己编译的,建立的过程在我的博文中已经相信的说明,这里就不在赘述。
第三部分 基于MPC8641d的U-Boot的源码分析
3.1 MPC8641d上电后从OxFFF00100物理地址处执行指令
当MPC8641d上电或者施加复位信号时,CPU通过读取硬复位配置信号,启动Local bus存储控制器CS0#(对应于Flash的片选信号)有效,选中Flash,CPU地址线上输出硬件复位中断向量对应的地址OxFFF00100,开始读第l条指令,从
board/freescale/mpc8641hpcn/ u-boot.lds链接脚本文件可以看到,这条指令对
应于arch/powerpc/cpu/mpc86xx/start.S中的_start: 标号处.下面我们将介绍uboot启动过程中的几个关键函数和文件:
关于u-boot.lds文件的分析可以参考:基于MPC8641d的U-Boot的GOT表分析和u-boot.lds解读
具体代码如下:
_start:
boot_cold:
boot_warm:
1:
#ifdef CONFIG_SYS_L2
#endif
in_flash:
代码解释:
<1>: b
U-Boot规定了两种启动方式:
第一种:系统上电启动U-Boot(我们称之为冷启动),把冷启动标签BOOTFLAG_COLD放入通用寄存器r21,CPU从boot_cold:标签处执行;
第二种:软件重启U-boot(我们称之为暖启动),把暖启动标签BOOTFLAG_WARM放入通用寄存器r21,CPU从_start_warm:标签处执行;
备注:BOOTFLAG_COLD和BOOTFLAG_WARM在include/configs/MPC8641HPCN.h文件中定义,代码如下:
#define BOOTFLAG_COLD
#define BOOTFLAG_WARM
<2>:bl
执行invalidate_bats函数,该函数比较简单目的就是把E600内核的8组BAT寄存器IBATxU/DBATxL(x=0至7)的内容全部初始化为0,具体代码如下:
invalidate_bats:
<3>: bl
调用clean_tlbs清空tlb表,clear_tlbs的具体代码如下:
clear_tlbs:
tlblp:
解释;
<3,1>:r3指向TLB表的首地址
<3,2>:r5执行TLB表的末地址
<3,3>:TLB表示256KB,其中每一个页表是4KB,所以<3,1>使用tlbie指令循环了64次,让TLB表中的64个页表均为无效。
备注:
tlbie r3:r3寄存器所指向的页表项如果在TLB快表中,就将这个页表项从TLB中移除(即使得TLB中这个页表项无效)。
有一个注意疑问:从上面的代码中我们可以看出TLB是256K包含64个页表,但是我们查看MPC8641d的芯片手册,E600包含ITLBDTLB,每个均为512K,包含256个页表。所以上面的初始化E600内核中ITLB和DTLB的前64个页表,并没有把TLB的所有内容均初始化。这是一个bug吗???!!!
<4> lis
解释:
l2cr寄存器是L2 Cache控制寄存器(L2 Cache Control Register),它的第0位控制着L2 Cache的开启和关闭。
L2_INIT在include/configs/MPC8641HPCN.h文件中定义为0,所以上述汇编指令的作用就是关闭L2 Cache
<5>:bl
解释:在L2 Cache已经关闭的情况下,调用l2cache_invalidate函数来清空L2 Cache中的内容,具体代码如下:
_GLOBAL(l2cache_invalidate)
#ifdef
#endif
1:
invl2:
解释:
<5,1>:通过测试l2cr寄存器的第0位来核实L2 Cache是否关闭,如果没有关闭,紧接着的指令来关闭L2 Cache,如果已经关闭了,就跳转到<5,2>;
<5,2>:设置l2cr寄存器的第10位,使得L2 Cache的内容无效,也就是清空L2 Cache;
<5,3>:核实是否已经清空L2 Cache,如果没有清空的话,就陷入无限的死循环,O(∩_∩)O~
<6>:
解释:
CONFIG_SYS_MONITOR_BASE_EARLY在include/configs/MPC8641HPCN.h定义为:
#define CONFIG_SYS_MONITOR_BASE_EARLY
在include/mpc86xx.h中EXC_OFF_SYS_RESET定义如下:
#define EXC_OFF_SYS_RESET
#define _START_OFFSET
<6,1>:把CONFIG_SYS_MONITOR_BASE_EARLY,即0xfff0 0000赋值给r3寄存器
<6,2>: in_flash - _start计算得到的是in_flash:标签在U-Boot的_start函数中的偏移地址,这个偏移在我们的MPC8641HPCN中为0x1f38。
所以in_flash - _start + EXC_OFF_SYS_RESET的值为0x2038;
进而我们可以得到in_flash标签的运行地址为0xfff0 0000 + 0x2038 = 0xfff0 2038,示意图如下:
我们把计算得到的in_flash标签的运行地址0xfff0 2038放入lr寄存器,然后通过指令:
转到in_flash:标签处运行。
in_flash:
<7> bl
解释:enable_ext_addr的作用就是通过设置E600中HID0(Hardware Implementation-Dependent Register 0)寄存器中的HIGH_BAT_EN、XAEN以及XBSEN位来开启4组IBATs (4–7) 和4组 DBATs (4–7)、开启扩展的块地址映射机制、以及开启32位的有效地址到36物理地址映射。
备注:我们在讨论MPC8641HPCN上Linux的启动过程中介绍过32为块地址映射块的尺寸最大只有256G,在E600的块地址映射经过扩展之后,块的尺寸可以达到512G,1G,2G以及4G的空间。
enable_ext_addr的汇编指令如下:
enable_ext_addr:
<8>: bl
early_bats函数的汇编序列如下:、
early_bats:
#if(CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
#endif
待续。。。。。。。。。。。。。。。。。
本文深入探讨了U-Boot在MPC8641HPCN开发板上的启动过程,包括上电后的初始指令执行、关键函数分析及硬件资源初始化等步骤。


1730

被折叠的 条评论
为什么被折叠?



