U-boot的启动一般分为两个阶段,现在我们先将第一阶段。
在此之前,我们先了解一下uboot的目录结构,各个文件夹是什么作用。
如果连各个文件夹是干什么的都不清楚就开始移植剪裁,势必会和我刚拿到开发板时对着uboot一脸懵逼的情景一样。
所以,我们先看uboot文件夹到底包含了哪些内容:
Board:存放和开发板有关的文件。 U-boot 支持的每个开发板的文件,都会以子
目录的形式存放在 baord 目录下。比如我们关注的 2440 开发板,与之最相近
的目录,便是 SMDK2410 文件夹。或许,您可以将它更名为您自己的文件夹,
比如将 SMDK2410 文件夹更名为 XXX----这样,您可能会更有成就感!
Common:U-Boot 支持的所有命令,都在这个目录中实现。每个命令放在该目
录下的一个文件中。一般情况下,我们如果修改该目录下的文件代码,无非是加
一些调试信息,打开或关闭一些宏。对于该目录下的 C 代码,我们无须大幅度
修改。除非您想自己增加自己的 u-boot 命令----同样也很有成就感哦!
Cpu:这个目录下,存放的是与 cpu 架构有关的目录。每个目录对应一个架构的
cpu。比如我们想移植 ARM9 的 S3C2440,就应该去找 ARM920T 的目录。
其他目录实际上对我们是没有意义的。
Disk:这是要对磁盘的支持。我们只移植 u-boot 的话,那这个对我们也没有意义。
Doc:参考文档的意思,这是最没用的,也是最有用的。推荐想研究 u-boot 的
同学抽时间阅读一下,有好处。
Driver:u-boot 支持的所有的驱动代码,默认是放在这个目录下的。如果您需要
添加自己的驱动代码,也可以放在这里。然后再 makefile 中加入相应的.o 文件
名。
Fs:这个目录下放的是 u-boot 支持的文件系统。目前 u-boot 已经能支持包括cramfs、 fat、 fdos、 jffs2 等文件系统。
Include:这个目录下存放的是头文件。 U-boot 使用的头文件以及对各种硬件平
台的系统配置文件都放在这里。对于每款特定的开发板,我们都需要修改系统配
置文件,它存放在 include 目录下的 configs 子目录中。比如我们研究 2440
的移植,那么可能就对 SMDK2410.h 感兴趣。
Lib_xxx:这是与体系结构相关的库文件。
Net:此目录下存放的代码,是有关网络协议的实现的代码。比如 TFTP 协议的实现就在这里面。
Post:上电自检的目录。该目录,我对此一点都没有研究。
Tools:生成 u-boot 的工具的目录。比如创建 bin 镜像文件等。
韦老师书上:
在知道了这些基础之后,我们就可以开始书写或者移植uboot第一阶段的代码了,其实就是硬件初始化,为第二阶段做好准备。
既然我们要使用的cpu是arm920T构架的s3c2440,那么我们就先看cpu\arm920t目录下的start.S汇编文件。
至于为什么uboot支持那么多cpu,我们编译之后却只对应这个文件夹的这个cpu,是在于我们在之前执行的make 100ask24x0_config操作,配置了uboot支持的单板,这个在我们讲到Makefile的时候再来细说。这里先只用知道,在这个目录下,去看看这个start.S汇编文件对于启动uboot第一阶段干了什么。
一打开start.S文件,我们是既熟悉又陌生,熟悉是在裸机中我们都写过类似的代码了,陌生是,怎么一来就有一个:
.balignl 16,0xdeadbeef
这个指令好像没见过啊,那么我们就来先说说它。
首先,我们在之前的随笔中说到了,在.string "undefined instruction exception"后面,我们加入了一句:
.align 4
这让编译器内存以4对齐。因为.string后的字符串,填充内存不确定,可能会出现字符串填充之后的指令不是位于4的倍数地址处,因为在我们使用的cpu中,是4字节对齐的。如果指令在内存的位置不是4的倍数,那么就将出现问题。
那么这个和上面的.balignl有什么关系呢?
这里要说明,比如现在汇编指令在0x10001001处,后面又有一个arm指令,此时在没有加入.align 4这类代码时,编译器会把下一条指令存放在0x10001000处,向下取4的倍数,在指定了类似.align 4这类代码之后,编译器就会把下一条指令存放在0x10001004处,向上取4的倍数,这个在之前的arm裸机中已经验证过了。
.balign是意思是:以当前地址为开始开始,找到第一次出现的以第一个参数为整数倍的地址,并将其作为结束地址,
在这个结束地址前面存储一个字节长度的数据,存储内容正是第二个参数。如果当前地址正好是第一个参数的倍数,则没有数据被写入到内存。
以此类推,.balignw则表示第二个参数存入的内容长度为2字节:
.balignw 4, 0x368d
因为现在填入的内容为2个字节,那就存在以下几种情况:
1>当前地址没有偏移就满足了以4为倍数的地址
2>当前地址偏移了1个字节就满足了以4为倍数的地址
3>当前地址偏移了2个字节就满足了以4为倍数的地址
4>当前地址编移了3个字节就满足了以4为倍数的地址
分析一下这四种情况:
1>当没有偏移的时候,地址中间肯定没有办法填上信息
2>当偏移1个字节的时候,地址中间空隙不够,所以填入的数值,是末定义,也就是说,填入什么值,不清楚
3>当偏移2个字节的时候,地址中间的空隙正好填入0x368d两个字节的内容
4>当偏移3个字节的时候,地址中间的空隙大于所要填的内容。此时填入的数值,是末定义,填入什么值,不清楚
以此类推,.balignl,这个指令用来填与一个字,即4个字节的长度
这可以看出,我们之前的aling 4,从当前地址取4的倍数(往上取),如果能填充,则填充0.
至少现在,我们知道,.balignl 16,0xdeadbeef是用来保证内存对齐的,0xdeadbeef是填充的数据。其实在这里我们去掉
.balignl 16,0xdeadbeef这个指令也没有关系(因为start.s中前面的指令都是4字节对齐了),但是,为了检测内存,程序员加上了这个。
Hexspeak
Hexspeak与leetspeak一样,是一种使用十六进制数字的变体英语拼写的新颖形式。由程序员创建的令人难忘的魔术数字,十六个字的单词可以作为一个清晰的唯一标识符来标记内存或数据。
十六进制符号表示使用16位0123456789ABCDEF的数字。只使用字母ABCDEF可以拼写几个单词。可以通过将一些十进制数字视为字母来进一步表达 - 数字“ 0 ”可以表示字母“O”,并且“ 1 ”可以表示字母“I”或“L”。不常见的是,“ 5 ”可以表示“S”,“ 7 ”表示“T”,“ 12 ”表示“R”,“ 6 ”或“ 9 ”可以分别表示“G”或“g”。leet或rebuses ; 例如“大便”这个词可以表示为DEFECA7E或DEFEC8。
https://en.wikipedia.org/wiki/Hexspeak*
这种十六进制的英文拼写方式,存在于程序员的世界已经很久了。所以不要再觉得陌生了^_^。
这里deadbeef用于捕获内存错误,但是Start.S中开始的代码都是arm 4字节的指令,所以去掉也没关系,但是既然发现了大牛们的常用术语,就要研究琢磨一番嘛。
之后就开始进入代码阶段了,大部分代码,我们在裸机中已经写过了,所以uboot也是裸机的集大成者。也算是再次复习巩固一下之前的知识。