第二季-专题5-核心初始化

专题5-核心初始化

第1课-异常向量表

一.概念解析

  1. 异常定义

因为内部或者外部的一些事,导致处理器停下正在处理的工作,转而出处理这些发生的事件。

  1. 异常类型

Arm处理器有七种异常类型,依次是:重启键,用户自己的命令未识别,软中断,预取指令识别,取数据失败,中断,快速中断。

 

  1. 异常向量

当一种异常发生的时候,ARM处理器会跳转到对应异常的固定地址去执行异常处理程序,而这个固定的地址,就称为异常向量。

  1. 向量表

由七个异常向量以及其处理函数跳转关系组成的表就是异常向量表:

0x00000000:  b   reset

0x00000004:  ldr  pc, _undefined_instruction

0x00000008:  ldr  pc, -software_interrupt

0x0000000c:  ldr  pc, _prefetch_abort

0x00000010:  ldr  pc, _data_abort

0x00000014:  ldr  pc, _not_used

0x00000018:  ldr  pc, _irq

0x0000001c:  ldr  pc, _lrq

二.代码编写

start.s

gboot.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  @使得伪指令变成了装载指令

_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)  //宏定义,输出格式是arm的

ENTRY(_start)     //宏定义,输出程序的入口

SECTIONS {

    . = 0x30008000;  //起始地址

    . = ALIGN(4);    //四字节,对齐的处理

    .text :      //代码段

    {

    start.o (.text)

    *(.text)

    }

    . = ALIGN(4);

    .data :      //数据段

    {

    *(.data)

    }

    . = ALIGN(4);

    bss_start = .;

    .bss :          //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 $^  //通用规则

   

%.o : %.c

    arm-linux-gcc -g -c $^

   

.PHONY: clean

clean:

    rm *.o *.elf *.bin

 

三. 210处理器BL1头信息添加

    我们编写的gboot充当BL1的作用,在210的irom中自带BL0,上电后率先运行的就是BL0,在BL0运行之后会进行一个校验。BL1之前是有16个字节的头的,LB0将BL1拷贝到irom里面后,会通过对BL1的计算,得到校验码。将这个经验吗和在BL1的头中填入的校验码进行比对,若是比对结果一样,BL1可以运行;若是不一样就BL1就不能运行,若BL1之中没有头文件,肯定BL1就不会运行。头文件格式如下:

 

    0x0写的是:BL1的大小;

    0x4没有用到;

    0x8写的是用户写入的校验码大小;

    0xc没有用到。

第2课-设置svc模式

       这一部分不需要做2440、6410和210的区分

 

       这是linux系统的其中工作模式,对于bootloader它的工作模式是supervisor,一种比较高级的工作模式,本节课的重点就是将处理它设置在supervisor模式。具体依靠的是程序状态字寄存器:

 

       0-4字段设置的是工作模式,,将这5个字设置为10011就可以。

步骤:

(1)将这五个字段全部置零:bic

(2)将其中的三个字段置1:orr

(3)为了访问CPSR或者SPSR,需要使用mrs和msr

对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

_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

 

set_svc:

        mrs r0, cpsr  @从cpsr取值

        bic r0, r0, #0x1f

        orr r0, r0, #0xd3  @理论上是#0x13用来表示10011,这里用#0xd3来表示@11010011,设置I和F两位为1,屏蔽了中断与快速中断

        msr cpsr, r0  @将值放在cpsr

        mov pc, lr 

第3课-关闭看门狗

  1. 作用

在嵌入式领域,有些系统需要长期运行在无人看守的环境。在运行的过程中,难免不出现系统死机的情况,这时候需要系统自带的一种自动重启的功能。Watchdaog一般是一个硬件模块,起作用就是在系统死机时,帮助系统实现自动重启。

  1. 工作方式

Watchdaog在在硬件上实现了计时功能,启动计时后,用户(软件)必须在计时结束前重新开始计时,俗称“喂狗”,如果到超时的时候还没有重新开始计时,那么它就认为系统是死机了,就自动重启系统。

  1. 原理图

 

       时钟源经过WTCON[15:8]和WTCON[4:3]分频器的处理,得到我们需要的时钟信号,之后通过WTCNT进行计数,当它检测到0的时候,没有新的WTDAT信号来重置,下面通过WTCON[0]进行重启。

       看门狗有这么好的作用,之所以要关闭看门狗,因为bootloader是一个简单的程序,一般是不需要使用的,使用它会增加“喂狗”的操作,增加系统而定负担。

我们通过寄存器来完成这个操作。

在2440中,寄存器名字为WTCON,如下:

 

 

在6410中,寄存器名字为WTCON,如下:

 

       设置与2440一样。

       在210中的WTCON的地址是0xE2700000,其他设置与2440一样。

  1. 代码实现

修改start.s的下半部分,如下:

reset:

        bl set_svc

        bl disable_watchdog

set_svc:

        mrs r0, cpsr

        bic r0, r0, #0x1f

        orr r0, r0, #0xd3

        msr cpsr, r0

        mov pc, lr

#define pWTCON 0x53000000

disable_watchdog:

        ldr r0, =pWTCON  @把地址装载到r0

        mov r1, #0x0     @mov只能访问通用寄存器,都设置为0

        str r1, [r0]     @将0的值都放在r0中

     mov pc, lr

第4课-关闭中断

步骤:

(1)     在CPSR中将I位(中断位)和F位(快速中断位)设置为1,将它们关闭,这在我们设置svc模式的时候已经设置了#0xd3

(2)    设置中断屏蔽寄存器,把中断屏蔽掉

 

2440:

在s3c2440的芯片手册中,找到下图:

 

       当中断请求前来的时候,会将请求指令记录在SRCPND里面,中断的请求要送到处理器,还要送到MASK寄存器,若将MASK(屏蔽寄存器)屏蔽掉请求信号,就不会有中断操作。在芯片手册的233页找到如下的内容:

 

       这是32位的寄存器,将其中某一位写做1,对应的中断就会被屏蔽,也就是,将所有的位都置1就好了。

代码:

2440,将start.s作如下修改:

reset:

       bl set_svc

       bl disable_watchdog

       bl disable_interrupt

set_svc:

       mrs r0, cpsr

       bic r0, r0,#0x1f

       orr r0, r0,#0xd3

       msr cpsr, r0

       mov pc, lr

#define pWTCON 0x53000000

disable_watchdog:

       ldr r0, =pWTCON

       mov r1, #0x0

       str r1, [r0]

       mov pc, lr

disable_interrupt:

       mvn r1, #0x0  @取反后赋值

       ldr r0, =0x4a000008   @将寄存器地址记录下

       str r1, [r0]         @将值幅值给地址

       mov pc, lr         @返回原位置

6410:

       6410中有两个中断使能寄存器,如下:

 

6410中有两个中断关闭寄存器,如下:

 

代码如下:

reset:

       bl set_svc

       bl disable_watchdog

       bl disable_interrupt

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 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

210:

210与6410类似都是采用向量中断,也分为使能IntEnable寄存器和屏蔽IntEnable寄存器。由于210分为更多功能的中断,它的屏蔽寄存器有4个,保存的地址分别是:

在6410基础上改写的代码是:

disable_interrupt:

       mvn r1,#0x0

       ldr r0,=0xf2000014

       str r1,[r0]

       ldr r0,=0xf2100014

       str r1,[r0]

       ldr r0,=0xf2200014

       str r1,[r0]

       ldr r0,=0xf2300014

       str r1,[r0]

       mov pc, lr

第5课-关闭mmu与cache

  1. ARM存储体系

金字塔顶端是各种寄存器,访问速度快但是数量有限;第二层是TCM,包括内存与cache,数量较多,但速度相对来说慢一些;辅助存储器数量更多,但是访问速度更加缓慢。

 

  1. cache

cache的存储图如下:

 

对比有无cache的访问主内存的方式,有cache的系统对主内存的访问效率更高。

cache是一种容量小但存取速度非常快的存储器,它保存最近用到的存储器中数据的拷贝。对于程序员来说,cache是透明的。它自动决定保存哪些数据、覆盖哪些数据。按照功能划分:

I-Cache: 指令Cache,用于存放指令

D-Cache:数据Cache,用于存放数据

       对于2440的存储结构如下:

 

       其中既有Data Cache有Instruction Cache,它们的大小都是16Kb。210中的连个cache大小是32KB。

  1. 虚拟地址

 

虚拟地址:程序中使用的地址。

物理地址:物理存储单元实际的地址

使用虚拟地址

-可以让进程使用更大的空间

-可以解决冲突

  1. mmu作用

 

       在Arm11之前,根据虚拟地址就可访问cache,但是在Arm11本身包括之后的操作,需要实际的物理地址才能访问cache

  1. 关闭cache和mmu

mmu与cache的使用是需要一系列的配置才能使用的,并不是不用。只是在初始化的时候,必须将它们关闭,控制它们的是协处理器CP15。

2440:

       在920核心手册里面,可以看到CP15有一个control register寄存器,它也是32位的寄存器,12位作用是Icache enable,第2为控制Dcache enable,第0位控制MMU,如下:

 

 

 

       我们还要设置CP15里面的第7个寄存器,使得原本的数据无效,指令是:

MCR p15, 0, Rd, c7, c7, 0

步骤:

(1)     使Icache和Dcache失效

(2)     关闭Icache、Dcache和关闭mmu

修改start.s代码为:

reset:

       bl set_svc

       bl disable_watchdog

       bl disable_interrupt

       bl disable_mmu

disable_mmu:

       mcr p15,0,r0,c7,c7,0     @使Icache和Dcache失效

       mrc p15,0,r0,c1,c0,0     @将寄存器读出来,固定的格式,与下面的配对

       bic r0, r0, #0x00000007  @使得第0和2位置零,12位可以不去处理

       mcr p15,0,r0,c1,c0,0     @将寄存器写进去,固定的格式,与上面的配对

mov pc, lr              @返回主函数的位置,bl将返回地址存在lr寄存器,当程序@运行结束,将返回地址传给pc指针

在6410与210的芯片上,CP15的结构是一样的,不用修改。

原文地址:https://www.cnblogs.com/free-1122/p/11452006.html