您的位置:首页 > 其它

简单的bootloader分析(start.s)

2009-06-10 16:09 330 查看
这个程序是arm7 核启动代码, LPC2000cpu, 因其简单copy 过来做分析,以留念。

代表了一个简单的boot loader的过程。 可以很好解决main之前都干了什么的问题(start.s)。

;/*****************************************************************************/

;/* STARTUP.S: Startup file for Philips LPC2000 */

;/*****************************************************************************/

;/* <<< Use Configuration Wizard in Context Menu >>> */

;/*****************************************************************************/

;/* This file is part of the uVision/ARM development tools. */

;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */

;/* This software may only be used under the terms of a valid, current, */

;/* end user licence from KEIL for a compatible version of KEIL software */

;/* development tools. Nothing else gives you the right to use this software. */

;/*****************************************************************************/

;/*

; * The STARTUP.S code is executed after CPU Reset. This file may be

; * translated with the following SET symbols. In uVision these SET

; * symbols are entered under Options - ASM - Define.

; *

; * REMAP: when set the startup code initializes the register MEMMAP

; * which overwrites the settings of the CPU configuration pins. The

; * startup and interrupt vectors are remapped from:

; * 0x00000000 default setting (not remapped)

; * 0x80000000 when EXTMEM_MODE is used

; * 0x40000000 when RAM_MODE is used

; *

; * EXTMEM_MODE: when set the device is configured for code execution

; * from external memory starting at address 0x80000000.

; *

; * RAM_MODE: when set the device is configured for code execution

; * from on-chip RAM starting at address 0x40000000.

; */

; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs

Mode_USR EQU 0x10

Mode_FIQ EQU 0x11

Mode_IRQ EQU 0x12

Mode_SVC EQU 0x13

Mode_ABT EQU 0x17

Mode_UND EQU 0x1B

Mode_SYS EQU 0x1F

I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled

F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled

;// <h> Stack Configuration (Stack Sizes in Bytes)

;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>

;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>

;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>

;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>

;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>

;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>

;// </h>

UND_Stack_Size EQU 0x00000000

SVC_Stack_Size EQU 0x00000008

ABT_Stack_Size EQU 0x00000000

FIQ_Stack_Size EQU 0x00000000

IRQ_Stack_Size EQU 0x00000080

USR_Stack_Size EQU 0x00000400

Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + /

FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)

AREA STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem SPACE Stack_Size // stack memory 是开辟的一块内存区。指向栈顶

Stack_Top EQU Stack_Mem + Stack_Size // 实际是栈底之意,栈是向上生长的,即越用越浅(地址越小)

;// <h> Heap Configuration

;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>

;// </h>

Heap_Size EQU 0x00000000

AREA HEAP, NOINIT, READWRITE, ALIGN=3

Heap_Mem SPACE Heap_Size

; VPBDIV definitions

VPBDIV EQU 0xE01FC100 ; VPBDIV Address

;// <e> VPBDIV Setup

;// <i> Peripheral Bus Clock Rate

;// <o1.0..1> VPBDIV: VPB Clock

;// <0=> VPB Clock = CPU Clock / 4

;// <1=> VPB Clock = CPU Clock

;// <2=> VPB Clock = CPU Clock / 2

;// <o1.4..5> XCLKDIV: XCLK Pin

;// <0=> XCLK Pin = CPU Clock / 4

;// <1=> XCLK Pin = CPU Clock

;// <2=> XCLK Pin = CPU Clock / 2

;// </e>

VPBDIV_SETUP EQU 0

VPBDIV_Val EQU 0x00000000

; Phase Locked Loop (PLL) definitions

PLL_BASE EQU 0xE01FC080 ; PLL Base Address

PLLCON_OFS EQU 0x00 ; PLL Control Offset

PLLCFG_OFS EQU 0x04 ; PLL Configuration Offset

PLLSTAT_OFS EQU 0x08 ; PLL Status Offset

PLLFEED_OFS EQU 0x0C ; PLL Feed Offset

PLLCON_PLLE EQU (1<<0) ; PLL Enable

PLLCON_PLLC EQU (1<<1) ; PLL Connect

PLLCFG_MSEL EQU (0x1F<<0) ; PLL Multiplier

PLLCFG_PSEL EQU (0x03<<5) ; PLL Divider

PLLSTAT_PLOCK EQU (1<<10) ; PLL Lock Status

;// <e> PLL Setup

;// <o1.0..4> MSEL: PLL Multiplier Selection

;// <1-32><#-1>

;// <i> M Value

;// <o1.5..6> PSEL: PLL Divider Selection

;// <0=> 1 <1=> 2 <2=> 4 <3=> 8

;// <i> P Value

