start.S进一步、更详细的、深入的解释和分析

转自:http://blog.163.com/kmustchenb@126/blog/static/110905765201092893830876/

#inclde <config.h>

l         config.h这个头文件在u-boot-1.1.6/incl?/linux目录下,执行命令
# make smdk2410_config之前,内容如下:
 
#ifndef _LINUX_CONFIG_H
#define _LINUX_CONFIG_H
/* #incl? <linux/autoconf.h> */
#endif
执行make smdk2410_config之之后,又重新生成,内容为:
/* Automatically generated – do not edit */
#incl? “config/smdk2410.h”
其中config/smdk2410.h这个文件是和开发板密切相关的,里面主要是一些系统各硬件的宏定义与设定,以及条件编译指令,对以后做移植工作至关重要!!
#incl? <version.h>
 
l         version.h这个头文件在u-boot-1.1.6/incl?/下,文件内容为:
#ifndef   __VERSION_H__
#define  __VERSION_H__
#incl? "version_autogenerated.h"
#endif    /* __VERSION_H__ */
version_autogenerated.h这个头文件,在编译的时候会自动生成,内容为:
#define U_BOOT_VERSION “U-BOOT 1.1.6”
 
注:config.h和version_autogenerated.h这两个头文件具体怎么生成的,可以参考顶层 oot的Makefile。
 
 
.globl _start 
l         这是在定义u-boot的启动定义入口点,汇编程序的缺省入口是 start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。
l         .global是GNU ARM汇编的一个伪操作,声明一个符号可被其他文档引用,相当于声明了一个全局变量,.globl和.global相同。该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。
l         为什么是8条指令呢?这里来算一算。首先,一条arm指令为32bit(位),0x0000 0020换算成十进制为2^5=32B(字节),而32(B) = 4 * 8(B) = 4 * 8 * 8( bit),所以刚好8条指令(一个字节Byte包含8个位bit)。
l         为了方便后面的计算,我们可以先熟练换算:
0x0000,0100         256 Byte
0x0000,1000         4KB    256*4*4B
0x0001,0000         64K    4*4*4KB
0x0010,0000         1M     64*4*4KB
0x0100,0000         16M              1*4*4MB
0x1000,0000     256M   16*4*4MB
那么0x8000  就是   8(十进制) X    0x1000 =  32K
0x400000           =  4M
 
 
 
下面是在汇编程序种经常会遇到的异常向量表。Arm处理器一般包括复位、未定义指令、SWI、预取终止、数据终止、IRQ、FIQ等异常,其中U-Boot中关于异常向量的定义如下:
_start:   b       reset   
l         _start 标号表明 oot程序从这里开始执行。
l         b是不带返回的跳转(bl是带返回的跳转),意思是无条件直接跳转到reset标号出执行程序。b是最简单的分支,一旦遇到一个 b 指令,ARM 处理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的 R15 的值的一个偏移量;而不是一个绝对地址。它的值由汇编器来计算,它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位。
       ldr  pc, _undefined_instr tion   //未定义指令
       ldr  pc, _software_interrupt   //软中断SWI
       ldr  pc, _prefetch_abort   //预取终止
       ldr  pc, _data_abort  //数访问终止
       ldr  pc, _not_used
       ldr  pc, _irq    //中断请求IRQ
       ldr  pc, _fiq    //快速中断FIQ
 
_undefined_instr tion:       .word undefined_instr tion
_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
 
l         .word为ARM汇编特有的伪操作符,语法如下:
.word <word1> {,<word2>} …
作用:插入一个32-bit的数据队列。(与armasm中的DCD功能相同)
我们可以使用.word把标识符作为常量使用,例如:
Start:
valOfStart:
.word   Start
这样一来,程序的开头Start便被存入了内存变量valOfStart中。即.word伪操分配了一段字内存单元(分配的单元都是字对齐的),并用伪操作中的Start进行初始化(.long和.int作用与之类似)。
 
       .balignl 16,0xdeadbeef
l         .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。
.align {alignment} {,fill} {,max}
  其中,alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,缺省用0填充。max是填充字节数最大值,假如填充字节数超过max, 就不进行对齐,例如: 
  .align 4 
