U-boot第一阶段分析

来源:互联网 发布:安卓app源码 编辑:程序博客网 时间:2024/05/11 05:03

u-boot是在单板刚启动的时候执行的一段程序。其作用是将内核从flash、硬盘等介质上拷贝到内存中,并传递给内核一些启动参数并跳转到内核去执行。

由于u-boot的代码非常的依赖于不同的体系结构。对u-boot的分析也只能提炼出不同体系结构的共性,做相应的总结。总的说来,u-boot所做到工作分为两个阶段。第一个阶段是将u-boot第二阶段的代码拷贝到ram空间,跳转到第二阶段代码执行。第二阶段是将内核代码拷贝到ram并跳转到内核去执行。

具体执行过程中做到操作如下

· 第一阶段的功能

1.  硬件设备初始化

2. 加载U-Boot第二阶段代码到RAM空间

3. 设置好栈

4. 跳转到第二阶段代码入口

· 第二阶段的功能

5. 初始化本阶段使用的硬件设备

6. 检测系统内存映射

7. 将内核从Flash读取到RAM中

8. 为内核设置启动参数

9. 调用内核

下面以ARM9 u-boot执行过程做一个分析,之后如果有时间再继续分析mips架构的u-boot执行过程,由于u-boot中涉及到许多汇编和体系结构的知识,对我们学习不同的体系结构有很大的帮助。如果相关知识不熟悉,阅读代码的时候会遇到很多疑惑。

第一阶段--硬件设备初始

.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

.balignl 16,0xdeadbeef

地址 

异常 

进入模式

描述

0x00000000 

复位

管理模式

复位电平效时,产生复位异常,程序跳转到复位处理程序处执行

0x00000004 

未定义指令

未定义模式

遇到不能处理的指令时,产生未定义指令异常

0x00000008

软件中断

管理模式

执行SWI指令产生,用于用户模式下的程序调用特权操作指令

0x0000000c

预存指令

中止模式

处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常

0x00000010

数据操作

中止模式

处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常

0x00000014

未使用

未使用

未使用

0x00000018

IRQ

IRQ

外部中断请求效,且CPSR中的I位为0时,产生IRQ异常

0x0000001c

FIQ

FIQ

快速中断请求引脚效,且CPSR中的F位为0时,产生FIQ异常

在之前的文章中曾经提及过arm处理器有8中运行方式,上电后,cpu首先跳转到0x00000000 地址开始执行

reset:

/*

 * set the cpu to SVC32 mode

 */

mrs r0,cpsr

bic r0,r0,#0x1f

orr r0,r0,#0xd3

msr cpsr,r0

mrs r0,cpsr     //将当前cpsr的状态为保存到r0中。

bic r0,r0,#0x1f //bic,位清零指令。0x1f=00011111,相当于清除低5位。  

刚好是模式位。

orr r0,r0,#0xd3 //或指令。置模式位。0xd3=11010011以及设置5,6,7位的

状态位。禁止FIQ,IRQ,处于arm状态。低5位为10011,则对应超级用户态。msr cpsr,r0     //在将r0中的值赋给状态寄存器cps

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

关闭看门狗定时器

/*

 * 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

关闭禁止各个中断

#ifdef CONFIG_S3C2440

#define MPLLCON 0x4c000004

#define UPLLCON 0x4c000008

ldr r0, =CLKDIVN

mov r1, #5

str r1, [r0]

ldr r0, =MPLLCON

ldr r1, =0x7f021

str r1, [r0]

ldr r0, =UPLLCON

ldr r1, =0x38022

str r1, [r0]

#else

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

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif

设置cpu各个模块的主频大小

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

/*

 * we do sys-critical inits only at reboot,

 * not when booting from ram!

 */

#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

如果cpu还是在flash或者step stone的内存中运行的话,跳转到cpu_init_crit运行

cpu_init_crit清空I cache和D cache并清空掉TLB表项,暂时关闭MMU,跳转到lowlevel_init对ram控制寄存器进行初始化

#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

mov lr, ip

mov pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

设置堆栈指针

stack_setup:

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

sub r0, r0, #CFG_MALLOC_LEN


设置堆栈指针

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

设置cpu的时钟

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

    bl clock_init

#endif  

#define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00))

#define S3C2410_UPLL_48MHZ      ((0x28<<12)|(0x01<<4)|(0x02))

#define S3C2410_CLKDIV          0x03    /* FCLK:HCLK:PCLK = 1:2:4 */

void clock_init(void)

{

S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;

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

    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

    {

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

    }

    else

    {

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

        clk_power->CLKDIVN = S3C2440_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 = S3C2440_UPLL_48MHZ;

        /* some delay between MPLL and UPLL */

        delay (4000);

        /* configure MPLL */

        clk_power->MPLLCON = S3C2440_MPLL_400MHZ;

        /* some delay between MPLL and UPLL */

        delay (8000);

    }

}

硬件初始化完成,堆栈设置完成,之后将u-boot第二阶段的代码拷贝到内存

#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

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

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

上面的代码过程是,首先看uboot是不是已经在内存中运行了,如果是这样直接将bss区间置0就可以了,如果不是运行在内存中设置

r0 为flash起始位置

r1 为希望将u-boot拷贝到的ram位置

r2 u-boot代码段的长度

int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)

{

    unsigned int *pdwDest;

    unsigned int *pdwSrc;

    int i;

    if (bBootFrmNORFlash())

    {

        pdwDest = (unsigned int *)buf;

        pdwSrc  = (unsigned int *)start_addr;

        /* 从 NOR Flash启动 */

        for (i = 0; i < size / 4; i++)

        {

            pdwDest[i] = pdwSrc[i];

        }

        return 0;

    }

    else

    {

        /* 初始化NAND Flash */

nand_init_ll();

        /* 从 NAND Flash启动 */

        nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));

return 0;

    }

}

将bss区域清0

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

跳转到内存中执行u-boot的第二阶段过程

ldr pc, _start_armboot


0 0
原创粉丝点击