1、异常的定义
异常:因为内部或者外部的一些事件,导致处理器停下正在处理的工作,转而去处理这些发生的事情。
2、异常的类型
ARM处理器有7种Exception type分别为:Reset、Undefined instructions、Software interrupt、Prefetch Abort、Data Abort、IRQ、FIQ
2、什么是异常向量
当一种异常发生的时候,ARM处理器会跳转到对应该异常的固定地址去执行异常处理程序,而这个固定的地址,就称为异常向量。
3、异常向量表
由七个异常向量及其处理函数跳转关系组成的表为异常向量表。
下面是一个例子:
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, _irq ldr pc, _fiq _undefined_instruction: .word 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: nop
gboot.lds
OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS{ . = 0x50008000; . = ALIGN(4); .text : { start.o(.text) *(.text) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); bss_start = .; .bss : { *(.bss) } bss_end = .; }
Makefile
all : start.o arm-linux-ld -Tgboot.lds -o gboot.elf $^ arm-linux-objcopy -O binary gboot.elf gboot.bin %.o : %.S arm-linux-gcc -g -c %.S %.o : %.c arm-linux-gcc -g -c %.c .PHONY: clean clean: rm *.o *.elf *.bin关于异常向量表,对于2440和6410以上就结束了,不过对于210还要添加BL1头
./mkv210_image led.bin 210.bin
/home/dnw 210.bin 0x50008000
如果不加头的话,就无法正常工作。原因是210在上电后会运行厂家已经固化在SRAM中的BL0,这个时候,由BL0来调用BL1,BL1运行会产生校验码(这个校验码就在添加的头里面)并与BL0里的校验码进行比对,确认是否为要运行的BL1。成功后就运行BL1.
Header Info (check sum(user writing)、BL1 size(user writing)).
二、设置SVC模式
此时设置ARM的工作模式为SVC(supervisor),这样可以使用更多的寄存器,同时拥有很大的操作权限。具体可以参考下图
通过上图对ARM的状态寄存器的解释,我们可以得知将CPSR的后五位设置为0b10011就可以使用SVC模式。同时我们还要关闭irq和fiq。
具体实现代码:
续上start.S
reset: bl set_svc set_svc: mrs r0, cpsr bic r0, r0, #ox1f orr r0, r0, #oxd3 msr cpsr, r0
三、关闭看门狗
1、什么是看门狗
有些嵌入式设备要长期工作在无人看管的情况下,这个时候就需要,当发生死机时,设备可以实现自启动。而watchdog就可以完成这样一种功能。watchdog模块是一硬件设备。其作用就是当系统发生死机时,帮助系统实现自启动。
2、看门狗如何工作
看门狗模块有三部分组成,分别为时钟产生器,计时器,重启器。当开启看门狗时,计时器就开始了计时,系统必须在计时结束前对看门狗重新设置使其重新计时,简称喂狗。否则它会认为系统发生了死机,就重启系统。
3、为什么要关闭看门狗
一般情况下,bootloader的运行过程中不会发生死机,所以我们就关闭看门狗。否则我们还要不断的喂狗,而占用系统时间。
下面是6410中的watchdog的解释
代码编写:
reset: bl set_svc bl disable_watchdog set_svc: mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0 #define pWTCON 0x7E004000 disable_watchdog: ldr r0, =pWTCON /*mov的操作数最多为8位*/ mov r1, #0x0 str r1, [r0]注:我们这里把watchdog的控制寄存器直接清零,也可以达到效果。
四、关闭中断
关闭中断要两个环节:1、CPSR中的I F位 置1,在设置SVC时我们已经做过,所以这里就不做了。2、对中断屏蔽寄存器进行设置
2440的板子需要设置INTMSK寄存器
210的板子需要设置4组寄存器VICINTENCLEAR
6410的板子需要设置2组寄存器VIC0INTENCLEAR和VIC1INTENCLEAR
下面我们以6410为例子进行介绍:
编码如下
disable_interrupt: mvn r1, #0x0 ldr r0, =0x71200014 str r1, [r0] ldr r0, =0x71300014 str r1, [r0]
五、关闭MMU和Cache
1、前言
从ARM的存储体系,我们可以看到,位于金子塔顶端的是处理器的寄存器,后面依次为TCM和辅助存储器。显然从金子塔的底部到顶部存储器的存取速度愈来愈快,价格也越来越高,而数量却越来越少。
2、什么是Cache
我们都知道处理器的访问速度是非常快的,而内存的速度却慢的很。这样当处理器在访问内存时就出现了问题。而Cache恰恰就用来解决这个问题。从物理结构上来讲,Cache位于处理器与内存之间,cache中存储了处理器经常从内存访问的数据与指令,也就是cache是内存的部分拷贝。这时处理器往往先访问cache,如果cache中没有想要的数据,才去内存查找。而cache的访问速度要比内存大的多,这样就提高了整个的运行效率。
cache又分为:I-Cache和D-Cache
3、MMU
谈到MMU这个时候就要先说一下虚拟地址:作为一个程序员,大家都知道有逻辑地址和物理地址之分,如果我们不直接和硬件打交道,我们根本不用去管物理地址,只要用逻辑地址就可以了。而MMU就是把逻辑地址转换为物理地址的协议。
假如我们只使用物理地址就会出现两个问题要解决:1、地址冲突(两段程序使用同一物理地址)。2、范围小
我们使用了MMU就可以把逻辑地址映射到物理地址,再具体的说就是两段程序使用的是同一逻辑地址,而经过映射后,它们都被映射到不同的物理地址。还有就是地址空间变大了。具体的物理地址的分配不用程序员来管,都要MMU来分配,这样就可以更好的利用物理空间。
ARM11之间Cache位于MMU前面靠近处理器,也就是说cache使用的是虚拟地址(逻辑地址),而ARM11之后包括ARM11的MMU靠近内存,这个时候使用的是物理地址。
4、为什么要关闭MMU和Cache
MMU和Cache在使用之前要进行配置,在ARM初始化的时候还没有进行配置,所以这个时候要关闭它们。还有就是避免Bootloader将linux内核下载到D-cache中,而I-cache这个时候可以不管它。
关闭MMU和Cache的步骤:
1、使I-cache和D-cache失效
2、关闭I-Cache和D-Cache,关闭MMU
下面是cp15的寄存器解释:
代码如下:
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
2440、6410和210的cp15是一样的。所以这里的代码也是一样的。
整个核心初始化的代码为:
.text .global _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word 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 bl disable_mmu set_svc: mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0 mov pc, lr #define pWTCON 0x7E004000 disable_watchdog: ldr r0, =pWTCON /*mov的操作数最多为8位*/ mov r1, #0x0 str r1, [r0] mov pc, lr disable_interrupt: mvn r1, #0x0 ldr r0, =0x71200014 str r1, [r0] ldr r0, =0x71300014 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
上一篇:ARM裸机开发bootloader—点亮LED灯
下一篇:ARM裸机开发bootloader代码搬移从SRAM到DRAM
推荐阅读最新更新时间:2024-03-16 14:56