指定对齐方式为字对齐,2的4次方为16(bit),两个字节,即一个字。更详细的解释,可以参阅这篇博客:
http://zqwt.012.blog.163.com/blog/static/12044684201031102956976/
 
 
/*************************************************************************
* 下面这几句实际上说的是 oot的启动流程
 *************************************************************************
* Startup Code (reset vector)  //启动代码(复位向量)
 * do important init only if we don't start from memory!
* //如果不从ram启,我们就在此做一些重要的初始化
 * relocate armboot to ram //搬运代码到ram中去执行
 * setup stack       //设置堆栈
 * jump to second stage    //跳到第二阶段去执行board.c
*************************************************************************
 */
 
_TEXT_BASE:
       .word    TEXT_BASE
l         TEXT_BASE在开发板相关的目录中的/u-boot-1.1.6/board/smdk2410/config.mk文档中定义, 他定义了代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
 
.globl _armboot_start
_armboot_start:
       .word _start
l         用.globl声明 _armboot_start 并用_start 来进行初始化。在board/u-boot.lds
中定义(是不是在编译的时候定义的???)。
 
l         下面这几行代码是在S3C2410开发板的链接脚本board/u-boot.lds中给出定义的。
声明_bss_start并用__bss_start来初始化,其中__bss_start定义在和板相关的u-boot.lds中。_bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在的地址不是编译时的地址的情况,这里直接取得该标号对应的地址,不受编译时地址的影响. _bss_end也是同样的道理。
 
.globl _bss_start
_bss_start:
       .word __bss_start
 
.globl _bss_end
_bss_end:
       .word _end
 
#ifdef CONFIG_USE_IRQ  //如果定义了CONFIG_USE_IRQ就执行下面的代码
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
       .word    0x0badc0de
 
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
       .word 0x0badc0de
#endif
 
 
/*
 * the act l reset code
 * 复位代码从这里开始执行
 */
 
reset:
 
l         设置CPU的状态类型为SVC特权模式(一共7种权限,这是其中的一种)。
Reset即复位,在系统中经常会用到,该操作是异常处理的第一个操作,其主要目的是设置CPU模式为SVC特权模式。在此,有必要介绍一下ARM处理器的7种工作模式。
 
 
l         CPSR(当前程序状态寄存器)的低5位用于定义当前操作模式,如图示:
 
l         除用户模式外的其他6种模式称为特权模式 。
特权模式中除系统模式以外的5种模式又称为异常模式,即 :
FIQ(Fast Interrupt Reqst)
IRQ(Interrupt ReQst)
SVC(Supervisor)
中止(Abort)
未定义(Undefined)
l         ARM处理器总共有37个32位寄存器,可以分为以下两类寄存器 :
1)31个通用寄存器(R0~R15)
R0~R15;
R13_svc、R14_svc;
R13_abt、R14_abt;
R13_und、R14_und;
R13_irq、R14_irq;
R8_frq-R14_frq。
2)6个状态寄存器
CPSR;SPSR_svc、SPSR_abt、SPSR_und、SPSR_irq和SPSR_fiq 。
 
 
 
 
 
 




l         但是这32个寄存器不能同时被访问,具体哪些寄存器是可编程访问的,取决于微处理器的工作状态以及具体的运行模式。但在任何时候,通用寄存器R0~R14、程序计数器(R15)PC、一个或两个状态寄存器都是可访问的。通用寄存器包括R0~R15(31个),可以分为3类:
1)未分组寄存器R0~R7
R0~R7是不分组寄存器。在所有处理器模式下,未分组寄存器都指向同一个物理寄存器,也就是说它们每一个都访问的是同一个物理寄存器,它们未被系统用作特殊的用途。但必须得注意,未分组寄存器没有被系统用于特别的用途,任何可采用通用寄存器的应用场合都可以使用相同的未分组寄存器,这样可能会造成寄存器中数据的破坏,所以必须注意对同一寄存器在不同模式下使用时的数据保护。
    2)分组寄存器R8~R14
分组寄存器R8-R12:
FIQ模式分组寄存器R8~R12。
FIQ以外的分组寄存器R8~R12。
分组寄存器R13、R14
寄存器R13通常用做堆栈指针SP。
寄存器R14用作子程序链接寄存器(Link Register-LR),也称为LR。
     3)程序计数器R15