;// </e>

PLL_SETUP EQU 1

PLLCFG_Val EQU 0x00000024

; Memory Accelerator Module (MAM) definitions

MAM_BASE EQU 0xE01FC000 ; MAM Base Address

MAMCR_OFS EQU 0x00 ; MAM Control Offset

MAMTIM_OFS EQU 0x04 ; MAM Timing Offset

;// <e> MAM Setup

;// <o1.0..1> MAM Control

;// <0=> Disabled

;// <1=> Partially Enabled

;// <2=> Fully Enabled

;// <i> Mode

;// <o2.0..2> MAM Timing

;// <0=> Reserved <1=> 1 <2=> 2 <3=> 3

;// <4=> 4 <5=> 5 <6=> 6 <7=> 7

;// <i> Fetch Cycles

;// </e>

MAM_SETUP EQU 1

MAMCR_Val EQU 0x00000002

MAMTIM_Val EQU 0x00000004

; External Memory Controller (EMC) definitions

EMC_BASE EQU 0xFFE00000 ; EMC Base Address

BCFG0_OFS EQU 0x00 ; BCFG0 Offset

BCFG1_OFS EQU 0x04 ; BCFG1 Offset

BCFG2_OFS EQU 0x08 ; BCFG2 Offset

BCFG3_OFS EQU 0x0C ; BCFG3 Offset

;// <e> External Memory Controller (EMC)

EMC_SETUP EQU 0

;// <e> Bank Configuration 0 (BCFG0)

;// <o1.0..3> IDCY: Idle Cycles <0-15>

;// <o1.5..9> WST1: Wait States 1 <0-31>

;// <o1.11..15> WST2: Wait States 2 <0-31>

;// <o1.10> RBLE: Read Byte Lane Enable

;// <o1.26> WP: Write Protect

;// <o1.27> BM: Burst ROM

;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit

;// <2=> 32-bit <3=> Reserved

;// </e>

BCFG0_SETUP EQU 0

BCFG0_Val EQU 0x0000FBEF

;// <e> Bank Configuration 1 (BCFG1)

;// <o1.0..3> IDCY: Idle Cycles <0-15>

;// <o1.5..9> WST1: Wait States 1 <0-31>

;// <o1.11..15> WST2: Wait States 2 <0-31>

;// <o1.10> RBLE: Read Byte Lane Enable

;// <o1.26> WP: Write Protect

;// <o1.27> BM: Burst ROM

;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit

;// <2=> 32-bit <3=> Reserved

;// </e>

BCFG1_SETUP EQU 0

BCFG1_Val EQU 0x0000FBEF

;// <e> Bank Configuration 2 (BCFG2)

;// <o1.0..3> IDCY: Idle Cycles <0-15>

;// <o1.5..9> WST1: Wait States 1 <0-31>

;// <o1.11..15> WST2: Wait States 2 <0-31>

;// <o1.10> RBLE: Read Byte Lane Enable

;// <o1.26> WP: Write Protect

;// <o1.27> BM: Burst ROM

;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit

;// <2=> 32-bit <3=> Reserved

;// </e>

BCFG2_SETUP EQU 0

BCFG2_Val EQU 0x0000FBEF

;// <e> Bank Configuration 3 (BCFG3)

;// <o1.0..3> IDCY: Idle Cycles <0-15>

;// <o1.5..9> WST1: Wait States 1 <0-31>

;// <o1.11..15> WST2: Wait States 2 <0-31>

;// <o1.10> RBLE: Read Byte Lane Enable

;// <o1.26> WP: Write Protect

;// <o1.27> BM: Burst ROM

;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit

;// <2=> 32-bit <3=> Reserved

;// </e>

BCFG3_SETUP EQU 0

BCFG3_Val EQU 0x0000FBEF

;// </e> End of EMC

; External Memory Pins definitions

PINSEL2 EQU 0xE002C014 ; PINSEL2 Address

PINSEL2_Val EQU 0x0E6149E4 ; CS0..3, OE, WE, BLS0..3,

; D0..31, A2..23, JTAG Pins

PRESERVE8

; Area Definition and Entry Point

; Startup Code must be linked first at Address at which it expects to run.

AREA RESET, CODE, READONLY

ARM

; Exception Vectors

; Mapped to Address 0.

; Absolute addressing mode must be used.

; Dummy Handlers are implemented as infinite loops which can be modified.

Vectors LDR PC, Reset_Addr

LDR PC, Undef_Addr

LDR PC, SWI_Addr

LDR PC, PAbt_Addr

LDR PC, DAbt_Addr

NOP ; Reserved Vector

; LDR PC, IRQ_Addr

LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr

LDR PC, FIQ_Addr

Reset_Addr DCD Reset_Handler

Undef_Addr DCD Undef_Handler

SWI_Addr DCD SWI_Handler

PAbt_Addr DCD PAbt_Handler

DAbt_Addr DCD DAbt_Handler

DCD 0 ; Reserved Address

IRQ_Addr DCD IRQ_Handler

FIQ_Addr DCD FIQ_Handler

Undef_Handler B Undef_Handler

SWI_Handler B SWI_Handler

PAbt_Handler B PAbt_Handler

DAbt_Handler B DAbt_Handler

IRQ_Handler B IRQ_Handler

FIQ_Handler B FIQ_Handler

; Reset Handler

EXPORT Reset_Handler

Reset_Handler

; Setup External Memory Pins

IF :DEF:EXTERNAL_MODE

LDR R0, =PINSEL2

LDR R1, =PINSEL2_Val

STR R1, [R0]

ENDIF

; Setup External Memory Controller

IF EMC_SETUP <> 0

LDR R0, =EMC_BASE

IF BCFG0_SETUP <> 0

LDR R1, =BCFG0_Val

STR R1, [R0, #BCFG0_OFS]

ENDIF

IF BCFG1_SETUP <> 0

LDR R1, =BCFG1_Val

STR R1, [R0, #BCFG1_OFS]

ENDIF

IF BCFG2_SETUP <> 0

LDR R1, =BCFG2_Val

STR R1, [R0, #BCFG2_OFS]

ENDIF

IF BCFG3_SETUP <> 0

LDR R1, =BCFG3_Val

STR R1, [R0, #BCFG3_OFS]

ENDIF

ENDIF ; EMC_SETUP

; Setup VPBDIV

IF VPBDIV_SETUP <> 0

LDR R0, =VPBDIV

LDR R1, =VPBDIV_Val

STR R1, [R0]

ENDIF

; Setup PLL

IF PLL_SETUP <> 0

LDR R0, =PLL_BASE

MOV R1, #0xAA

MOV R2, #0x55

; Configure and Enable PLL

MOV R3, #PLLCFG_Val

STR R3, [R0, #PLLCFG_OFS]

MOV R3, #PLLCON_PLLE

STR R3, [R0, #PLLCON_OFS]

STR R1, [R0, #PLLFEED_OFS]

STR R2, [R0, #PLLFEED_OFS]

; Wait until PLL Locked

PLL_Loop LDR R3, [R0, #PLLSTAT_OFS]

ANDS R3, R3, #PLLSTAT_PLOCK

BEQ PLL_Loop

; Switch to PLL Clock

MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC)

STR R3, [R0, #PLLCON_OFS]

STR R1, [R0, #PLLFEED_OFS]

STR R2, [R0, #PLLFEED_OFS]

ENDIF ; PLL_SETUP

; Setup MAM

IF MAM_SETUP <> 0

LDR R0, =MAM_BASE

MOV R1, #MAMTIM_Val

STR R1, [R0, #MAMTIM_OFS]

MOV R1, #MAMCR_Val

STR R1, [R0, #MAMCR_OFS]

ENDIF ; MAM_SETUP

; Memory Mapping (when Interrupt Vectors are in RAM)

MEMMAP EQU 0xE01FC040 ; Memory Mapping Control

IF :DEF:REMAP

LDR R0, =MEMMAP

IF :DEF:EXTMEM_MODE

MOV R1, #3

ELIF :DEF:RAM_MODE

MOV R1, #2

ELSE

MOV R1, #1

ENDIF

STR R1, [R0]

ENDIF

; Initialise Interrupt System

; ...

; Setup Stack for each mode

LDR R0, =Stack_Top

; Enter Undefined Instruction Mode and set its Stack Pointer

MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit // 从栈底开始设置。

MOV SP, R0

SUB R0, R0, #UND_Stack_Size

; Enter Abort Mode and set its Stack Pointer

MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #ABT_Stack_Size

; Enter FIQ Mode and set its Stack Pointer

MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #FIQ_Stack_Size

; Enter IRQ Mode and set its Stack Pointer

MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #IRQ_Stack_Size // 80个字节

; Enter Supervisor Mode and set its Stack Pointer

MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit

MOV SP, R0

SUB R0, R0, #SVC_Stack_Size // 8 个字节

; Enter User Mode and set its Stack Pointer

MSR CPSR_c, #Mode_USR

MOV SP, R0

SUB SL, SP, #USR_Stack_Size // SL 是r10 寄存器,作为stack 的顶部极限位置。

; Enter the C code

IMPORT __main

LDR R0, =__main

BX R0 //当目标是arm 非thumb时,等同于BL R0, 当目标是thumb, bit0要置1

; User Initial Stack & Heap

AREA |.text|, CODE, READONLY

IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

__user_initial_stackheap // 独立的子程序, 获取堆和栈的位置和大小(立即数)

LDR R0, = Heap_Mem

LDR R1, =(Stack_Mem + USR_Stack_Size)

LDR R2, = (Heap_Mem + Heap_Size)

LDR R3, = Stack_Mem

BX LR // 该指令等同于返回指令。 该指令所引起的LR值变动,要保证我们不会再使用

END

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

注释是很好的,实现了简单的boot 的功能,可以帮助理解main 之前都干了什么这个问题。

下面的总结是以它为模板,也涵盖其它芯片start.s, 具有一定普遍性。

1. 设置了中断矢量表。 貌似8个矢量地址。 使得发生了意外或中断,程序有个归属。

否则,程序会跑飞。

2. 复位后,c main之前程序都干了啥? (复位应该保证中断是关着的吧,软件再关一次也无妨)

a.如果你有外部memrory, 需要设置External memory interface. 例如设置flash 参数, sdram参数。

为的是更好发挥External memrory 的效率。 也有的需要设置MMU

b. 设置工作时钟,PLL, 也是为了效率。

c. 也有在此时设置串口的,为的是尽早控制程序调试。(或者点个led之类的)

d. 初始化各模式下栈指针(arm),这样当使用栈时才能正确。

栈是编译器为程序保留的一块内存,占据Stack_Mem, 到Stack_Mem+Stack_Size 区间。先入后出结构。push pop显示操作。

e. 初始化堆指针。 堆也是保留的一块连续内存。必须获得堆的位置,大小,以后好管理。

start.s 中不使用堆,但有一个子程序可以取到堆和栈的位置和大小。

; ---------------------------------------------------------------------------

上面只是简单的boot 过程,程序在flash的固定位置上运行。 loader 的作用是boot 把程序加载到ram中来运行。

上面还有一个问题未说,就是中断服务程序问题。进入main 之前是应该开中断的,除非你不用中断。 继续...

先来一段中断服务程序吧。 看看arm 是怎样处理中断的。

;===================================================================================

;呵呵,来了来了.好戏来了,这一段程序就是用来进行第二次查表的过程了.

;如果,那这一次查表就是由软件来实现的了.

;为什么要查两次表??

;ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常,是由硬件来完成的,

;可以认为是第一次查表,硬件查表。

;那么到底是那个设备引起的异常呢,我们怎样跳转到服务地址呢? 没办法了,再查一次表呗!

;在INTOFFSET 处,会储藏着中断号。

;在一个中断表中,HandeEINT处, INTOFFSET*4 处, 会储存着这个中断服务程序地址。

;===================================================================================

IsrIRQ

sub sp,sp,#4 ;给PC寄存器保留

stmfd sp!,{r8-r9} ;把r8-r9压入栈

ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9

ldr r9,[r9] ;把INTOFFSET的值装入r9

ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8

;===================================================================================

;哈哈,这查表方法够好了吧,r8(入口)+index*4(别忘了一条指令是4 bytes的喔),

;这不就是我们要找的那一项了吗.找到了表项,下一步做什么?肯定先装入了!

;==================================================================================

add r8,r8,r9,lsl #2

ldr r8,[r8] ;装入中断服务程序的入口

str r8,[sp,#8] ;弥补了原来保留的字节,把入口也入栈,准备用招

ldmfd sp!,{r8-r9,pc} ;施招,弹出栈,哈哈,顺便把r8弹出到PC,跳转成功!

LTORG ;声明文字池,因为我们用了ldr伪指令

到了中断服务程序,应该是所有寄存器入栈,适当的时候开中断,最后interrupt 返回。结束中断模式。

; ---------------------------------------------------------------------------

loader 程序,(令我想起了mdoc, x86,等等的启动)它从不同的介质中加载程序到内存。

从nor flash直接copy 就可以了。(当然, nor flash也要先配置)

从nand flash 要有相应的nand flash 配置及读写代码。

从ide 加载要用bios 中断或者atapi 命令,

从网络加载要有网口驱动。

从串口加载要有串口程序或串口驱动。

从usb加载要有usb 驱动程序

热闹起来了,但其目的就是把程序加载到内存。

又令我想起wince 的boot 过程。 mdoc 的xloader, 加载eboot 到内存。然后在eboot 下可以进行开发。eboot 可以带

各种小型驱动,工作于虚拟地址模式。eboot中开发了键盘,显示,串口,usb,网口等驱动。当然这早就越出了汇编代码

用c 开发了。

eboot 可以加载ipl, win内核认为ipl才是它的初始化加载器,ipl又工作于实模式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: