初始化异常向量表:
异常:因为外部或内部一些事件,导致处理器停下正在处理的工作,转而处理这些发生的事件。共七种异常:reset,undefined instructions, Software Interruption(SWI),Prefetch Abort,Data Absort,IRQ,FIQ。当一种异常发生,ARM处理器会跳转到对应该异常的固定地址去执行异常程序,而这个固定地址就是异常向量。
由七个异常向量及其处理函数跳转关系组成的表即为异常向量表:
关闭看门狗:
Watchdog:在硬件上实现定时器的功能,当启动后系统要在计时结束之前重新对计时器计时, 当系统死机时候能感知到事情的发生,然后重启系统,
左边PCLK经过分频操作后输出的就是定时器的时钟,中间是计数的逻辑,一旦开始计数之后,每个时钟WTCNT就会减一,减到0时WTDAT还没有设置新的值,他就认为系统死机,后面就会产生重启信号,让CPU重启。
关闭中断:
中断处理过程:当中断产生之后,寄存器SRCPND记录中断产生的请求状态,通过mask屏蔽寄存器设置要屏蔽的中断请求,下面就通过mask屏蔽中断请求,最终不会送到处理器。
关闭mmu和cache:
ARM存储体系,顶端:CPU内部寄存器,访问速度快,数量太少。中间:紧耦合存储器(cache,主存储器)。下层:辅助存储器(nandflash, SD卡)。
上面为没有使用cache的系统,CPU直接访问主存储器,由于两者间速度巨大区别导致CPU访问低效率,为了改善这个情况,引入cache相比内存访问速度更快,cache存放的是主存储区一些数据的拷贝,当CPU访问主存找数据时,CPU会根据地址在cache里找有无这块数据,如果没有主存会把数据传给CPU,还会把数据放入cache,第二次再访问数据时,cache里已有数据拷贝,不会在访问慢的主存,直接从cache取走数据。
cache是容量小但访问速度快的存储器,他保存最近用到存储器数据的拷贝。I-Cache指令cache用于存放指令。D-Cache,数据cache,存放数据。
虚拟地址:1:比如Linux有多个应用程序,都要用到同一个物理地址造成地址冲突。2:仅仅使用物理地址范围只有64M,使用地址范围较小。引入虚拟地址后多个应用程序使用同一个地址为虚拟地址,但是经过硬件的映射能够把相同的虚拟地址映射到不同地方,有效解决冲突问题。空间变大了,任何应用访问的虚拟地址空间都是4G,真正使用的时候才映射,使进程使用更大的地址空间。mmu完成虚拟地址到物理地址的映射,要使用mmu需要一个正常的配置,才能正确的使用mmu,但是在进行arm初始化时还没有配置好mmu,不能使用否则导致错误发生,在初始化阶段暂时关掉,mmu和cache都通过cp15协处理器控制。
//2440 , 6410版本
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
下面编写三个部分的代码:
Start.s uboot.lds makefile
// Start.S
.text ; 指明代码段
_global _start ;声明全局
_start: ;程序入口
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc,_prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
//在_undefined_instruction处存储_undefined_instruction大小为_undefined_instruction地址。
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
undefined_instruction:
nop
software_interrupt:
nop
prefetch_abort:
nop
data_abort:
nop
not_used:
nop
irq:
nop
fiq:
nop
reset:
bl set_svc
bl disable_watchdog ;关闭看门狗
bl disable_interrupt ;屏蔽中断,往INTMSK全部写入1
bl diable_mmu
mov pc, lr
set_svc: ;设置为svc工作模式
mrs r0, cpsr
bic r0, r0, #0x1f ;第二操作数哪些位为1,第一操作数哪些就清除
orr r0, r0, #0x13
msr cpsr , r0
mov pc, lr
#define pwTCON 0x53000000
disable_watchdog: ;通过WTCON控制看门狗
ldr r0, =pwTCON
mov r1, 0x0
str r1, [r0]
mov pc, lr
disable_interrupt:
mov r1, #0x0
ldr r0, =0x40000008
str r1, [r0]
mov pc, lr
disable_mmu:
mcr p15, 0, r0, c7, c7, 0
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, 0x00000007
mcr p15, 0, r0, c1, c0, 0
mov pc, lr
uboot.lds链接器脚本,整个程序的构成将根据链接器脚本。
//uboot.lds
OUTPUT_ARCH(arm) ;指明输出格式
ENTRY (_start) ;输出程序的入口
SECTIONS {
. = 0x30008000 ;整个程序链接起始地址
. = ALIGN(4) ;4字节对齐
.text : ;代码段
{
start.o (.text)
*(.text)
}
. = ALIGN(4); ;4字节对齐
.data :
{
*(.data)
}
. = ALIGN(4); ;4字节对齐
bss_start = .; ;记录bss开始结束
.bss :
{
*(.bss)
}
bss_end = .;
}
//编写makefile,makefile由一条条规则构成,首先创建两条通用规则
all : start.o
arm-linux-ld -Tuboot.lds -o uboot.elf $^
Arm-linux-objcopy -O -bin uboot.elf uboot.bin
%.o = %.s
arm-linux-gcc -o -c $^
%.o = %.s
arm-linux-gcc -g -c $^