寄存器R15被用作程序计数器,也称为PC 。
R15值的改变将引起程序执行顺序的变化,这有可能引起程序执行中出现一些不可预料的结果。
ARM处理器采用多级流水线技术,因此保存在R15的程序地址并不是当前指令的地址。一些指令对于R15的用法有一些特殊的要求。在ARM状态下,R15的位[1:0]为0,位[31:2]用于保存PC;在Thumb状态下R15的位[0]为0,位[31:1]用于保存PC。
l         这里有必要了解一Thumb状态下的寄存器组织
Thumb状态下的寄存器集是ARM状态下寄存器集的子集。程序员可以直接访问8个通用的寄存器(R0~R7),程序计数器PC、堆栈指针SP、连接寄存器LR和当前状态寄存器CPSP。其实,每一种特权模式都各有一组SP,LR和SPSR。可以看看下面这张图:
 




   
 
 
 
 
 
 
 
l         ARM程序状态寄存器
所有处理器模式下都可以访问当前的程序状态寄存器CPSR。CPSR包含条件码标志、中断禁止位、当前处理器模式以及其它状态和控制信息。
在每种异常模式下都有一个对应的物理寄存器——程序状态保存寄存器SPSR。当异常出现时,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。
下面这张图是CPSR和SPSR的格式:
 
 
 
 
 
 
 
 
 
 
 
 
 
 




       mrs r0,cpsr   //把当前程序状态寄存器中的数据拷贝给r0
       bic  r0,r0,#0x1f // r0和0x1f(00011111)的反码进行位与,目的是给r0的后5位清零
orr  r0,r0,#0xd3
    /* r0和0xd3 (11010011)进行位或,最后得到r0=11010011,
* 目的是设置r0的后5位为10011,让ARM进入SVC特权模式 */
       msr cpsr,r0
/* 把当前r0中保存的CPU的状态拷贝给cpsr,让ARM进入SVC特权模式 */
 
l         MRS {} Rd, CPSR|SPSR
这条指令的意思是将CPSR|SPSR传送到Rd。我们可以使用这两条指令将状态寄存器传送到一般寄存器,只修改该寄存器必要的位,再将结果传送回状态寄存器,这样能够最好地完成对CRSP或SPSR的修改。
MSR {} CPSR_|SPSR_,Rm 或是 MSR {} CPSR_f|SPSR_f,#
 MRS和MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分
bic r0,r1,r2  ;r0:=r1 and not r2
orr ro,r1,r2  ;r0:=r1 or r2这几条指令执行完毕后,进入SVC32模式,该模式主要用来处理软件中断(SWI)
 
我们可以在S3C2410x芯片手册中研读这一段文字:
 
THE PROGRAM STATUS REGISTERS
The ARM920T contains a Current Program Status Register(CPSR), plus five Saved Program Status Registers(SPSRs) for use by exception handlers.
ARM920T具有一个当前程序状态寄存器(CPSR),还有5个保存程序状态寄存器(SPSR)供异常处理程序使用。
These register's functions are:
l         Hold information about the most recently performed ALU operation
保存有算术逻辑单元最近的操作
l         Control the enabling and disabling of interrupts
控制着开启和关闭中断
l         Set the processor operating mode
设置处理器的操作模式
图2 Program Status Register Format
 
那么,现在我们很容易理解:11010011 表示CPU禁止任何中断、仍处于arm状态、切换到特权模式
 
 
l         下面这几行代码的作用是定义了一些宏,给寄存器赋值,以后会用到
 
#if defined(CONFIG_S3C2400)
# define pWTCON            0x15300000
# define INTMSK             0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN     0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON            0x53000000
# define INTMSK             0x4A000008 /* Interupt-Controller base addresses */
# define INTS MSK      0x4A00001C
# define CLKDIVN     0x4C000014 /* clock divisor register */
#endif
 
l         这里就是所谓的关闭看门狗。
看门狗即watchdog timer,是一个定时器电路,一般有一个输入叫喂狗,一个输出叫MCU(Micro Controller Unit多点控制单元)的RST端(复位端)。MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给WDT(watchdog timer abbreviation)清零,如果超过规定的时间不喂狗(一般在程序跑飞时,会发生这种情况,此时WDT规定的时间被超过),RST就给出一个复位信号到MCU,然后MCU复位。很明显,看门狗的作用就是防止程序发生死循环,或者说程序跑飞。寄存器具体怎么设置,可以根据S3C2410的用户手册来实现。
 
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
       ldr     r0, =pWTCON   //还是把寄存器pWTCON的地址装载到r0中
       mov     r1, #0x0     //给r1清零
       str     r1, [r0]
