说明:本文为作者自己在初学uboot过程中对相关知识的一些汇总,学习建立在前人经验的基础上,作此总结只为让自己印象深刻一些,可能会有偏差之处,待以后学习深入,再行更正。
uboot启动分为两个阶段:
第一阶段:主要是汇编程序
第一阶段的代码在汇编文件start.S中,该文件位于u-boot-0.2.0\cpu\arm920t目录下。
主要工作内容包括:
1、硬件设备初始化
2、关闭看门狗(防止CPU不断重启)(向看门狗控制寄存器写0)
3、屏蔽中断(向INTMSK寄存器中写入0xffffffff)
4、设置stack(第二阶段代码为C代码,必须用到栈)(将sp指针指向一段没有被使用的内存即可完成栈的设置)
5、将第二阶段启动代码由flash搬移到RAM中(如果代码直接在RAM中执行,则不需要进行此步骤)
6、跳转到第二阶段启动代码
具体内容包括:设置异常向量、CPU进入SVC模式(管理模式)、设置控制寄存器地址、关闭看门狗、屏蔽中断、设置时钟、将第二阶段代码搬移到RAM中、关闭MMU和cache。
第二阶段:主要是C程序
第二阶段代码的入口是board.c文件中的start_armboot函数,board.c文件位于u-boot-0.2.0\lib_arm目录下。
主要工作内容包括:
1、初始化本阶段用到的硬件设备
2、检测内存映射(逻辑地址→线性地址(启用分页机制)→物理地址;逻辑地址→物理地址(未启用分页机制))
3、将内核从flash搬移到RAM中(内核也可以在flash中运行,但速度很慢)
4、设置内核启动参数(以标记列表tagged list的形式传递参数,通过gd_t、bd_t结构体中的信息设置标记列表)
5、调用内核(theKernel(0,machid,bi->bi_boot_params)函数)
uboot使用命令bootm启动加载到内存中的内核,bootm命令会调用do_bootm函数,在Linux系统中,do_bootm函数会继续调用do_bootm_linux函数来设置标记列表和启动内核。
以上为内核启动的简单过程的总结,用以加深印象。
以下为uboot代码中的一些知识点,总结以加深印象:
1、.伪操作符baligal
在机器码中并没有汇编指令与其对应,是由编译器来实现其功能。
意思是:以当前地址为开始,找到第一次出现的以第一个参数为整数倍的地址,并将其作为结束地址,在这个结束地址前面存储一个字节长度的数据,存储内容正是第二个参数。如果当前地址正好是第一个参数的倍数,则没有数据被写入内存。
2、INTMSK和INTSUBMSK
主中断屏蔽寄存器和副中断屏蔽寄存器,这两个寄存器各个位分别与SRCPND和SUBSRCPND对应。它们的作用是决定该位对应的中断请求是否被处理。若某位被置为1,则该位对应的中断产生后被忽略,即CPU不处理该中断请求,置为0,则处理该中断请求。SRCPND和SUBSRCPND分别代表不同的中断源。
3、主机字节序和网络字节序
不同的CPU有不同的字节序类型,字节序是指整数在内存中保存的顺序,这个叫做主机序,常见的有两种:Little Endian和Big Endian。
(1)Little Endian:将低序字节存储在起始地址;
(2)Big Endian:将高序地址存储在起始地址;
例如,将0x12345678写入0x0000开始的内存中,结果如下:
地址 BE LE
0x0000 0x78 0x12
0x0001 0x56 0x34
0x0002 0x34 0x56
0x0003 0x12 0x78
网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用Big Endian排序方式。
为了进行转换BSD Socket提供了转换的函数,有以下四种:
(1)htons:把unsigned short类型从主机序转到网络序;
(2)htonl:把unsigned long类型从主机序转到网络序;
(3)ntohs:把unsigned short类型从网络序转到主机序;
(4)ntohl:把unsigned long类型从网络序转到主机序;
以上的转换函数中:h=host;n=network;s=short;l=long;
在使用Little Endian的系统中,这些函数会把字节序进行转换;
在使用Big Endian的系统中,这些函数会被定义成空宏;
暂时汇总至此!