boot_jump_linux函数,U-Boot系列之三: u-boot整体结构、移植步骤以及启动代码分析...

U-Boot系列之三: u-boot整体结构、移植步骤以及启动代码分析

[日期:2011-08-05]

来源:Linux社区

作者:yeshi

[字体:大 中 小]

本篇文章首先介绍u-boot的整体代码结构,移植的基本步骤,然后分析启动的代码(start.S)中

其中代码结构和移植步骤是参考了下面两个连接的文章,作者是 焦玉全 黄乡生 鲍玉军,题目是

第7540篇:U-Boot在S3C2410上的移植(具体URL忘了,我文章是下载的,知道的朋友告诉一声)一、整体结构

首先下载u-boot的源代码(www.denx.de),解压缩,你可以看到下面的目录:

- board 目标板相关文件,主要包含SDRAM、FLASH驱动;

- common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;

- cpu 与处理器相关的文件。如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;

- driver 通用设备驱动,如CFI FLASH驱动(目前对INTEL FLASH支持较好)

- doc U-Boot的说明文档;

- examples可在U-Boot下运行的示例程序;如hello_world.c,timer.c;

- include U-Boot头文件;尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;

- lib_xxx 处理器体系相关的文件,如lib_ppc, lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;

- net 与网络功能相关的文件目录,如bootp,nfs,tftp;

- post 上电自检文件目录。尚有待于进一步完善;

- rtc RTC驱动程序;

- tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具;

二、移植步骤

为了使U-Boot支持新的开发板,一种简便的做法是在U-Boot已经支持的开发板中选择一种和目标板接近的,并在其基础上进行修改。代码修改的步骤如下:

1)在board目录下创建smdk2410目录,添加smdk2410.c、flash.c、memsetup.s、u-boot.lds和config.mk等;

2)在cpu目录下创建arm920t目录,主要包含start.s、interrupts.c、cpu.c、serial.c和speed.c等文件;

3)在include/configs目录下添加smdk2410.h,它定义了全局的宏定义等;

4)修改u-boot根目录下的Makefile文件:

smdk2410_config : unconfig@./mkconfig $(@:_config=) arm arm920t smdk2410

5)运行make smdk2410_config,如果没有错误,就可以开始进行与硬件相关的代码移植工作。由于这部分代码与硬件紧密相关,所以要熟悉开发板的硬件配置,可参考各芯片的用户手册。

当然,这个是一般步骤,后面我们做的可能具体文件名还和这个不一样,等到那时候在交待,这里先介绍的目的是在开始的时候给个大概的思路,要不直接分析源代码,有点在原始森林的感觉,耐心的看吧:)

三、start.S分析

首先介绍start.S中的代码的具体作用,由于该代码是系统最开始执行的,这时,u-boot对系统一无所知,必须要初始化一些东西,比如设置异常的入口地址和异常处理函数;配置PLLCON寄存器,确定系统的主频;屏蔽看门狗和中断;初始化I/O寄存器;关闭MMU功能;调用 /board/smdk2410中的memsetup.s,初始化存储器空间,设置刷新频率;将U-Boot的内容复制到SDRAM中;设置堆栈的大小, 然后ldr pc, _start_armboot,跳到C函数

代码来自华恒的板子上面的资料

/* CPU clcok */

/* 50.00 MHz */

#define MDIV_50                 0x5c

#define PDIV_50                 0x4

#define SDIV_50                 0x2

/* 100.00 MHz */

#define MDIV_100        0xa1

#define PDIV_100        0x3

#define SDIV_100        0x1

/* 200.00 MHz */

/*CPU clock = 202.800000 Mhz, HCLK = 101.400000 Mhz, PCLK = 50.700000 Mhz*/

/*0xa1  3  1*/

/*180Mhz 90Mhz 45Mhz  0x52  1  1*/

/*152MHZ              0x44 1   1*/

#define MDIV_200                0xa1

#define PDIV_200                0x3

#define SDIV_200                0x1

#define vMPLLCON_50             ((MDIV_50 << 12) | (PDIV_50 << 4) | (SDIV_50))

#define vMPLLCON_100        ((MDIV_100 << 12) | (PDIV_100 << 4) | (SDIV_100))

#define vMPLLCON_200        ((MDIV_200 << 12) | (PDIV_200 << 4) | (SDIV_200))

/*

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

*

* Jump vector table as in table 3.1 in [1]

*

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

*/

.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

/*

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

*

* 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

*

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

*/

/*

* CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h)

*/

_TEXT_BASE:

.word    TEXT_BASE

.globl _armboot_start

_armboot_start:

.word _start

/*

* Note: _armboot_end_data and _armboot_end are defined

* by the (board-dependent) linker script.

* _armboot_end_data is the first usable FLASH address after armboot

*/

.globl _armboot_end_data

_armboot_end_data:

.word armboot_end_data

.globl _armboot_end

_armboot_end:

.word armboot_end

/*

* _armboot_real_end is the first usable RAM address behind armboot

* and the various stacks

*/

.globl _armboot_real_end

_armboot_real_end:

.word 0x0badc0de

#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:=============================================〉程序开始的时候跳转到这里

ldr     r0, =pWTCON

mov     r1, #0x0

str     r1, [r0];0x0写到0x53000000地址上,其实该地址是看门狗的控制寄存器,该指令就是关闭看门狗,具体对应位请看2410的用户手册。

/*

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

*/

mov    r1, #0xffffffff

ldr    r0, =INTMSK

str    r1, [r0];将0xffffffff写到INTMSK代表的地址上,屏蔽中断

#if defined(CONFIG_S3C2410)

ldr    r1, =0x7ff

ldr    r0, =INTSUBMSK

str    r1, [r0];对于2410还要设置此寄存器

#endif

@ initialise system clocks;下面没什么要讲的,具体参看2410的用户手册

mov     r1, #CLK_CTL_BASE

mvn     r2, #0xff000000

str     r2, [r1, #0x0]  /*oLOCKTIME*/

@ldr    r2, mpll_50mhz

@str    r2, [r1, #0x4]  /*oMPLLCON*/

mov     r1, #CLK_CTL_BASE

/*        mov     r2, #0x3*/

mov     r2, #0x3

str     r2, [r1, #0x14]            /*oCLKDIVN*/

mrc     p15, 0, r1, c1, c0, 0           @ read ctrl register

orr     r1, r1, #0xc0000000             @ Asynchronous

mcr     p15, 0, r1, c1, c0, 0           @ write ctrl register

@ now, CPU clock is 200 Mhz

mov     r1, #CLK_CTL_BASE

ldr     r2, mpll_200mhz

str     r2, [r1, #0x4]               /*oMPLLCON*/

/*

* we do sys-critical inits only at reboot,

* not when booting from ram!

*/

#ifdef CONFIG_INIT_CRITICAL

bl    cpu_init_crit ;跳到下面的子过程

#endif

relocate:;下面代码的��用是把u-boot的后续代码搬运到内存中

/*

* relocate armboot to RAM

*/

adr    r0, _start        /* r0

ldr    r2, _armboot_start

ldr    r3, _armboot_end

sub    r2, r3, r2        /* r2

ldr    r1, _TEXT_BASE        \board\smdk2410\config.mk中定义了_TEXT_BASE,表示把u-boot搬到内存中的相应位置,在这里是0x33F00000,相对于0x30000000来说是63MB的地方,朋友们可能要疑惑了,前面的文章不是介绍了我们用的板子是32M内存吗?那怎么是63M的地方呢,其实2410支持地址循环,这里其实就是31M的地方,哈哈,那u-boot不是把自己放在SDRAM中的最高的地方吗?的确是这样的。

add    r2, r0, r2        /* r2

/*

* r0 = source address

* r1 = target address

* r2 = source end address

*/

copy_loop:;开始拷贝

ldmia    r0!, {r3-r10}

stmia    r1!, {r3-r10}

cmp    r0, r2

ble    copy_loop

/* set up the stack */;最后我们在u-boot之后建立堆栈,为C语言的执行创建环境,否则是不允许执行C程序的,大小为128*1024

ldr    r0, _armboot_end

add    r0, r0, #CONFIG_STACKSIZE 该宏在\include\configs\smdk2410.h中定义

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

ldr    pc, _start_armboot

_start_armboot:    .word start_armboot;跳转到/lib_arm/board.c中的start_armboot()函数中运行了,到此我们完成了第一阶段,初始汇编代码的运行

/*

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

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

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

*/

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 memsetup.S in your board directory.

*/

mov    ip, lr

bl    memsetup ==〉上面英文注释就是,在重新定位之前,要初始化RAM,以及设置刷新频率

我们在本文的最后插上memsetup.S的代码。

mov    lr, ip

mov    pc, lr返回,并且回到上面,进行重定位

/*

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

*

* 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

add     r8, sp, #S_PC

ldr    r2, _armboot_end

add    r2, r2, #CONFIG_STACKSIZE

sub    r2, r2, #8

ldmia    r2, {r2 - r4}                   @ get pc, cpsr, old_r0

add    r0, sp, #S_FRAME_SIZE        @ restore sp_SVC

add    r5, sp, #S_SP

mov    r1, lr

stmia    r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_r

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_end        @ setup our mode stack

add    r13, r13, #CONFIG_STACKSIZE    @ resides at top of normal stack

sub    r13, r13, #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:

get_irq_stack

irq_save_user_regs

bl     do_irq

irq_restore_user_regs

.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

@ Processor clock values

.align 4

mpll_50mhz:

.long   vMPLLCON_50

mpll_100mhz:

.long   vMPLLCON_100

mpll_200mhz:

.long   vMPLLCON_200

.align    5

.globl reset_cpu

reset_cpu:

#ifdef CONFIG_S3C2400

bl    disable_interrupts

ldr    r1, _rWTCON

ldr    r2, _rWTCNT

/* Disable watchdog */

mov    r3, #0x0000

str    r3, [r1]

/* Initialize watchdog timer count register */

mov    r3, #0x0001

str    r3, [r2]

/* Enable watchdog timer; assert reset at timer timeout */

mov    r3, #0x0021

str    r3, [r1]

_loop_forever:

b    _loop_forever

_rWTCON:

.word    0x15300000

_rWTCNT:

.word    0x15300008

#else /* ! CONFIG_S3C2400 */

mov     ip, #0

mcr     p15, 0, ip, c7, c7, 0           @ invalidate cache

mcr     p15, 0, ip, c8, c7, 0           @ flush TLB (v4)

mrc     p15, 0, ip, c1, c0, 0           @ get ctrl register

bic     ip, ip, #0x000f                 @ ............wcam

bic     ip, ip, #0x2100                 @ ..v....s........

mcr     p15, 0, ip, c1, c0, 0           @ ctrl register

mov     pc, r0

#endif /* CONFIG_S3C2400 */

/

start.S到此结束

//下面就是初始化内存的代码

/board/smdk2410/memsetup.S

memsetup:

/* memory control configuration */

/* make r0 relative the current location so that it */

/* reads SMRDATA out of FLASH rather than memory ! */

ldr     r0, =SMRDATA

ldr    r1, _TEXT_BASE

sub    r0, r0, r1

ldr    r1, =BWSCON    /* Bus Width Status Controller */

add     r2, r0, #13*4

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 0x31

.word 0x30

.word 0x30

下篇文章,http://www.linuxidc.com/Linux/2011-08/39959.htm 我们主要分析start_armboot()函数的主要作用,其实该函数就是进行一系列的硬件初始化,然后进入main_loop,等待用户的命令,或者直接默认加载Linux内核,启动Linux,好了今天就到这吧,该休息了:) 0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值