/* 把r1中的数据(全0)装载(存储)到寄存器[r0]所包含的有效地址,即给寄存器WTCON清零,目的是关闭看门狗 */
 
l         禁止所有中断
       /*
        * mask all IRQs by setting all bits in the INTMR - default
        */
       mov       r1, #0xffffffff
       ldr  r0, =INTMSK   //是不是把INTMSK的地址0X4A000008存储在r0中
       str  r1, [r0]   //把r1中的数据存储在寄存器[r0]所包含的有效地址,屏蔽所有中断源
 
# if defined(CONFIG_S3C2410)
       ldr  r1, =0x3ff   // 0x3ff =00111111
       ldr  r0, =INTS MSK
       str  r1, [r0]
# endif
这是S3C2410参考手册中列出的中断控制器(Interrupt Controller)表格:
 
 
 
 
l         设置时钟频率
S3C2410用户手册推荐FLCKHCLKPCLK=124,其中FCLK默认是120MHz,通常FCLK用于CPU,HCLK用于AHB总线,PCLK用于APB总线,具体实现如下:
       /* FCLK:HCLK:PCLK = 1:2:4 */
       /* default FCLK is 120 MHz ! */
       ldr  r0, =CLKDIVN
       mov       r1, #3  //0011 HDIVN=1;PDIVN=1
       str  r1, [r0]
#endif   /* CONFIG_S3C2400 || CONFIG_S3C2410 */
 
 
 
 
 
 
 
l         /* we do sys-critical inits only at reboot, not when booting from ram! */
我们只在系统reboot的时候做一些至关重要的系统初始化,而不在从sram启动的时候做这件事情。
B 转移指令,跳转到指令中指定的目的地址,BL 带链接的转移指令,像B相同跳转并把转移后面紧接的一条指令地址保存到链接寄存器LR(R14)中,以此来完成子程式的调用。
该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在LR中,以使得执行完后能够正常返回。
 
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
       bl    cpu_init_crit   //跳转
#endif
 
l         下面这段代码的作用是所谓搬运代码,即重定向
 
#ifndef CONFIG_SKIP_RELOCATE_ OOT
relocate:                           /* relocate U-Boot to RAM      */
       adr r0, _start           /* r0 <- current position of code   */
//_start为当前程序执行的位置(地址)
       ldr  r1, _TEXT_BASE             /* test if we run from flash or RAM */
//_TEXT_BASE为从RAM中开始执行的基地址,其实我们最终
// 要把代码拷贝到_TEXT_BASE上去
       cmp     r0, r1                  /* don't reloc during debug  */
//如果当前程序执行的地址等于从RAM中开始执行的基地址了(该搬运了吧),那么
//跳转到堆栈设置(搬运之前,首先得设置堆栈)
       beq     stack_setup  //先去设置堆栈,再回来搬运代码(重定向)
       ldr  r2, _armboot_start
//_armboot_start 为 oot的起始地址(_armboot_start的值就等于_start)
       ldr  r3, _bss_start
// _bss_start为 oot的结束地址
       s r2, r3, r2              /* r2 <- size of armboot            */
//让r3和r2做算数减法的目的是计算出 oot镜像的大小r2
       add r2, r0, r2              /* r2 <- source end address         */
//r2(_bss_start) = r0(_start)+ r2( oot镜像大小)
 
 
l         这几行代码是一个循环,做的事儿就是所谓的搬运代码
l         这里有条指令ldmia,解释如下:
 
多寄存器传输——数据块操作
 
 
 
 
 
 
多寄存器传输——堆栈操作
 
 
数据块操作和堆栈操作的比较
 
 
 
copy_loop:
       ldmia     r0!, {r3-r10}    /* copy from source address [r0](_start)    */
       stmia     r1!, {r3-r10}         /* copy to   target address [r1](_TEXT_BASE)   */
       cmp     r0, r2                   /* until source end addreee [r2]    */
       ble     copy_loop    //Branch if Less than or Eq l
#endif   /* CONFIG_SKIP_RELOCATE_ OOT */
 
 
l         设置堆栈(设置SDRAM的基地址_TEXT_BASE = 0x33F80000)。
这里需要注意的是堆栈在代码段的下方!宏CFG_MALLOC_LEN和CFG_GBL_DATA_SIZE在目标板的头文件中定义.\u-boot\incl?\configs\smdk2410.h,可以按下面这张图来理解:
所谓重定向后的u-boot
分配IRQ和FRQ的栈空间
动态内存区长度
全局数据的大小
代码段的开始地址
stack_setup:
       ldr  r0, _TEXT_BASE       
