uboot启动(nand)

本文详细解析了U-Boot从NAND Flash启动的过程,包括S3C2440处理器的NAND启动配置、镜像文件的链接方式、启动代码的工作原理以及NAND数据的复制流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UBOOT从NANDFLASH启动分析
2009年12月15日 08:38 来源:ChinaUnix博客 作者:gentlly 编辑:周荣茂

    UBOOT从NAND FLASH启动分析

    在分析启动代码之前先看一下S3C2440的NAND启动:

    在配置NAND启动模式之后,S3C2440上电会先将NAND中的0x0 - 0x1000共4096字节的数据拷贝到位于Bank0中的Boot Internal SRAM上

    Bank0如下图:

    

    可以看出Boot Internal SRAM为4KB大小,也正是因为Boot Internal SRAM只有4KB大小,所以只能从NAND中拷贝4K的内容 = 3= 这个Boot Internal SRAM是配置为NAND FLASH启动模式才有的

    这4K内容是什么呢?~ 这就要看Uboot的镜像文件中是如何进行连接的了~

    连接脚本在board/smdk2440/u-boot.lds中,如下

    SECTIONS

    {

     . = 0x00000000;

     . = ALIGN(4);

     .text :

     {

     cpu/arm920t/start.o (.text)

     cpu/arm920t/s3c24x0/nand_read.o (.text)

     *(.text)

     }

     . = ALIGN(4);

     .rodata : { *(.rodata) }

     . = ALIGN(4);

     .data : { *(.data) }

     . = ALIGN(4);

     .got : { *(.got) }

     . = .;

     __u_boot_cmd_start = .;

     .u_boot_cmd : { *(.u_boot_cmd) }

     __u_boot_cmd_end = .;

     . = ALIGN(4);

     __bss_start = .;

     .bss : { *(.bss) }

     _end = .;

    }

    .text为代码段,可以看出cpu/arm920t/start.o在代码段的最前面,所以会先执行start.o中的代码

    连接完成后的镜像文件的前4K如下

    cpu/arm920t/start.o(.text)

     .text 0x33f80000 0x4e0 cpu/arm920t/start.o

     0x33f80050 IRQ_STACK_START

     0x33f80048 _bss_start

     0x33f8004c _bss_end

     0x33f80044 _armboot_start

     0x33f80000 _start

     0x33f80054 FIQ_STACK_START

     cpu/arm920t/s3c24x0/nand_read.o(.text)

     .text 0x33f804e0 0x1b8 cpu/arm920t/s3c24x0/nand_read.o

     0x33f804e0 nand_read_ll

     *(.text)

     .text 0x33f80698 0x64 board/smdk2440/libsmdk2440.a(lowlevel_init.o)

     0x33f8069c lowlevel_init

     .text 0x33f806fc 0x280 cpu/arm920t/libarm920t.a(interrupts.o)

     0x33f80934 do_fiq

     0x33f80880 do_undefined_instruction

     0x33f80744 show_regs

     0x33f80958 do_irq

     0x33f80728 bad_mode

     0x33f808c8 do_prefetch_abort

     0x33f8070c disable_interrupts

     0x33f80910 do_not_used

     0x33f808ec do_data_abort

     0x33f808a4 do_software_interrupt

     0x33f806fc enable_interrupts

     .text 0x33f8097c 0x250 cpu/arm920t/s3c24x0/libs3c24x0.a(interrupts.o)

     0x33f80aa4 set_timer

     0x33f80a20 reset_timer

     0x33f8097c interrupt_init

     0x33f80ba0 get_tbclk

     0x33f80a90 get_timer

     0x33f809f0 reset_timer_masked

     0x33f80a24 get_timer_masked

     0x33f80ab4 udelay

     0x33f80b10 udelay_masked

     0x33f80bac reset_cpu

     0x33f80b8c get_ticks

     .text 0x33f80bcc 0x150 cpu/arm920t/s3c24x0/libs3c24x0.a(speed.o)

     0x33f80c4c get_HCLK

     0x33f80cec get_PCLK

     0x33f80c44 get_FCLK

     0x33f80d14 get_UCLK

     .text 0x33f80d1c 0x1e8 cpu/arm920t/s3c24x0/libs3c24x0.a(cmd_s3c24xx.o)

     0x33f80d8c do_s3c24xx

     .text 0x33f80f04 0xdc cpu/arm920t/s3c24x0/libs3c24x0.a(serial.o)

     0x33f80f04 serial_setbrg

     0x33f80fa8 serial_tstc

     0x33f80f80 serial_putc

     0x33f80f58 serial_init

     0x33f80fb8 serial_puts

     0x33f80f68 serial_getc

     .text 0x33f80fe0 0x140 lib_arm/libarm.a(_divsi3.o)

     0x33f80fe0 __divsi3

    如何设置从0x33f80000开始呢?~这是链接的时候指定的

    在根目录下面的config.mk中有下面一句

    LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)

    关键就是其中的-Ttext $(TEXT_BASE),这句指明了代码段的起始地址

    而TEXT_BASE在board/smdk2440/config.mk中定义 TEXT_BASE = 0x33F8 0000

    为什么是0x33F8 0000呢?~

    这是将NAND中Uboot拷贝到RAM中的起始地址,所以在代码拷贝到RAM之前不能使用绝对地址来寻址数据,只能用相对地址

    在以下将用虚拟地址来指Uboot在RAM中的地址,也就是0x33F8 0000

    现在来看代码cpu/arm920t/start.S

    _start: ;异常处理向量表

     b start_code

     ldr pc, _undefined_instruction ;未定义指令异常:0x00000004

     ldr pc, _software_interrupt ;软中断异常:0x00000008

     ldr pc, _prefetch_abort ;预取异常:0x0000000C

     ldr pc, _data_abort ;数据异常:0x00000010

     ldr pc, _not_used ;未使用:0x00000014

     ldr pc, _irq ;外部中断请求IRQ:0x00000018

     ldr pc, _fiq ;快束中断请求FIQ:0x0000001C

    b start_code在虚拟地址0x33F8 0000处 , 拷贝到Boot Internal SRAM后则位于0x0处,所以b start_code是第一条执行的指令,

    start_code在cpu/arm920t/start.S中

    代码如下:

     //读取CPSR寄存器的内容到R0

     mrs r0,cpsr

     //清除R0中的0 - 4 这5个位后保存到R0中

     //也就是清除用户模式位

     bic r0,r0,#0x1f

     //置R0的0 1 4 6 7 位为真

     //也就是选择SVC模式,同时IRQ和FIQ被禁止,处理器处于ARM状态

     //关闭中断和快速中断

     orr r0,r0,#0xd3

     //将R0中的值保存到CPSR上

     msr cpsr,r0

    # define pWTCON 0x53000000 ;看门狗控制寄存器WTCON

    # define INTMSK 0x4A000008 ;中断屏蔽寄存器INTMSK

    # define INTSUBMSK 0x4A00001C ;辅助中断屏蔽寄存器,由于外设中断源太多,要用此寄存器屏蔽剩余的中断源

    # define LOCKTIME 0x4c000000 ;PLL锁定时间计数寄存器

    # define MPLLCON 0x4c000004 ;主时钟锁相环控制寄存器

    # define UPLLCON 0x4c000008

    # define CLKDIVN 0x4C000014 ;时钟分频寄存器/* clock divisor register */

    # define INTSUBMSK_val 0xffff

    # define MPLLCON_val ((184 12) + (2 4) + 2) /*406M*/

    # define UPLLCON_val ((60 12) + (4 4) + 2) /* 47M */

    # define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */

    # define CAMDIVN 0x4C000018

     //取得看门狗寄存器的地址

     ldr r0, =pWTCON

     //将R1寄存器清0

     mov r1, #0x0

     //将看门狗寄存器清0,即将看门狗禁止,包括定时器定时,溢出中断及溢出复位等

     str r1, [r0]

     /*

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

     */

     //设R1寄存器为0xFFFF FFFF

     mov r1, #0xffffffff

     //读取中断屏蔽寄存器的地址

     ldr r0, =INTMSK

     //将中断屏蔽寄存器中的位全设1,屏蔽所有中断

     str r1, [r0]

     //# define INTSUBMSK_val 0xffff

     //设R1寄存器为0xFFFF

     ldr r1, =INTSUBMSK_val

     //读取辅助中断屏蔽寄存器的地址

     ldr r0, =INTSUBMSK

     //将辅助中断屏蔽寄中的11个中断信号屏蔽掉,本人觉得INTSUBMS_val应设成7ff

     str r1, [r0]

     //# define LOCKTIME 0x4c000000

     //读取PLL锁频计数器寄存器地址到R0中

     ldr r0,=LOCKTIME

     //将R1设为0x00FF FFFF

     ldr r1,=0xffffff

     //M_LTIME为最大的0xFFF

     //U_LTIME为最大的0xFFF

     str r1,[r0] ;0xfff=4096>1800,远远满足锁定要求

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

     /* default FCLK is 120 MHz ! */

     //# define CLKDIVN 0x4C000014 /* clock divisor register */

     //读取时钟分频寄存器的地址

     ldr r0, =CLKDIVN

     //# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */

     //将R1设为0x7

     mov r1, #CLKDIVN_va

     //PDIVN - 1: PCLK has the clock same as the HCLK/2.

     //HDIVN - 11 : HCLK = FCLK/3 when CAMDIVN[8] = 0.

     // HCLK = FCLK/6 when CAMDIVN[8] = 1.

     str r1, [r0]

     /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */

     //# define CAMDIVN 0x4C000018

     //读取摄像头时钟分频寄存器的地址

     ldr r0, =CAMDIVN

     //将R1设为0

     mov r1, #0

     //将摄像头时钟分频寄存器清0

     str r1, [r0]

     /* Clock asynchronous mode */

     //MRC p15, 0, Rd, c1, c0, 0 ; read control register

     //读取控制寄存器中的值到R1中

     mrc p15, 0, r1, c1, c0, 0 ;将协处理器p15的寄存器c1和c0的值传到arm处理器的R1寄存器中

     //31 iA bit Asynchronous clock select

     //30 nF bit notFastBus select

     orr r1, r1, #0xc0000000 ;将最高两位置1

     //MCR p15, 0, Rd, c1, c0, 0 ; write control register

     //将R1中的值写到控制寄存器中

     mcr p15, 0, r1, c1, c0, 0 将arm的寄存器R1的32位数据传到协处理器p15的两个16位寄存器c1和c0

     //# define UPLLCON 0x4c000008

     //读取UPLL设置寄存器的地址到R0中

     ldr r0,=UPLLCON

     //# define UPLLCON_val ((60

     ldr r1,=UPLLCON_val

     //将R1中的值写入UPLL设置寄存器中

     str r1,[r0]

     //ARM920T为5级流水线,需要至少5个周期来让指令生效

     nop

     nop

     nop

     nop

     nop

     nop

     nop

     nop

     //读取MPLL设置寄存器的地址到R0中

     ldr r0,=MPLLCON

     //# define MPLLCON_val ((184

     ldr r1,=MPLLCON_val

     //将R1中的值写入MPLL设置寄存器中

     str r1,[r0]

    #define GPJCON 0x560000D0

    #define GPJDAT 0x560000D4

    #define GPJUP 0x560000D8

     //跳转到cpu_init_crit处执行

     //并将下一条指令的地址写入LR寄存器中

     bl cpu_init_crit

    cpu_init_crit在cpu/arm920t/start.S中

    代码如下:

    cpu_init_crit:

     /*

     * flush v4 I/D caches

     */

     //将R0寄存器置0

     mov r0, #0

     //Invalidate ICache and DCache SBZ MCR p15,0,Rd,c7,c7,0

     //禁止指令和数据cache

     mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */

     //Invalidate TLB(s) SBZ MCR p15,0,Rd,c8,c7,0

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

     /*

     * disable MMU stuff and caches

     */

     //MRC p15, 0, Rd, c1, c0, 0 ; read control register

     mrc p15, 0, r0, c1, c0, 0

     //清除[8] [9] [13] 这3个位

     //8 - System protection

     //9 - ROM protection

     //13 - Base location of exception registers - 0 = Low addresses = 0x00000000.

     bic r0, r0, #0x00002300 // clear bits 13, 9:8 (--V- --RS)

     //清除[0] [1] [2] [7] 这4个位

     // 0 - MMU enable - 0 = MMU disabled.

     // 1 - Alignment fault enable - 0 = Fault checking disabled.

     // 2 - DCache enable - 0 = DCache disabled.

     // 7 - Endianness - 0 = Little-endian operation.

     bic r0, r0, #0x00000087 // clear bits 7, 2:0 (B--- -CAM)

     //设置位[1]为真

     // 1 - Alignment fault enable - 1 = Fault checking enabled.

     orr r0, r0, #0x00000002 // set bit 2 (A) Align

     //设置位[12]为真

     //12 - ICache enable - 1 = ICache enabled.

     orr r0, r0, #0x00001000 // set bit 12 (I) I-Cache

     //MCR p15, 0, Rd, c1, c0, 0 ; write control register

     mcr p15, 0, r0, c1, c0, 0

     //将返回地址保存到IP中

     mov ip, lr

     //跳转到lowlevel_init中执行

     bl lowlevel_init

    cpu_init_crit在cpu/arm920t/start.S中

    代码如下:

    .globl lowlevel_init

     //读取下面标号为SMRDATA处的地址到R0中

     ldr r0, =SMRDATA

     //读取上面标号为_TEXT_BASE处的地址内容到R1中

     //也就是取得TEXT_BASE的值到R1中

     ldr r1, _TEXT_BASE

     //计算SMRDATA的相对地址保存到R0中

     //SMRDATA为虚拟地址,而TEXT_BASE为虚拟地址的起始地址

     //而现在Uboot的起始地址并不为虚拟地址

     //TEXT_BASE为0x33F8 0000,SMRDATA为0x33F8 06C8

     //而现在程序运行在起始地址为0x0000 0000的地方

     //所以需要计算以0x0000 0000为标准的相对地址

     sub r0, r0, r1

     //取得带宽与等待状态控制寄存器地址到R1中

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

     //一共需要设置13个寄存器,每个寄存器4字节

     add r2, r0, #13*4

    0:

     //读取R0所指的项的值到R3中后R0自加4字节

     ldr r3, [r0], #4

     //将R3中的值保存到R1所指的地址中后R1自加4字节

     str r3, [r1], #4

     //比较R0和R2是否相等,相等则说明13个寄存器全部设置完毕

     cmp r2, r0

     //不等则跳转到上面标号为0处的地址继续执行

     bne 0b

     //跳回到返回地址中继续执行

     mov pc, lr

     .ltorg

    /* the literal pools origin */

    SMRDATA:

     .word (0+(B1_BWSCON4)+(B2_BWSCON8)+(B3_BWSCON12)+(B4_BWSCON16)+(B5_BWSCON20)+(B6_BWSCON24)+(B7_BWSCON28))

     .word ((B0_Tacs13)+(B0_Tcos11)+(B0_Tacc8)+(B0_Tcoh6)+(B0_Tah4)+(B0_Tacp2)+(B0_PMC))

     .word ((B1_Tacs13)+(B1_Tcos11)+(B1_Tacc8)+(B1_Tcoh6)+(B1_Tah4)+(B1_Tacp2)+(B1_PMC))

     .word ((B2_Tacs13)+(B2_Tcos11)+(B2_Tacc8)+(B2_Tcoh6)+(B2_Tah4)+(B2_Tacp2)+(B2_PMC))

     .word ((B3_Tacs13)+(B3_Tcos11)+(B3_Tacc8)+(B3_Tcoh6)+(B3_Tah4)+(B3_Tacp2)+(B3_PMC))

     .word ((B4_Tacs13)+(B4_Tcos11)+(B4_Tacc8)+(B4_Tcoh6)+(B4_Tah4)+(B4_Tacp2)+(B4_PMC))

     .word ((B5_Tacs13)+(B5_Tcos11)+(B5_Tacc8)+(B5_Tcoh6)+(B5_Tah4)+(B5_Tacp2)+(B5_PMC))

     .word ((B6_MT15)+(B6_Trcd2)+(B6_SCAN))

     .word ((B7_MT15)+(B7_Trcd2)+(B7_SCAN))

     .word ((REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT)

     .word 0x32

     .word 0x30

     .word 0x30

    执行mov pc, lr后将返回到cpu_init_crit中

    剩下来还有2条指令

     //恢复返回地址到LR

     mov lr, ip

     //跳转到返回地址

     mov pc, lr

    执行完毕之后将返回到start_code中执行接下来的代码

    代码如下:

     //#define GPJCON 0x560000D0

     //取得J端口控制寄存器的地址到R0中

     LDR R0, = GPJCON

     //将R1设置为0x1 5555

     LDR R1, = 0x15555

     //将R1中的值保存到J端口控制寄存器

     //GPJ0 - 01 - Output

     //GPJ1 - 01 - Output

     //GPJ2 - 01 - Output

     //GPJ3 - 01 - Output

     //GPJ4 - 01 - Output

     STR R1, [R0]

     //#define GPJUP 0x560000D8

     //取得J端口上拉功能寄存器的地址到R0中

     LDR R0, = GPJUP

     //将R1设置为0x1F

     LDR R1, = 0x1f

     //将R1中的值保存到J端口上拉功能寄存器

     //禁止GPJ0 - GPJ4的上拉功能

     STR R1, [R0]

     //#define GPJDAT 0x560000D4

     //取得J端口数据寄存器的地址到R0中

     LDR R0, = GPJDAT

     //将R1设为0x0

     LDR R1, = 0x00

     //将R1中的值保存到J端口数据寄存器

     //将J端口数据寄存器清0

     STR R1, [R0]

    //下面是NAND数据拷贝过程

    //relocate:

    copy_myself:

     //#define S3C2440_NAND_BASE 0x4E000000

     //取得Nand Flash设置寄存器的地址

     mov r1, #S3C2440_NAND_BASE

     //将R2设为0xFFF0

     ldr r2, =0xfff0 // initial value tacls=3,rph0=7,rph1=7

     //#define oNFCONF 0x00

     //读取Nand Flash设置寄存器中的值到R3中

     ldr r3, [r1, #oNFCONF]

     //将R3或上R2后保存到R3中

     orr r3, r3, r2

     //将R3中的值保存到Nand Flash设置寄存器中

     //TWRPH0 - 111 - Duration = HCLK * (TWRPH0 + 1)

     //TACLS - 11 - Duration = HCLK * TACLS

     str r3, [r1, #oNFCONF]

     //#define oNFCONT 0x04

     //读取Nand Flash控制寄存器中的值到R3中

     ldr r3, [r1, #oNFCONT]

     //将R3的[0]位置1

     orr r3, r3, #1 // enable nand controller

     //将R3中的值保存到Nand Flash控制寄存器中

     //Mode - 1:Nand Flash Controller Enable

     str r3, [r1, #oNFCONT]

     //读取虚拟起始地址到R0中

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

     //预留malloc所需要的空间

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

     //预留bdinfo所需要的空间

     sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */

     //预留中断和快速中断向量表空间

     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

     //预留12字节给中断栈

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

     // copy u-boot to RAM

     //读取虚拟起始地址到R0中,作为目标地址

     ldr r0, _TEXT_BASE

     //将R1设为0,作为源地址

     mov r1, #0x0

     //将UBOOT大小的值保存在R2中,作为数据大小

     mov r2, #CFG_UBOOT_SIZE

     //跳转到nand_read_ll处执行

     //并将下一条指令的地址保存在LR中

     bl nand_read_ll

    nand_read_ll的原型为

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

    之前设置的R0 R1 R2为它的3个参数

    R0 - buf

    R1 - start_addr

    R2 - size

    nand_read_ll的代码在cpu/arm920t/s3c24x0/nand_read.c中

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

    {

     int i, j;

     //检测源地址和大小是否在NandFlash的边界上

     if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))

     //不在边界上则返回-1表示出错

     return -1; /* invalid alignment */

     /* chip Enable */

     // #define nand_select() (NFCONT &= ~(1

     //置NAND Flash控制寄存器中除Reg_nCE外所有的位为1

     //Reg_nCE - NAND FLASH Memory nFCE signal control

     //0 - Force nFCE to low (Enable chip select)

     nand_select();

     // #define nand_clear_RnB() (NFSTAT |= (1

     //置NAND Flash操作状态寄存器中的RnB_TransDetect位为1

     //When RnB low to high transition is occurred, this value set and issue interrupt if enabled.

     //To clear this value write '1'

     //1: RnB transition is detected

     nand_clear_RnB();

     for (i=0; i10; i++);

     //从源地址的首地址开始历便所要拷贝的数据大小

     for (i=start_addr; i (start_addr + size);)

     {

     //检测地址是否在NAND Flash的边界上

     if (start_addr % NAND_BLOCK_SIZE == 0)

     {

     //检测是否为坏块

     if (is_bad_block(i))

     {

     /* Bad block */

     //向后延伸一个存储块

     i += NAND_BLOCK_SIZE;

     size += NAND_BLOCK_SIZE;

     //跳到下一块

     continue;

     }

     }

     j = nand_read_page_ll(buf, i);

     //指向下一块

     i += j;

     buf += j;

     // LED_FLASH();

     }

     /* chip Disable */

     // #define nand_deselect() (NFCONT |= (1

     //置Reg_nCE位为1

     //NAND Flash Memory nFCE signal control

     //1: Force nFCE to High(Disable chip select)

     nand_deselect();

     return 0;

    }

    nand_read_ll将Uboot从NAND中拷贝到RAM中

    拷贝完成后将返回到start_code

    接下来的代码如下:

     //检测R0是否为0,R0为nand_read_ll的返回值

     tst r0, #0x0

     //为0则说明无错,跳转到ok_nand_read处执行

     beq ok_nand_read

    ok_nand_read:

     //将R0设为0

     mov r0, #0

     //ldr r1, =0x33f00000

     //将R1设为虚拟地址起始处

     ldr r1, _TEXT_BASE

     //检测0x400个字节

     mov r2, #0x400 // 4 bytes * 1024 = 4K-bytes

    go_next:

     //读取R0处地址的数据到R3中

     //然后R0自加4字节

     ldr r3, [r0], #4

     //读取R1处地址的数据到R4中

     //然后R1自加4字节

     ldr r4, [r1], #4

     //比较R3和R4的数据是否相等

     //也就是检测Boot Internal SRAM和RAM中的数据是否相等

     //以保证数据无错

     teq r3, r4

     //不等则跳转到notmatch

     bne notmatch

     //相等则R2自减4

     subs r2, r2, #4

     //当R2为0则跳转到done_nand_read

     beq done_nand_read

     //R2不为0则跳转回go_next继续检测

     bne go_next

    done_nand_read:

     LDR R0, = GPJDAT

     LDR R1, = 0x2

     STR R1, [R0]

    stack_setup:

     //读取虚拟起始地址到R0中

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

     //预留malloc所需要的空间

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

     //预留bdinfo所需要的空间

     sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */

     //预留中断和快速中断向量表空间

     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

     //预留12字节给中断栈

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

    clear_bss:

     //读取BSS段的起始地址

     ldr r0, _bss_start /* find start of bss segment */

     //读取BSS段的结束地址

     ldr r1, _bss_end /* stop here */

     //将R2设为0x0

     mov r2, #0x00000000 /* clear */

    clbss_l:

     //将R2中的值保存在R0所指的地址

     str r2, [r0] /* clear loop... */

     //R0自加4字节

     add r0, r0, #4

     //比较R0和R1是否相等

     cmp r0, r1

     //不等则说明清0还没结束

     ble clbss_l

     LDR R0, = GPJDAT

     LDR R1, = 0x1

     STR R1, [R0]

     //跳转到start_armboot处执行

     ldr pc, _start_armboot

    _start_armboot: .word start_armboot

    这里start_armboot是一个绝对地址,在朗成所修改的这个Uboot中为0x33F8 13F4

    执行ldr pc, _start_armboot之后将会跳到RAM中的绝对地址继续执行

    整理了一个流程图,分为3个存储器:

    1 Boot Internal SRAM , 接在BANK0,起始地址为0x0

    2 RAM , 接在BANK6,起始地址为0x3000 0000

    3 NAND FLASH,为单独寻址

    流程如下图:

    <img alt="" src="http://blogimg.chinaunix.net/blog/upfile2/090629231629.png" div="" <="">

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值