uboot启动第一阶段分析

来源:互联网 发布:淘宝越南新娘价格图片 编辑:程序博客网 时间:2024/06/05 07:03

u-boot第一阶段分析:

第一阶段主要是在start.S

.globl _start  //声明_start是全局变量,和c语言中的extern相似,声明此变量,并且告诉链 接器此变量是全局的,外部可以访问。由board\100ask24x0\u-boot.lds ENTRY(_start)可知,_start是程序入口地址,一开始从nor_flash启动,_start0,当执行后面的地址重载后,_start就变为TEXT_BASE = 0x33F80000

_start: b       reset  //b指令,就只是单纯的掉转到某处继续执行,而不能再通过mov pc, lr跳转回来了

/*处理器的异常处理向量表*/

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

//word的作用就是说在这个地址处放一个内容。

_irq: .word irq指令就是在_irq标号的地址处申请一个字的空间长度(4字节)来放一个irq标签的地址,当发生中断时候,根据这个标号处存放的地址来转到该地址去。

.balignl 16,0xdeadbeef意思就是要16字节对齐后,再存放接下来的代码。直到能被16字节整除的地址(33f80040能被16u整除)出现前都用0xdeadbeef这个值来填充。

根据反汇编得到的指令就可以很容易的看出。

33f80000 <_start>:

33f80000: ea000017  b 33f80064 <reset>