/* upper 128 KiB: relocated oot 这句话意思是,_TEXT_BASE上面是128 KiB重定位的u-boot */
s r0, r0, #CFG_MALLOC_LEN  
/* malloc area _TEXT_BASE向下是内存分配空间 */
s r0, r0, #CFG_GBL_DATA_SIZE
/* bdinfo 然后是bdinfo结构体地址空间 */
#ifdef CONFIG_USE_IRQ
       s r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
       s sp, r0, #12         
/* leave 3 words for abort-stack 给堆栈异常留3个字的空间 */
 
l         这里是所谓BSS段清零
BSS(Block Started by Symbol)段是可执行文件中的一种数据段。通常ARM编译器生成的可执行文件由两部分数据组成,分别是代码段和数据段。代码段又分为可执行代码段(text)和只读数据段(rodata);数据段又分为初始化数据段(data)和未初始化数据段(bss)。
clear_bss:
       ldr  r0, _bss_start           /* 找到bss段的开始地址 */
       ldr  r1, _bss_end             /* stop here  */
       mov      r2, #0x00000000        /* clear  */
 
clbss_l:
str   r2, [r0]          /* clear loop...  用一个循环,做清零工作 */
       add r0, r0, #4
       cmp       r0, r1
       ble  clbss_l
 
#if 0
       /* try doing this st? after the relocation */
       ldr     r0, =pWTCON
       mov     r1, #0x0
       str     r1, [r0]
 
       /*
        * mask all IRQs by setting all bits in the INTMR - default
        */
       mov r1, #0xffffffff
       ldr   r0, =INTMR
       str   r1, [r0]
 
       /* FCLK:HCLK:PCLK = 1:2:4 */
       /* default FCLK is 120 MHz ! */
       ldr   r0, =CLKDIVN
       mov r1, #3
       str   r1, [r0]
       /* END st? after relocation */
#endif
 
l         跳转到start_armboot函数入口,_start_armboot保存函数入口指针
       ldr  pc, _start_armboot
_start_armboot: .word start_armboot
/*start_armboot()在lib_arm\board.c中定义,它类似于Linux内核的start_kernel(),它们都是一种系统初始化的接口函数:在start_kernel()中集中完成了内核几乎所有资源的初始化,包括CPU相关的资源和外设接口等;而在start_armboot()中也要完成一些初始化工作。*/
 
/*
 *************************************************************************
 *
 * CPU_init_critical registers
* CPU_init_critical临界区寄存器
* setup important registers
 * setup memory timing
* 此处要设置一些重要的寄存器,并进行内存测试。*/
 *************************************************************************
 */
 
 
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 
l         设置CP15寄存器
 CP15寄存器是系统控制协处理寄存器,用于连接在内存中的也表描述符,此外还用于决定对MMU的操作。设置CP15寄存器的目的是失效Icache(指令cache)和Dcache(数据cache),然后禁止MMU和cache。
 
cpu_init_crit:
       /*
        * flush v4 I/D caches
      使I/D caches失效
        */
       mov       r0, #0
       mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
       mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */
 
       /*
        * disable MMU st? and caches
        */
       mrc p15, 0, r0, c1, c0, 0
       bic  r0, r0, #0x00002300  @ clear bits 13, 9:8 (--V- --RS)
       bic  r0, r0, #0x00000087  @ clear bits 7, 2:0 (B--- -CAM)
       orr  r0, r0, #0x00000002  @ set bit 2 (A) Align
       orr  r0, r0, #0x00001000  @ set bit 12 (I) I-Cache
       mcr p15, 0, r0, c1, c0, 0
 
       /*
        * before relocating, we have to setup RAM timing
      在搬运代码之前,我们必须设置好sram的定时
        * because memory timing is board-dependend, you will
      因为sram定时是依赖于具体的开发板的,你将会    
 * find a lowlevel_init.S in your board directory.
      在自己的开发板目录board目录下发现一个
lowlevel_init.S文件。实际上,这个文件所做的工作主要就是内存的初始化。
        */
 
