Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1882835
  • 博文数量: 496
  • 博客积分: 12043
  • 博客等级: 上将
  • 技术积分: 4778
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-27 14:26
文章分类

全部博文(496)

文章存档

2014年(8)

2013年(4)

2012年(181)

2011年(303)

2010年(3)

分类: 嵌入式

2012-06-15 14:01:25

#include

l         config.h这个头文件在u-boot-1.1.6/include/linux目录下,执行命令

# make smdk2410_config之前,内容如下:

 

#ifndef _LINUX_CONFIG_H

#define _LINUX_CONFIG_H

/* #include */

#endif

执行make smdk2410_config之之后,又重新生成,内容为:

/* Automatically generated – do not edit */

#incl? “config/smdk2410.h”

其中config/smdk2410.h这个文件是和开发板密切相关的,里面主要是一些系统各硬件的宏定义与设定,以及条件编译指令,对以后做移植工作至关重要!!

#include

 

l         version.h这个头文件在u-boot-1.1.6/include/下,文件内容为:

#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.hversion_autogenerated.h这两个头文件具体怎么生成的,可以参考顶层 ootMakefile

 

 

.globl _start 

l         这是在定义u-boot的启动定义入口点,汇编程序的缺省入口是 start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。

l         .globalGNU ARM汇编的一个伪操作,声明一个符号可被其他文档引用,相当于声明了一个全局变量,.globl.global相同。该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。

l         为什么是8条指令呢?这里来算一算。首先,一条arm指令为32bit(位),0x0000 0020换算成十进制为2^5=32B(字节),而32B = 4 * 8B = 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、预取终止、数据终止、IRQFIQ等异常,其中U-Boot中关于异常向量的定义如下:

_start:   b       reset   

l         _start 标号表明 oot程序从这里开始执行。

l         b是不带返回的跳转(bl是带返回的跳转),意思是无条件直接跳转到reset标号出执行程序。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         .wordARM汇编特有的伪操作符,语法如下:

.word {,} …

作用:插入一个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的次幂,缺省为4fill是填充内容,缺省用0填充。max是填充字节数最大值,假如填充字节数超过max 就不进行对齐例如:
 
  .align 4 

指定对齐方式为字对齐24次方为16bit),两个字节,即一个字。更详细的解释,可以参阅这篇博客:

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种模式又称为异常模式,即 

FIQFast Interrupt Reqst

IRQInterrupt ReQst

SVCSupervisor

中止(Abort

未定义(Undefined

l         ARM处理器总共有3732位寄存器,可以分为以下两类寄存器 

131个通用寄存器(R0~R15

R0R15

R13_svcR14_svc

R13_abtR14_abt

R13_undR14_und

R13_irqR14_irq

R8_frq-R14_frq

26个状态寄存器

CPSRSPSR_svcSPSR_abtSPSR_undSPSR_irqSPSR_fiq 

 

 

l         但是这32个寄存器不能同时被访问,具体哪些寄存器是可编程访问的,取决于微处理器的工作状态以及具体的运行模式。但在任何时候,通用寄存器R0~R14、程序计数器(R15PC、一个或两个状态寄存器都是可访问的。通用寄存器包括R0~R1531个),可以分为3类:

1未分组寄存器R0~R7

R0~R7是 不分组寄存器。在所有处理器模式下,未分组寄存器都指向同一个物理寄存器,也就是说它们每一个都访问的是同一个物理寄存器,它们未被系统用作特殊的用途。 但必须得注意,未分组寄存器没有被系统用于特别的用途,任何可采用通用寄存器的应用场合都可以使用相同的未分组寄存器,这样可能会造成寄存器中数据的破 坏,所以必须注意对同一寄存器在不同模式下使用时的数据保护。

    2分组寄存器R8~R14

分组寄存器R8-R12

FIQ模式分组寄存器R8~R12

FIQ以外的分组寄存器R8~R12

分组寄存器R13R14

寄存器R13通常用做堆栈指针SP

寄存器R14用作子程序链接寄存器(Link RegisterLR),也称为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。其实,每一种特权模式都各有一组SPLRSPSR。可以看看下面这张图:

 


   

 

 

 

 

 

 

 

l         ARM程序状态寄存器

所有处理器模式下都可以访问当前的程序状态寄存器CPSRCPSR包含条件码标志、中断禁止位、当前处理器模式以及其它状态和控制信息。

在每种异常模式下都有一个对应的物理寄存器——程序状态保存寄存器SPSR。当异常出现时,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。

下面这张图是CPSRSPSR的格式:

 

 

 

 

 

 

 

 

 

 

 

 

 

 


       mrs r0,cpsr   //把当前程序状态寄存器中的数据拷贝给r0

       bic  r0,r0,#0x1f // r00x1f00011111)的反码进行位与,目的是给r0的后5位清零

orr  r0,r0,#0xd3

    /* r00xd3 11010011)进行位或,最后得到r0=11010011

目的是设置r0的后5位为10011,让ARM进入SVC特权模式 */

       msr cpsr,r0

/* 把当前r0中保存的CPU的状态拷贝给cpsr,让ARM进入SVC特权模式 */

 

l         MRS {} Rd, CPSR|SPSR

这条指令的意思是将CPSR|SPSR传送到Rd。我们可以使用这两条指令将状态寄存器传送到一般寄存器,只修改该寄存器必要的位,再将结果传送回状态寄存器,这样能够最好地完成对CRSPSPSR的修改。

MSR {} CPSR_|SPSR_,Rm 或是 MSR {} CPSR_f|SPSR_f,#

 MRSMSR配合使用,作为更新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,是一个定时器电路,一般有一个输入叫喂狗,一个输出叫MCUMicro Controller Unit多点控制单元)的RST端(复位端)。MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给WDTwatchdog 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用于CPUHCLK用于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启动的时候做这件事情。

转移指令,跳转到指令中指定的目的地址,BL 带链接的转移指令,像B相同跳转并把转移后面紧接的一条指令地址保存到链接寄存器LRR14)中,以此来完成子程式的调用。

该语句首先调用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            */

//r3r2做算数减法的目的是计算出 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_LENCFG_GBL_DATA_SIZE在目标板的头文件中定义./u-boot/incl?/configs/smdk2410.h,可以按下面这张图来理解:

所谓重定向后的u-boot

分配IRQFRQ的栈空间

动态内存区长度

全局数据的大小

代码段的开始地址

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段清零

BSSBlock 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),然后禁止MMUcache

 

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

阅读(1844) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~