`
emowuyi
  • 浏览: 1477473 次
文章分类
社区版块
存档分类
最新评论

u-boot分析(一)

 
阅读更多

一、bootloader的概念

简单的说,bootloader就是在操作系统运行之前运行的一段小程序,通过这段小程序,我们可以初始化硬件设备,简历内存空间映射图,从而将系统的软硬件环境带到一个合适的的状态,一边最终调用操作系统内核准备好正确的环境。

通常,bootloader是严重的依赖于硬件而实现的,特别在嵌入式世界,建立一个通用的bootloader几乎是不可能的,尽管如此,我们仍然可以对bootloader归纳出一些通用的概念来,以指导用户特定的bootloader设计与实现。

当然,在arm7与arm9的开发应用中,也有许多是不需要linux操作系统的,而是直接开发裸机的代码,别以为就不要bootloader了,反而可以利用bootloader加快裸机的开发,应用在bootloader运行后,比如u-boot,基本上支持所有的外设,可以说uboot就是一个小型的操作系统,裸机代码可以直接建立在uboot之上,有兴趣可以做一些这样的开发。不在本文的讨论范围。

二、bootloader的分层

通常多阶段的 Boot Loader 能提供更为复杂的功能,以及更好的可移植性。从固态存储设备上启动的 Boot Loader 大多都是 2 阶段的启动过程,也即启动过程可以分为 stage 1 和 stage 2 两部分。由于 Boot Loader 的实现依赖于 CPU 的体系结构,因此大多数 Boot Loader 都分为 stage1 和 stage2 两大部分。依赖于 CPU 体系结构的代码,比如设备初始化代码等,通常都放在 stage1 中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而 stage2 则通常用C语言来实现,这样可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。熟知的uboot就是分为stage1与stage2.

三、bootloader的主要任务与典型结构框架

Boot Loader 的 stage1 通常包括以下步骤(以执行的先后顺序):

  • 硬件设备初始化。

  • 为加载 Boot Loader 的 stage2 准备 RAM 空间。

  • 拷贝 Boot Loader 的 stage2 到 RAM 空间中。

  • 设置好堆栈。

  • 跳转到 stage2 的 C 入口点。

Boot Loader 的 stage2 通常包括以下步骤(以执行的先后顺序):

  • 初始化本阶段要使用到的硬件设备。

  • 检测系统内存映射(memory map)。

  • 将 kernel 映像和根文件系统映像从 flash 上读到 RAM 空间中。

  • 为内核设置启动参数。

  • 调用内核。
四、stage1

(1)基本的硬件初始化

这是 Boot Loader 一开始就执行的操作,其目的是为 stage2 的执行以及随后的 kernel 的执行准备好一些基本的硬件环境。它通常包括以下步骤(以执行的先后顺序):

1.屏蔽所有的中断。为中断提供服务通常是 OS 设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。中断屏蔽可以通过写 CPU 的中断屏蔽寄存器或状态寄存器(比如 ARM 的 CPSR 寄存器)来完成。

2.设置 CPU 的速度和时钟频率。

3.RAM 初始化。包括正确地设置系统的内存控制器的功能寄存器以及各内存库控制寄存器等。

4.初始化 LED。典型地,通过 GPIO 来驱动 LED,其目的是表明系统的状态是 OK 还是 Error。如果板子上没有 LED,那么也可以通过初始化 UART 向串口打印 Boot Loader 的 Logo 字符信息来完成这一点。

5.关闭 CPU 内部指令/数据 cache。


(2)为加载 stage2 准备 RAM 空间

为了获得更快的执行速度,通常把 stage2 加载到 RAM 空间中来执行,因此必须为加载 Boot Loader 的 stage2 准备好一段可用的 RAM 空间范围。

(3) 拷贝 stage2 到 RAM 中

拷贝时要确定两点:(1) stage2 的可执行映象在固态存储设备的存放起始地址和终止地址;(2) RAM 空间的起始地址。

(4)设置堆栈指针 sp

堆栈指针的设置是为了执行 C 语言代码作好准备。通常我们可以把 sp 的值设置为(stage2_end-4),也即在 3.1.2 节所安排的那个 1MB 的 RAM 空间的最顶端(堆栈向下生长)。

此外,在设置堆栈指针 sp 之前,也可以关闭 led 灯,以提示用户我们准备跳转到 stage2。

经过上述这些执行步骤后,系统的物理内存布局应该如下图2所示。

(5) 跳转到 stage2 的 C 入口点

在上述一切都就绪后,就可以跳转到 Boot Loader 的 stage2 去执行了。比如,在 ARM 系统中,这可以通过修改 PC 寄存器为合适的地址来实现。

五、stage2

1初始化本阶段要使用到的硬件设备

2 检测系统的内存映射(memory map)

3 加载内核映像和根文件系统映像

4 设置内核的启动参数

5 调用内核

六、到这里,bootloader的工作就完成了,开始有linux kernel管理硬件。


**********************************************************************************

下面开始分析u-boot,先看一下u-boot的存储器映射图



uboot上电运行的第一个文件是start.s,它位于每个文件夹cpu下的不同平台中,比如mini2440的start.s位于arm920t下

#include <common.h>
#include <config.h>
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start
_start: b start_code ;上电运行的第一条指令,跳转到start_code处执行
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

.balignl 16,0xdeadbeef

/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/

/*存储器映射,如上图*/
_TEXT_BASE:
.word TEXT_BASE

.globl _armboot_start
_armboot_start:
.word _start

/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start

.globl _bss_end
_bss_end:
.word _end

#ifdef 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 actual start code

真正的指令开始处
*/

start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f;这里要对照2440的datasheet中的cpsr寄存器,屏蔽除了mode的所有位
orr r0, r0, #0xd3;设置mode为svc(超级用户,最高权限),此处irq,fiq置1,关闭中断
msr cpsr, r0

@ bl coloured_LED_init;可以点亮一个led,指示u-boot已经开始运行,函数在board文件夹下的具体板级文件里
@ bl red_LED_on;指令bl是带返回的跳转,运行完red_LED_on函数后,会回到此处继续往下执行

#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
* relocate exception table
*/
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif

#ifdef CONFIG_S3C24X0
/* turn off the watchdog */

/*s3c2440手册中有以下特殊寄存器的内存地址*/
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008/* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014/* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008/* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014/* clock divisor register */
# endif
#define CLK_CTL_BASE 0x4C000000/* tekkaman */
#define MDIV_405 0x7f << 12/* tekkaman */
#define PSDIV_405 0x21/* tekkaman */
#define MDIV_200 0xa1 << 12/* tekkaman */
#define PSDIV_200 0x31/* tekkaman */

ldr r0, =pWTCON;加载地址0x53000000到r0
mov r1, #0x0;设置r1为0x0
str r1, [r0];在地址0x53000000处写0,关闭watchdog

/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0];INTMSK中断屏蔽寄存器,32位寄存器,每一个都是和一个中断源相关,置1则不响应中断请求,这里不响应所有请求,关闭中断,配合cpsr的f与i位
# if defined(CONFIG_S3C2410)
ldr r1, =0x7ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

#if defined(CONFIG_S3C2440)
ldr r1, =0x7fff
ldr r0, =INTSUBMSK;INTSUBMSK子中断屏蔽寄存器,为15位,置1不响应中断请求,同INTMSK
str r1, [r0]
#endif

/*设置时钟频率

*s3c2440有三个时钟,FCLK,HCLK,PCLK

*FCLK is used by ARM920T,内核时钟,主频

*HCLK is used for AHB bus ,which is used by the ARM920T, the memory controller,the interrupt controller,the lcd controller,the dma,and*usb host block是总线时钟,包括主要控制器

*PCLK is used for APB bus, which is used by the peripherals such as wdt,iis,i2c,pwm timer,mmc interface,adc,uart,gpio,rtc and spi即接口时钟,

*三个时钟通常设为1:4:8或者1:3:6

*/
#if defined(CONFIG_S3C2440)
/* FCLK:HCLK:PCLK = 1:4:8 */
ldr r0, =CLKDIVN;
mov r1, #5
str r1, [r0]

/*CP15系统控制协处理器,通过协处理器指令mrc和mcr提供具体的寄存器来配置和控制caches,mmu,保护系统,配置时钟模式(在bootloader时钟初始化时用到),具体参看arm architecture reference manual 2nd 第487页*/

mrcp15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0

/*CLK_CTL_BASE= 0x4c000000

*MPLLCON=0x4c000004

*MDIV_405=0x7f<<12,选择12MHz输入频率,405MMz输出频率

*MPLLCON由MDIV[19:12] \ PDIV[9:4] \ SDIV[1:0]决定

*对照datasheet,mdiv为0x7f,pdiv为0x02,sdiv为0x01

*/
mov r1, #CLK_CTL_BASE
mov r2, #MDIV_405
add r2, r2, #PSDIV_405
str r2, [r1, #0x04]/* MPLLCON tekkaman */

#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]

mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0/*write ctrl register tekkaman*/

mov r1, #CLK_CTL_BASE/* tekkaman*/
mov r2, #MDIV_200
add r2, r2, #PSDIV_200
str r2, [r1, #0x04]
#endif
#endif /* CONFIG_S3C24X0 */

/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT ;如果没有定义CONFIG_SKIP_LOWLEVEL_INIT,就跳转到cpu_init_crit处进行初始化工作,我们当然不会调过底层的初始化,因为LOWLEVEL_INIT会对我们的sdram进行初始化,这对我们的cpu是必要的
bl cpu_init_crit;函数位置?
#endif


/***************** CHECK_CODE_POSITION *****************************************

*检查代码运行的位置,因为_start是程序执行的第一条代码,所以如果在flash中运行,_start的值应为0,

*而如果在ram中运行,_start则不为0,但是_start为何等于_TEXT_BASE?

*/
adr r0, _start/* r0 <- current position of code */
ldr r1, _TEXT_BASE/* test if we run from flash or RAM */
cmp r0, r1/* don't reloc during debug */
beq stack_setup;若r0==r1,则跳转到stack_setup
/***************** CHECK_CODE_POSITION ******************************************/

/***************** CHECK_BOOT_FLASH ******************************************/
ldr r1, =( (4<<28)|(3<<4)|(3<<2) )/* address of Internal SRAM 0x4000003C*/
mov r0, #0/* r0 = 0 */
str r0, [r1]

mov r1, #0x3c/* address of men 0x0000003C*/
ldr r0, [r1]
cmp r0, #0
bne relocate

/* recovery */
ldr r0, =(0xdeadbeef)
ldr r1, =( (4<<28)|(3<<4)|(3<<2) )
str r0, [r1]
/***************** CHECK_BOOT_FLASH ******************************************/

/***************** NAND_BOOT *************************************************/
#define LENGTH_UBOOT 0x60000
#define NAND_CTL_BASE 0x4E000000

#ifdef CONFIG_S3C2440
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20

@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]

ldr r2, =( (1<<4)|(0<<1)|(1<<0) )@ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]

ldr r2, =(0x6)@ RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]

mov r2, #0xff@ RESET command
strb r2, [r1, #oNFCMD]

mov r3, #0@ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1

nand2:
ldr r2, [r1, #oNFSTAT]@ wait ready
tst r2, #0x4
beq nand2

ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2@ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]

@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START@ setup stack pointer
mov fp, #0@ no previous frame, so fp=0

@ copy U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read

bad_nand_read:
loop2:
b loop2@ infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400@ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next

notmatch:
loop3:
b loop3@ infinite loop
#endif

#ifdef CONFIG_S3C2410

/* Offset */
#define oNFCONF 0x00
#define oNFCMD 0x04
#define oNFSTAT 0x10

@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =0xf830@ initial value
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800@ enable chip
str r2, [r1, #oNFCONF]
mov r2, #0xff@ RESET command
strb r2, [r1, #oNFCMD]

mov r3, #0@ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1

nand2:
ldr r2, [r1, #oNFSTAT]@ wait ready
tst r2, #0x1
beq nand2

ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800@ disable chip
str r2, [r1, #oNFCONF]

@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START@ setup stack pointer
mov fp, #0@ no previous frame, so fp=0

@ copy U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read

bad_nand_read:
loop2:
b loop2@ infinite loop

ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400@ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next

notmatch:
loop3:
b loop3@ infinite loop

#endif
/***************** NAND_BOOT *************************************************/

/***************** NOR_BOOT *************************************************/
relocate: /* relocate U-Boot to RAM */
/*********** CHECK_FOR_MAGIC_NUMBER***************/
ldr r1, =(0xdeadbeef)
cmp r0, r1
bne loop3
/*********** CHECK_FOR_MAGIC_NUMBER***************/
adr r0, _start/* r0 <- current position of code */
ldr r1, _TEXT_BASE/* test if we run from flash or RAM */
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2/* r2 <- size of armboot */
add r2, r0, r2/* r2 <- source end address */

copy_loop:
ldmia r0!, {r3-r10}/* copy from source address [r0] */
stmia r1!, {r3-r10}/* copy to target address [r1] */
cmp r0, r2/* until source end addreee [r2] */
ble copy_loop
/***************** NOR_BOOT *************************************************/

/*若代码在ram中运行,则直接跳到此处,开始设置sp*/
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE/* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN/* malloc area */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
subsp, r0, #12 /* leave 3 words for abort-stack */

/*对照下图阅读上述代码,用户栈区sp往下生长*/


/*清零bss*/
clear_bss:
ldr r0, _bss_start/* find start of bss segment */
ldr r1, _bss_end/* stop here */
mov r2, #0x00000000/* clear */

/*清零循环,空间为32位,所以add r0,r0,#4(4个字节)*/
clbss_l:str r2, [r0]/* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l

/*准备跳转到stage2,ldr与b的区别?

*start_armboot在lib_arm/board.c文件中

*/
ldrpc, _start_armboot


#if defined(CONFIG_MINI2440_LED)
#define GPIO_CTL_BASE 0x56000000
#define oGPIO_B 0x10
#define oGPIO_CON 0x0
/* R/W, Configures the pins of the port */
#define oGPIO_DAT 0x4
#define oGPIO_UP 0x8
/* R/W, Pull-up disable register */
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_B
ldr r2, =0x295551
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
ldr r2, =0x1c1
str r2, [r1, #oGPIO_DAT]
#endif

_start_armboot: .word start_armboot
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .wordSTACK_BASE+STACK_SIZE-4

/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*
*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches

*清零数据cache与指令cache

*清零TLB
*/

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 stuff and caches

*关闭MMU与cache,必须关闭,不会回有脏数据,影响正确运行
*/

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
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr

/*在cpu_init_crit中又调用外部函数lowlevel_init,因此要事先保护好lr寄存器的内容,当返回时候,再恢复它

*寄存器r12,用作过程调用中间临时寄存器,记作ip,在子程序间的连接代码段中常有这种使用规则

*寄存器r14,称为连接寄存器,记作lr,它用于保存子程序的返回地址

*/
bl lowlevel_init;依赖具体的board

mov lr, ip
mov pc, lr;保存cpu_init_crit的返回地址
#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
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12}@ Calling r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE)
sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)
/* set base 2 words into abort stack */
sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
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
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12}@ Calling r0-r12
add r7, sp, #S_PC
stmdb r7, {sp, lr}^@ Calling SP, LR
str lr, [r7, #0]@ Save calling PC
mrs r6, spsr
str r6, [r7, #4]@ Save CPSR
str r0, [r7, #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
/* return & move spsr_svc into cpsr */
subs pc, lr, #4
.endm

.macro get_bad_stack
ldr r13, _armboot_start@ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE)
sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
/* reserve a couple spots in abort stack */
sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8)

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_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction

.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:
//Apollo +
/*
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs
*/
/* use IRQ for USB and DMA */
sub lr, lr, #4 @ the return address
ldr sp, IRQ_STACK_START @ the stack for irq
stmdb sp!, { r0-r12,lr } @ save registers

ldr lr, =int_return @ set the return addr
ldr pc, =IRQ_Handle @ call the isr
int_return:
ldmia sp!, { r0-r12,pc }^ @ return from interrupt
//Apollo -


.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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics