start.S的分析很多人也都写过了.这里只是重新整理了一下,加了点自己的理解,如果有不对的地方还希望大家指正
下面以u-boot-1.2.0源码分析arm920t的start.S
1.首先看一下./board/smdk2410/U-Boot.lds文件,对后面理解start.S有很大好处
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*指定输出格式为elf, 小端模式*/
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)/*指定输入目标系统为arm*/
ENTRY(_start)/*指定程序入口点,其中_start在/u-boot-1.2.0/cpu/arm920t/start.S里定义*/
SECTIONS
{
. = 0x00000000;/*从0地址开始*/
/*text段,其中start.o位于最前端,即0x0位置*/
. = ALIGN(4);/*4字节对齐*/
.text :
{
cpu/arm920t/start.o(.text)
*(.text)
}
/*rodata段*/
. = ALIGN(4);
.rodata : { *(.rodata) }
/*data段*/
. = ALIGN(4);
.data : { *(.data) }
/*got段*/
. = ALIGN(4);
.got : { *(.got) }
/*u_boot_cmd段(存放u-boot所有命令的段).指定_u_boot_cmd_start及__u_boot_cmd_end位置*/
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
/*bss段.指定__bss_start及end的位置*/
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
/*
从高到低依次是:
_end
bss段
_bss_start
__u_boot_cmd_end
u_boot_cmd段
__u_boot_cmd_start
got段
data段
rodata段
text段
(start.o)
_start
0x00000000
记住这些信息,对往后分析start.S有好处
*/
/*全局入口点,同时_start在U-boot.lds里被指定为程序的第一个入口点,这里也可以看出首先会运行reset*/
.globl _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
/以这个地方往后为16倍数的地址的地方插入0xdeadbeef标志*/
.balignl 16,0xdeadbeef
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
/*指定_TEXT_BASE的位置,其中TEXT_BASE在/board/smdk210/config.mk里定义,为u-boot的加载地址*/
_TEXT_BASE:
.word TEXT_BASE
/*指定_armboot_start的位置,其中_start在/board/smdk210/U-boot.lds里定义*/
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
/*指定_bss_start的位置,其中__bss_start在/board/smdk210/U-boot.lds里定义*/
.globl _bss_start
_bss_start:
.word __bss_start
/*指定_bss_end的位置,其中_end在/board/smdk210/U-boot.lds里定义*/
.globl _bss_end
_bss_end:
.word _end
/*指定IRQ_STACK_START和FIQ_STACK_START的位置*/
#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 reset code
*/
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr /*读cpsr寄存器到ro*/
bic r0,r0,#0x1f /*清除低5位*/
orr r0,r0,#0xd3 /*把低5位置为10011,即设为svc模式*/
msr cpsr,r0/*写回cpsr*/
/*定义pWTCON(喂狗寄存器),INTMSK(中断掩码寄存器),CLKDIVN(时钟除数寄存器),这个需要根据相关芯片的datasheet配置*/
/* turn off the watchdog */
#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 INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014/* clock divisor register */
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
/*喂狗*/
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, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
/*CLKDIVN的值决定了FCLK:HCLK:PCLK的值,这里默认设为3*/
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 2氏*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
/* 一些*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
这里会先跳到cpu_init_cut,代码如下:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>cpu_init_crit>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0/* flush v3/v4 cache 无效数据cache和指令cache*/
mcr p15, 0, r0, c8, c7, 0/* flush v4 TLB 无效TLB(什么是TLB?)*/
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0/*读c1的值到r0*/
bic r0, r0, #0x00002300@ clear bits 13, 9:8 (--V- --RS)/*V控制中断向量表的位置,R和S控制MMU的一些保护位*/
bic r0, r0, #0x00000087@ clear bits 7, 2:0 (B--- -CAM)/*B为0是little-endian, C为0是禁止数据cache,A为0是地址对齐检查,M为0是禁止MMU*/
orr r0, r0, #0x00000002@ set bit 2 (A) Align/*使能地址对齐检查*/
orr r0, r0, #0x00001000@ set bit 12 (I) I-Cache/*使能指令cache*/
mcr p15, 0, r0, c1, c0, 0/*写回c1*/
/*
* 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.
*/
/*执行/board/smdk210/lowlevel_init.S的lowlevel_init部分*/
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr/*跳回程序调用处*/
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
这里会跳到./board/smdk2410/lowlevel_init.S,我们再跳过去看一下
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>lowlevel_init.S>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define BWSCON 0x48000000
/* BWSCON */
#define DW8
(0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)
#define B1_BWSCON (DW32)
#define B2_BWSCON (DW16)
#define B3_BWSCON (DW16 + WAIT + UBLB)
#define B4_BWSCON (DW16)
#define B5_BWSCON (DW16)
#define B6_BWSCON (DW32)
#define B7_BWSCON (DW32)
/* BANK0CON */
#define B0_Tacs 0x0
/* 0clk */
#define B0_Tcos 0x0
/* 0clk */
#define B0_Tacc 0x7
/* 14clk */
#define B0_Tcoh 0x0
/* 0clk */
#define B0_Tah 0x0
/* 0clk */
#define B0_Tacp 0x0
#define B0_PMC 0x0
/* normal */
/* BANK1CON */
#define B1_Tacs 0x0
/* 0clk */
#define B1_Tcos 0x0
/* 0clk */
#define B1_Tacc 0x7
/* 14clk */
#define B1_Tcoh 0x0
/* 0clk */
#define B1_Tah 0x0
/* 0clk */
#define B1_Tacp 0x0
#define B1_PMC 0x0
#define B2_Tacs 0x0
#define B2_Tcos 0x0
#define B2_Tacc 0x7
#define B2_Tcoh 0x0
#define B2_Tah 0x0
#define B2_Tacp 0x0
#define B2_PMC 0x0
#define B3_Tacs 0x0
/* 0clk */
#define B3_Tcos 0x3
/* 4clk */
#define B3_Tacc 0x7
/* 14clk */
#define B3_Tcoh 0x1
/* 1clk */
#define B3_Tah 0x0
/* 0clk */
#define B3_Tacp 0x3 /* 6clk */
#define B3_PMC 0x0
/* normal */
#define B4_Tacs 0x0
/* 0clk */
#define B4_Tcos 0x0
/* 0clk */
#define B4_Tacc 0x7
/* 14clk */
#define B4_Tcoh 0x0
/* 0clk */
#define B4_Tah 0x0
/* 0clk */
#define B4_Tacp 0x0
#define B4_PMC 0x0
/* normal */
#define B5_Tacs 0x0
/* 0clk */
#define B5_Tcos 0x0
/* 0clk */
#define B5_Tacc 0x7
/* 14clk */
#define B5_Tcoh 0x0
/* 0clk */
#define B5_Tah 0x0
/* 0clk */
#define B5_Tacp 0x0
#define B5_PMC 0x0
/* normal */
#define B6_MT 0x3
/* SDRAM */
#define B6_Trcd
0x1
#define B6_SCAN 0x1
/* 9bit */
#define B7_MT 0x3
/* SDRAM */
#define B7_Trcd 0x1
/* 3clk */
#define B7_SCAN 0x1
/* 9bit */
/* REFRESH parameter */
#define REFEN 0x1
/* Refresh enable */
#define TREFMD 0x0
/* CBR(CAS before RAS)/Auto refresh */
#define Trp
0x0 /* 2clk */
#define Trc
0x3 /* 7clk */
#define Tchr 0x2
/* 3clk */
#define REFCNT 1113
/* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
ldr r0, =SMRDATA/*把SMRDATA的地址赋给r0*/
ldr r1, _TEXT_BASE/*把_TEXT_BASE地址赋给r1*/
sub r0, r0, r1/*SMRDATA-_TEXT_BASE的值表示在SMRDATA标签的相对位置
ldr r1, =BWSCON/* Bus Width Status Controller *//*SDRAM控制寄存器起始地址*/
add r2, r0, #13*4/*r0是SMRDATA的相对起始位置,r2是SMRDATA的结束位置*/
/*从SMRDATA段循环赋13个寄存器的值到BWSCON寄存器,完成SDRAM控制寄存器初始化*/
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
/* everything is fine now */
/*跳回去这段代码的调用处*/
mov pc, lr
.ltorg
/* the literal pools origin */
SMRDATA:
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32
.word 0x30
.word 0x30
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<lowlevel_init.S<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<cpu_init_crit<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
从lowlevel_init跳回, 再从cpu_init_crit跳回来之后继续运行:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
/*比较_start和_TEXT_BASE,如果相等就直接跳到stack_setup,如果不相等的话要把u-boot搬到_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
/*起始:_start,结束_bss_start*/
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操作*/
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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack */
/*分配空间,从上到下依次是:
_TEXT_BASE
CFG_MALLOC_LEN,堆
CFG_GBL_DATA_SIZE,全局数据区
CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ,中断及快速中断栈区
*/
stack_setup:
ldr r0, _TEXT_BASE/* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN/* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12/* leave 3 words for abort-stack */
/*清除bss段*/
clear_bss:
ldr r0, _bss_start/* find start of bss segment */
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 stuff 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 stuff after relocation */
#endif
/*跳转到Uboot-1.2.0/lib_arm/board.c里的_start_armboot,也就是C程序入口*/
ldr pc, _start_armboot
_start_armboot: .word start_armboot
搞定.睡觉了.明天再看start_armboot