zoukankan      html  css  js  c++  java
  • 第二季-专题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的结构是一样的,不用修改。

  • 相关阅读:
    设计模式之设计原则
    把二叉树打印成多行
    快速排序的递归遍历和非递归遍历
    二叉树的非递归遍历
    约瑟夫环问题
    strcpy strcat strcmp memcpy函数的自己实现
    【解题模板】一些很基础的板子
    【笔记】取模运算的用法
    【OJ技巧】DSACPP pa-book中的一些提示
    【编程语言】Java基础进阶——面向对象部分
  • 原文地址:https://www.cnblogs.com/free-1122/p/11452006.html
Copyright © 2011-2022 走看看