l         初始化RAM时钟。因为内存时钟是依赖开发板硬件的,所以在board的相应目录下可以找到memsetup.s文件
       mov       ip, lr  //lr为链接寄存器
       bl    lowlevel_init
       mov       lr, ip
       mov       pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
 
/*
 *************************************************************************
 *
 * Interrupt handling 中断处理
 *
 *************************************************************************
 */
 
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE  72
 
#define S_OLD_R0   68
#define S_PSR          64
#define S_PC            60
#define S_LR            56
#define S_SP            52
 
#define S_IP             48
#define S_FP            44
#define S_R10          40
#define S_R9            36
#define S_R8            32
#define S_R7            28
#define S_R6            24
#define S_R5            20
#define S_R4            16
#define S_R3            12
#define S_R2            8
#define S_R1            4
#define S_R0            0
 
#define MODE_SVC 0x13
#define I_BIT     0x80
 
/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */
 
       .macro  bad_save_user_regs
       s sp, sp, #S_FRAME_SIZE
       stmia     sp, {r0 - r12}                     @ Calling r0-r12
       ldr  r2, _armboot_start
       s r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
       s r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
       ldmia     r2, {r2 - r3}                 @ get pc, cpsr
       add r0, sp, #S_FRAME_SIZE         @ restore sp_SVC
 
       add r5, sp, #S_SP
       mov       r1, lr
       stmia     r5, {r0 - r3}                 @ save sp_SVC, lr_SVC, pc, cpsr
       mov       r0, sp
       .endm
 
       .macro  irq_save_user_regs
       s sp, sp, #S_FRAME_SIZE
       stmia     sp, {r0 - r12}                     @ Calling r0-r12
       add     r8, sp, #S_PC
       stmdb   r8, {sp, lr}^                   @ Calling SP, LR
       str     lr, [r8, #0]                    @ Save calling PC
       mrs     r6, spsr
       str     r6, [r8, #4]                    @ Save CPSR
       str     r0, [r8, #8]                    @ Save OLD_R0
       mov       r0, sp
       .endm
 
       .macro  irq_restore_user_regs
       ldmia     sp, {r0 - lr}^               @ Calling r0 - lr
       mov       r0, r0
       ldr  lr, [sp, #S_PC]                  @ Get PC
       add sp, sp, #S_FRAME_SIZE
       s s      pc, lr, #4                     @ return & move spsr_svc into cpsr
       .endm
 
       .macro get_bad_stack
       ldr  r13, _armboot_start        @ setup our mode stack
       s r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
       s r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
 
       str  lr, [r13]                @ save caller lr / spsr
       mrs lr, spsr
       str     lr, [r13, #4]
 
       mov       r13, #MODE_SVC                    @ prepare SVC-Mode
       @ msr   spsr_c, r13
       msr spsr, r13
       mov       lr, pc
       movs     pc, lr
       .endm
 
       .macro get_irq_stack                    @ setup IRQ stack
       ldr  sp, IRQ_STACK_START
       .endm
 
       .macro get_fiq_stack                    @ setup FIQ stack
       ldr  sp, FIQ_STACK_START
       .endm
 
/*
 * exception handlers 中断处理程序
 */
       .align  5
undefined_instr tion:
       get_bad_stack
       bad_save_user_regs
       bl   do_undefined_instr tion
 
       .align     5
software_interrupt:
       get_bad_stack
       bad_save_user_regs
       bl   do_software_interrupt
 
       .align     5
prefetch_abort:
       get_bad_stack
       bad_save_user_regs
       bl   do_prefetch_abort
 
       .align     5
data_abort:
       get_bad_stack
       bad_save_user_regs
       bl   do_data_abort
 
       .align     5
not_used:
       get_bad_stack
       bad_save_user_regs
       bl   do_not_used
 
#ifdef CONFIG_USE_IRQ
 
       .align     5
irq:
       get_irq_stack
       irq_save_user_regs
       bl   do_irq
       irq_restore_user_regs
 
       .align     5
fiq:
       get_fiq_stack
       /* someone ought to write a more effiction fiq_save_user_regs */
       irq_save_user_regs
       bl   do_fiq
       irq_restore_user_regs
 
#else
 
       .align     5
irq:
       get_bad_stack
       bad_save_user_regs
       bl   do_irq
 
       .align     5
fiq:
       get_bad_stack
       bad_save_user_regs
       bl   do_fiq
 
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值