33f80004: e59ff014  ldr pc, [pc, #20] ; 33f80020 <_undefined_instruction>

33f80008: e59ff014  ldr pc, [pc, #20] ; 33f80024 <_software_interrupt>

33f8000c: e59ff014  ldr pc, [pc, #20] ; 33f80028 <_prefetch_abort>

33f80010: e59ff014  ldr pc, [pc, #20] ; 33f8002c <_data_abort>

33f80014: e59ff014  ldr pc, [pc, #20] ; 33f80030 <_not_used>

33f80018: e59ff014  ldr pc, [pc, #20] ; 33f80034 <_irq>

33f8001c: e59ff014  ldr pc, [pc, #20] ; 33f80038 <_fiq>

 

33f80020 <_undefined_instruction>:

33f80020: 33f80160  mvnccs r0, #24 ; 0x18

 

33f80024 <_software_interrupt>:

33f80024: 33f801c0  mvnccs r0, #48 ; 0x30

 

33f80028 <_prefetch_abort>:

33f80028: 33f80220  mvnccs r0, #2 ; 0x2

 

33f8002c <_data_abort>:

33f8002c: 33f80280  mvnccs r0, #8 ; 0x8

 

33f80030 <_not_used>:

33f80030: 33f802e0  mvnccs r0, #14 ; 0xe

 

33f80034 <_irq>:

33f80034: 33f80400  mvnccs r0, #0 ; 0x0

 

33f80038 <_fiq>:

33f80038: 33f80420  mvnccs r0, #536870912 ; 0x20000000

33f8003c: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}

 

然后是

_TEXT_BASE:

.word TEXT_BASE //board\100ask24x0\Config.mk文件中定义TEXT_BASE = 0x33F80000。及程序的链接地址。

 

.globl _armboot_start

_armboot_start:

.word _start //_start是程序入口,链接完毕它的值应该是TEXT_BASE=33f80000

 

.globl _bss_start

_bss_start:

.word __bss_start

 

.globl _bss_end

_bss_end:

.word _end

/* __bss_start_endboard\100ask24x0\u-boot.lds处定义*/

 

.globl FREE_RAM_END

FREE_RAM_END:

.word 0x0badc0de

 

.globl FREE_RAM_SIZE

FREE_RAM_SIZE:

.word 0x0badc0de

 

.globl PreLoadedONRAM

PreLoadedONRAM:

.word 0

 

#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

上面指令声明了_bss_start_bss_endFREE_RAM_ENDFREE_RAM_SIZEPreLoadedONRAMIRQ_STACK_STARTFIQ_STACK_START标号为全局 变量,下面会用到。

reset:

/*

 * set the cpu to SVC32 mode

 */

mrs r0,cpsr //mrs是读状态寄存器指令

bic r0,r0,#0x1f//bic是位清楚指令

orr r0,r0,#0xd3//orr是逻辑或指令

msr cpsr,r0//msr是写状态寄存器指令

 

这些指令执行后cpsr的低八位内容是110 10011,如下图可知为CPU进入Supervisor模式。且禁止中断和快中断,使用ARM指令。

cpsr寄存器格式如下

 

 


/* 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)//include\configs\100ask24x0.h处定义,所以执行该部分语句

# define pWTCON 0x53000000

# define INTMOD     0X4A000004

# 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] //往看门狗寄存器写0就可以关闭看门狗

 

/*

 * mask all IRQs by setting all bits in the INTMR - default

 */

mov r1, #0xffffffff

ldr r0, =INTMSK

str r1, [r0] //中断屏蔽寄存器全部写1,禁止所有中断

# if defined(CONFIG_S3C2410)

ldr r1, =0x3ff

ldr r0, =INTSUBMSK//子中断寄存器写1,禁止。但是这里0x3ff不严谨,由下图 INTSUBMSK寄存器可以看出应该为0x7ff

str r1, [r0]

# endif

 

#if 0

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif //这里是不编译的,因为在后面的时钟初始化中初始化了。

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

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         */

blne cpu_init_crit

#endif

此时_start仍然为0_TEXT_BASE0x3F800000.两者肯定不相等,所以运行cpu_init_crit函数,这个函数具体是干嘛的,下面再说。

 

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot   */

sub r0, r0, #CFG_MALLOC_LEN /* malloc area   256KB                   */

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo     128字节                   */

 

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

 

sub sp, r0, #12 /* leave 3 words for abort-stack    */

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

    bl clock_init

#endif   

CFG_MALLOC_LEN堆大小由128KB的环境变量大小和128KB的堆空间组成。

CFG_GBL_DATA_SIZE为全局变量区大小为128字节

CONFIG_STACKSIZE_IRQCONFIG_STACKSIZE_FIQIRQFIQ的堆栈,各为4K

最后还设置一个3字节大小的堆栈

所以最后

r0=_TEXT_BASE-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE-CONFIG_STACKSIZE_IRQ-CONFIG_STACKSIZE_FIQ-3

=0x33F80000-256KB-128-4K-4k-12=0x33F3EF74

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT//没有定义所以执行下面的语句

    bl clock_init 

#endif  

clock_init是处理器时钟的初始化,因为这个函数是c语言函数,所以在调用的时候要设置栈,所以前面是设置栈的一些指令。而且前面提到的注释掉时钟初始化指令就是在这里添加的。

下面看一下clock_init函数,在uboot官方提供的源码中是没有这个函数的,这里是为了移植而添加的。(在board\100ask24x0\Boot_init.c中定义)

void clock_init(void)

{

S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;

 

    /* support both of S3C2410 and S3C2440, by www.100ask.net */

        /* FCLK:HCLK:PCLK = 1:2:4 */

        clk_power->CLKDIVN = S3C2410_CLKDIV;

 

        /* change to asynchronous bus mod */

        __asm__(    "mrc    p15, 0, r1, c1, c0, 0\n"    /* read ctrl register   */  

                    "orr    r1, r1, #0xc0000000\n"      /* Asynchronous         */  

                    "mcr    p15, 0, r1, c1, c0, 0\n"    /* write ctrl register  */  

                    :::"r1"

                    );

  

        /* to reduce PLL lock time, adjust the LOCKTIME register */

        clk_power->LOCKTIME = 0xFFFFFFFF;

 

        /* configure UPLL */

        clk_power->UPLLCON = S3C2410_UPLL_48MHZ;

 

        /* some delay between MPLL and UPLL */

        delay (4000);

 

        /* configure MPLL */

        clk_power->MPLLCON = S3C2410_MPLL_200MHZ;

 

        /* some delay between MPLL and UPLL */

        delay (8000);

}

 

S3C24X0_CLOCK_POWER是定义的与时钟相关寄存器的结构体。

typedef struct {

    S3C24X0_REG32   LOCKTIME;

    S3C24X0_REG32   MPLLCON;

    S3C24X0_REG32   UPLLCON;

    S3C24X0_REG32   CLKCON;

    S3C24X0_REG32   CLKSLOW;

    S3C24X0_REG32   CLKDIVN;

    S3C24X0_REG32   CAMDIVN;    /* for s3c2440, by www.100ask.net */

} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;

S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;这句代码是创建一个clk_power 指针,且指向地址0x4C000000;LOCKTIME代表的地址为0x4C000000MPLLCON代表的地址为0x4C000004,以此类推。这些地址正好是这些寄存器的地址。

 

#ifndef CONFIG_SKIP_RELOCATE_UBOOT//没有定义,执行下面的指令

relocate: /* relocate U-Boot to RAM     */

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     clear_bss //如果_start_TEXT_BASE相同则跳到下面的clear_bss 标号处清 bss段且不反悔,则紧接着的指令不会执行。如果不相等,则说明此 时代码仍然在flash中,并没有搬移到配ram中,则继续执行下面的 的指令,将flash中的代码拷贝到ram中,然后再请bss

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot            */

#if 1

bl  CopyCode2Ram /* r0: source, r1: dest, r2: size */

//此时r0=_start,r1=r1, _TEXT_BASE,r2=_bss_start-_armboot_start=33fb0754-33f80000=193KB

//int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)函数的参数分别为r0,r1,r2.起始地址,目的地址,大小。

#else//下面的指令不执行

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

#endif

#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

 

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

//这段代码就是给BSS段每个地址处赋值0.

 

SetLoadFlag:

/* Set a global flag, PreLoadedONRAM */

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         */

ldr r2, =PreLoadedONRAM

mov r3, #1

streq r3, [r2]

ldr pc, _start_armboot

 

_start_armboot: .word start_armboot//跳转到start_armboot执行。

#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 */

mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

 

/*

 * disable MMU stuff 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

 * because memory timing is board-dependend, you will

 * find a lowlevel_init.S in your board directory.

 */

mov ip, lr

bl lowlevel_init//bvoard\100ask24x0\lowlevel_init.S中定义进行sdram相关的初始化。

mov lr, ip

mov pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

 

 

 

@

@ 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+CFG_MALLOC_LEN)

sub 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

sub 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

subs pc, lr, #4 @ return & move spsr_svc into cpsr

.endm

 

.macro get_bad_stack

ldr r13, _armboot_start @ setup our mode stack

sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub 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_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

 

@ thisway.diy, 2006.06.24

.globl Launch

    .align 4

Launch:    

    mov r7, r0

    @ diable interrupt

@ disable watch dog timer

mov r1, #0x53000000

mov r2, #0x0

str r2, [r1]

 

    ldr r1,=INTMSK

    ldr r2,=0xffffffff  @ all interrupt disable

    str r2,[r1]

 

    ldr r1,=INTSUBMSK

    ldr r2,=0x7ff       @ all sub interrupt disable

    str r2,[r1]

 

    ldr     r1, = INTMOD

    mov r2, #0x0        @ set all interrupt as IRQ (not FIQ)

    str     r2, [r1]

 

    @ 

mov ip, #0

mcr p15, 0, ip, c13, c0, 0      @ /* zero PID */

mcr p15, 0, ip, c7, c7, 0       @ /* invalidate I,D caches */

mcr p15, 0, ip, c7, c10, 4      @ /* drain write buffer */

mcr p15, 0, ip, c8, c7, 0       @ /* invalidate I,D TLBs */

mrc p15, 0, ip, c1, c0, 0       @ /* get control register */

bic ip, ip, #0x0001             @ /* disable MMU */

mcr p15, 0, ip, c1, c0, 0       @ /* write control register */

 

    @ MMU_EnableICache

    @mrc p15,0,r1,c1,c0,0

    @orr r1,r1,#(1<<12)

    @mcr p15,0,r1,c1,c0,0

 

    @ clear SDRAM: the end of free mem(has wince on it now) to the end of SDRAM

    ldr     r3, FREE_RAM_END

    ldr     r4, =PHYS_SDRAM_1+PHYS_SDRAM_1_SIZE    @ must clear all the memory unused to zero

    mov     r5, #0

 

    ldr     r1, _armboot_start

    ldr     r2, =On_Steppingstone

    sub     r2, r2, r1

    mov     pc, r2

On_Steppingstone:

2:  stmia   r3!, {r5}

    cmp     r3, r4

    bne     2b

 

    @ set sp = 0 on sys mode

    mov sp, #0

 

    @ add by thisway.diy 2006.06.26, switch to SVC mode

msr cpsr_c, #0xdf @ set the I-bit = 1, diable the IRQ interrupt

msr cpsr_c, #0xd3 @ set the I-bit = 1, diable the IRQ interrupt

    ldr sp, =0x31ff5800

    

    nop

nop

    nop

nop

 

mov     pc, r7  @ Jump to PhysicalAddress

nop

    mov pc, lr

 

#ifdef CONFIG_USE_IRQ//定义了

 

.align 5

irq:

/* add by www.100ask.net to 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调用中断服务函数在cpu\arm920t\s3c24x0\Interrupts.c中定义

int_return:

ldmia sp!,  { r0-r12,pc }^ @ return from interrupt恢复栈

 

.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

 

综上可知uboot里区域设置如下

 

 

_TEXT_BASE

GFG_MALLCO_LEN(256KB)

GFG_GBL_DATA_SIZE(128B)

CONFIG_STACK_SIZE_IRQ+CONFIG_STACK_SIZE_FIQ(8K)

Aboart Stack 12byte

 

 

 

 

 

0 0
原创粉丝点击