ldr r1, =(INT_BASE | INT_ICMR) /* 通过中断控制器基地址与相关偏移量获得中断屏蔽寄存器的地址*/
ldr r2, =0x0
str r2, [r1]
2. 设置CPU的速度与时钟频率:系统复位后对于CPU的速度与时钟频率都有一个初始的默认值,可以直接使用该值,到内核启动初始化的时候再设置;也可以在此处直接设置。
ldr r1, =CLK_BASE
ldr r2毕业论文http://www.Lwfree.cn_CCCR]
3. SDRAM 的初始化以及使能,这个设置与具体的RAM大小有关,包括正确地设置系统的内存控制器以及各内存库控制寄存器。具体代码稍长,在这里相关代码略去。
相关基本硬件初始化之后,开始设置模式。
1. 为ARM的各个操作模式设置称栈指针:在前面的伪代码中已经为各个操作模式分配相应的栈区,而且ARM各个模式下都有自己通用的栈顶指针SP,现在要做的是在不同模式下将该模式下的SP指向栈顶。每个模式的处理都类似,都是通过设置状态寄存器CPSR(可以参看前面章节的介绍)来完成,并且每个模式都要完成。以IRQ模式为例:
mrs r0, cpsr /* 保存CPSR的值 */
bic r0, r0, #0x1f /* 清楚所有的模式位*/
orr r0, r0, #0x12 /* 将系统设置为IRQ模式*/
msr CPSR_c, r0 /*将改变后的状态值发会给CPSR*/
ldr sp, =(IrqStack + IrqStackSz - 4) /* 设置SP*/
2. 将系统模式设置成监管模式(SVC),并设置SP。
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0x13
msr CPSR_c, r0
ldr sp, =(MonStack + MonStackSz - 4)
到此时,用汇编编写的硬件基本初始化代码完成,对于阶段1来说,剩下的工作就是将镜像2拷贝到SDRAM的指定处,这个工作我们通过一小段C代码来完成,文件名为cstart.c,完成拷贝功能的函数设为cstart。则在汇编末尾可以通过跳转指令进入阶段1的这一小段C代码:
bl cstart
在编译时,本课题将镜像2存放在一个二进制数组umon[ ]之中,具体的编译实现在后面相关篇幅中会有介绍。这样的话,将镜像2拷贝到SDRAM中的实现就比较简单,通过以下代码代码就可以实现:
memcpy((char *)UMON_RAMBASE,(char *)umon,(int)sizeof(umon));
其中,毕业论文http://www.Lwfree.cn
entry = (void(*)())UMON_RAMBASE;
entry();
4.3.2 阶段2的代码实现
本文在阶段2的处理,本文来自优文论文网更多的是对bootloader的功能性的扩展,具体集中在对本文的硬件系统的支持,并在此基础上实现bootloader的两种操作模式。
4.3.2.1 基本功能的实现
基本功能的实现包括加载内核镜像并转让控制权给内核,具体的实现步骤包括:
(1) 前面的存储布局中已经提过,本课题的内核镜像存放在地址0x000c0000处。根据linux内核压缩镜像的构成,离镜像起始的0x24处存放的是一个32位数来标识其身份,因此首先判断(0x000c0000+0x24)处的一个32位数是否等于0x016F2818(标识符)。
(2) 若检查一致,则将位于FLASH中的kernel镜像直接拷入SDRAM中,地址设为0xa0300000,如下:
memcpy(ram_start, (uchar *)KERNEL_FLASH_START, KERNEL_MAX_SIZE)
其中,KERNEL_MAX_SIZE设为1M,ram_start为0xa0300000,KERNEL_FLASH_START为0x000c0000。
(3) 设置启动参数,现今的Linux内核都以链表(tagged list)的形式来传递参数,启动参数以标记ATAG_CORE开始,ATAG_NONE结束。任何bootloader想要传递给kernel的参数都可以添加在在这两个表头与表尾之间。相关的代码如下:
struct tag *params = (struct tag *)BOOT_PARAMS;
params->hdr.size = tag_size(tag_core);
params->hdr.tag = ATAG_CORE;
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next(params);
//如果有参数传递,在此添加
params->hdr.size = 0;
params->hdr.tag = ATAG_NONE;
其中,相关数据结构如下:
struct tag_header {
ulong size;
ulong tag;
};
struct tag {
毕业论文http://www.Lwfree.cnmem;
struct tag_videotext videotext;
struct tag_ramdisk ramdisk;
struct tag_initrd initrd;
struct tag_serialnr serialnr;
struct tag_revision revision;
struct tag_videolfb videolfb;
struct tag_cmdline cmdline;
struct tag_acorn acorn;
struct tag_memclk memclk;
} u;
};
(4) 直接跳转至RAM中的内核镜像的第一条指令执行:
linux_kernel = (void (*)(int, int, struct tag *))ram_start;
linux_kernel(LINUX_ARG0, LINUX_ARG1, tagparams);
其中,三个参数的函数如下:
LINUX_ARG0固定为0;
LINUX_ARG1为表征系统机器类型,要与内核中的一致;
Tagparams为系统传给内核的参数列表的首物理地址。
以汇编角度看,最终这三个参数会对应系统寄存器R0,R1和R2。
4.3.2.2 扩展功能的实现本文来自优文论文网
本文对bootloader的设计决定了实现的bootloader不仅仅起到加载内核镜像这一基本功能,而是把bootloader看作是一个虚拟的小系统,让其对硬件板级系统有更多的支持以为系统开发者提供方便。
(1) 串口的支持
本文将串口的支持放在扩展功能的范畴内,事实上现在一般都已经存在一种共识:bootloader应该串口功能的支持,能够从串口终端正确地收到打印信息。
串口打印信息支持
向串口终端打印信息是一个非常重要而且有效地调试手段。
基于以上的原因,本课题没有通过外界的触发,而是直接在bootloader的阶段2代码中,初始化串口,串口初始化时将其配置成8位数据位、1停止位、无奇偶校验,波特率为115200。此串口使用PXA255内置的FF UART(全功能串口)。
另外在串口的支持代码中,增加相关接收与发送数据应用接口getchar( void )以及putchar(char c)。当要接收数据时,可以通过毕业论文http://www.Lwfree.cn,以达到打印信息的功能。
(2) 下载模式的实现
有了串口的支持,就可以实现下载模式的实现。在基本功能实现的第四个步骤(也就是启动内核)之前,首先使得代码流程延迟一段时间,接着调用串口的接收函数看是否有输入(开发者对应的是键盘输入),如果有数据,则bootloader不加载运行内核镜像,转入等待命令状态;如果没有,则加载运行内核镜像。
udelay(50000); /* 等待用户输入*/
if(getachar())
return; /* 返回之后进入命令行等待状态 */
else{ /* 否则运行内核*/
linux_kernel = (void (*)(int, int, struct tag *))ram_start;
linux_kernel(LINUX_ARG0, LINUX_ARG1, tagparams);}
那么在等待命令状态后,bootloader又如何进行工作呢?
在本文中,定义了一个数据结构monCommand(如下),它主要用来描述一个命令,结构体中,name项指向具体的命令,第二项指向该命令对应的执行函数,最后一项则指向一些帮助文档说明,例如命令的用法等等。
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] 下一页