[原创] S5PV210 uboot 启动分析

Wince.Android   2013-5-22 16:02 楼主

目录

1.编译配置

2.u-boot.lds连接配置文件

3.Stage1之start.S

4.Stage2之入口start_armboot


1.编译配置

    编译前先进行配置:make smdkv210single_config

    其中,Makefile中make smdkv210single_config为:

[cpp] view plaincopy


  • smdkv210single_config : unconfig  
  •     @$(MKCONFIG) $(@:_config=) arm s5pc11x smdkc110 samsung s5pc110  
  •     @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/smdkc110/config.mk  

    这里使用了Makefile中的替换引用规则,类似常看到的例子 obj=$(srcfiles:%.c=%.o): 由.c得到对应的.o文件.
    这里是一样的道理: $(@:_config=) ,@代表的是target smdkv210single_config, 那么$(@:_config=)就是将smdkv210single_config中的_config替换为空,

    即得到smdkv210single。


    这里$(@:_config=) arm s5pc11x smdkc110 samsung s5pc110都是mkconfig(即@$(MKCONFIG))的参数,mkconfig即根目录下的脚本文件。

    执行这句命令后,在include/下生成config.mk和config.h。并且Makefile包含这个config.mk。

    config.mk文件:


[cpp] view plaincopy


  • ARCH   = arm  
  • CPU    = s5pc11x  
  • BOARD  = smdkc110  
  • VENDOR = samsung  
  • SOC    = s5pc110  

    它指定里CPU架构,CPU型号,板子型号,CPU厂商,SOC??(母鸡啦)

    可以根据上面的这个信息找到对应的代码。比如说CPU代码在cpu/s5pc11x下,板子代码在board/samsung/smdkc110下。



2. u-boot.lds连接配置文件

      对于.lds文件,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置。u-boot.lds如何指定连接过程?首先它被根目录下config.mk引用,定义如下:LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds。根据这个路径,对于Android210而言,可以找到这个文件位于:board/samsung/smdkc110/u-boot.lds。其次,LDSCRIPT这个变量何时被用到?同样在config.mk中,可以找到:

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

       ifneq ($(TEXT_BASE),)
       LDFLAGS += -Ttext $(TEXT_BASE)
       endif

-T 参数指定生成可执行文件时ld连接器如何连接,TEXT_BASE是在make smdkv210single_config时写到board/samsung/smdkc110/config.mk中的,值为0xc3e00000。


[javascript] view plaincopy


  • /*
  • * (C) Copyright 2002
  • * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
  • *
  • * See file CREDITS for list of people who contributed to this
  • * project.
  • *
  • * This program is free software; you can redistribute it and/or
  • * modify it under the terms of the GNU General Public License as
  • * published by the Free Software Foundation; either version 2 of
  • * the License, or (at your option) any later version.
  • *
  • * This program is distributed in the hope that it will be useful,
  • * but WITHOUT ANY WARRANTY; without even the implied warranty of
  • * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  • * GNU General Public License for more details.
  • *
  • * You should have received a copy of the GNU General Public License
  • * along with this program; if not, write to the Free Software
  • * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  • * MA 02111-1307 USA
  • */  
  •   
  • OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm");指定输出可执行文件是elf格式,32位ARM指令,小端  
  • /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/  
  • OUTPUT_ARCH(arm);指定输出可执行文件的平台为ARM  
  • ENTRY(_start);指定输出可执行文件的起始代码段为_start  
  • SECTIONS  
  • {  
  •     . = 0x00000000; ;从0x0位置开始  
  •   
  •     . = ALIGN(4);  ;代码以4字节对齐  
  •     .text      :     ;指定代码段  
  •     {  
  •       cpu/s5pc11x/start.o   (.text)  
  •       cpu/s5pc11x/s5pc110/cpu_init.o    (.text)  
  •       board/samsung/smdkc110/lowlevel_init.o    (.text)  
  •           cpu/s5pc11x/onenand_cp.o      (.text)                  
  •           cpu/s5pc11x/nand_cp.o (.text)                       
  •           cpu/s5pc11x/movi.o (.text)   
  •           board/samsung/smdkc110/flash.o (.text)   
  •           common/secure.o (.text)   
  •       common/ace_sha1.o (.text)  
  •       cpu/s5pc11x/pmic.o (.text)  
  •       *(.text)  
  •     }  
  •   
  •     . = ALIGN(4);  
  •     .rodata : { *(.rodata) }    ;指定只读数据段  
  •   
  •     . = ALIGN(4);  
  •     .data : { *(.data) }    ;指定读/写数据段  
  •   
  •     . = ALIGN(4);  
  •     .got : { *(.got) }   ;指定got段, got段式是uboot自定义的一个段, 非标准段  
  •   
  •     __u_boot_cmd_start = .;   ;把__u_boot_cmd_start赋值为当前位置, 即起始位置  
  •     .u_boot_cmd : { *(.u_boot_cmd) }   ;指定u_boot_cmd段, uboot把所有的uboot命令放在该段  
  •     __u_boot_cmd_end = .;  ;把__u_boot_cmd_end赋值为当前位置,即结束位置  
  •   
  •     . = ALIGN(4);  
  •     .mmudata : { *(.mmudata) }   ;内存管理单元数据段  
  •   
  •     . = ALIGN(4);  
  •     __bss_start = .;  ;把__bss_start赋值为当前位置,即bss段的开始位置  
  •     .bss : { *(.bss) }   ;指定bss段  
  •     _end = .;  ;把_end赋值为当前位置,即bss段的结束位置  
  • }  



3.Stage1之start.S

     uboot是典型的bootloader之一,大多数bootloader都分为stage1和stage2两部分,u-boot也不例外。依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。u-boot的Stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下:

(1)定义入口。由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x00000000地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。
(2)设置异常向量(Exception Vector)。
(3)设置CPU的速度、时钟频率及终端控制寄存器。
(4)初始化内存控制器。
(5)将ROM中的程序复制到RAM中。
(6)初始化堆栈。
(7)转到RAM中执行,该工作可使用指令ldr pc来完成。

    根据config.mk中CPU的信息,找到对应的cpu目录为cpu/s5pc11x。首先看cpu/s5pc11x/start.S:

    其中代码解释引自:http://www.cnblogs.com/Efronc/archive/2012/02/28/2371662.html

[javascript] view plaincopy


  • /*
  • *  armboot - Startup Code for S5PC110/ARM-Cortex CPU-core
  • *
  • *  Copyright (c) 2009  Samsung Electronics
  • *
  • *
  • * See file CREDITS for list of people who contributed to this
  • * project.
  • *
  • * This program is free software; you can redistribute it and/or
  • * modify it under the terms of the GNU General Public License as
  • * published by the Free Software Foundation; either version 2 of
  • * the License, or (at your option) any later version.
  • *
  • * This program is distributed in the hope that it will be useful,
  • * but WITHOUT ANY WARRANTY; without even the implied warranty of
  • * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  • * GNU General Public License for more details.
  • *
  • * You should have received a copy of the GNU General Public License
  • * along with this program; if not, write to the Free Software
  • * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  • * MA 02111-1307 USA
  • *
  • * Base codes by scsuh (sc.suh)
  • */  
  • #include   
  • #include   
  • #if defined(CONFIG_ENABLE_MMU)  
  • #include   
  • #endif  
  • #include   
  • #ifndef CONFIG_ENABLE_MMU  
  • #ifndef CFG_PHY_UBOOT_BASE  
  • #define CFG_PHY_UBOOT_BASE  CFG_UBOOT_BASE  
  • #endif  
  • #endif  
  •   
  • /*
  • *************************************************************************
  • *
  • * Jump vector table as in table 3.1 in [1]
  • *
  • *************************************************************************
  • */  
  • #if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)    //阶段启动相关配置  
  •     .word 0x2000  
  •     .word 0x0  
  •     .word 0x0  
  •     .word 0x0  
  • #endif  
  •   
  • .globl _start  
  • _start: b   reset    //复位入口,此处使用b指令为相对调整,不依赖运行地址  
  •     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  
  • _pad:  
  •     .word 0x12345678 /* now 16*4=64 */    //保证16字节对齐  
  • .global _end_vect  
  • _end_vect:  
  •   
  •     .balignl 16,0xdeadbeef    //同样是保证16字节对齐,详见.align实验文章  
  • /*
  • *************************************************************************
  • *
  • * Startup Code (reset vector)    启动代码(复位向量)此处仅进行重要的初始化操作,搬移代码和建立堆栈
  • *
  • * do important init only if we don't start from memory!
  • * setup Memory and board specific bits prior to relocation.
  • * relocate armboot to ram
  • * setup stack
  • *
  • *************************************************************************
  • */  
  •   
  • _TEXT_BASE:  
  •     .word   TEXT_BASE    //TEST_BASE为根目录下Makefile传递进来的参数,具体为0xc3e00000  
  •   
  • /*
  • * Below variable is very important because we use MMU in U-Boot.
  • * Without it, we cannot run code correctly before MMU is ON.
  • * by scsuh.    //下面的代码非常重要,因为我们使用了MMU,没有这段代码,在MMC开启前我们将不能正确的运行代码
  • */  
  • _TEXT_PHY_BASE:  
  •     .word   CFG_PHY_UBOOT_BASE    //由dram的物理地址0x20000000加上0x3e00000而得,即0x23e00000.这个地址为MMU开启前的物理地址  
  •   
  • .globl _armboot_start  
  • _armboot_start:  
  •     .word _start    //复位地址,具体为0xc3e00010  
  •   
  • /*
  • * These are defined in the board-specific linker script.
  • */  
  • .globl _bss_start  
  • _bss_start:  
  •     .word __bss_start    //__bss_start在链接脚本文件中的bss段开始,_end在bss段结尾,用于清零bss端,这两个值在链接时才确定  
  •   
  • .globl _bss_end  
  • _bss_end:  
  •     .word _end  
  • #if defined(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 and IRQ & FIQ disable
  •      */  
  •     @;mrs   r0,cpsr  
  •     @;bic   r0,r0,#0x1f  
  •     @;orr   r0,r0,#0xd3  
  •     @;msr   cpsr,r0  
  •     msr cpsr_c, #0xd3       @ I & F disable, Mode: 0x13 - SVC    //进入svc模式,中断禁止  
  •   
  •   
  • /*
  • *************************************************************************
  • *
  • * CPU_init_critical registers
  • *
  • * setup important registers
  • * setup memory timing
  • *
  • *************************************************************************
  • */  
  •          /*
  •          * we do sys-critical inits only at reboot,    //仅在关键初始化时执行,而不是在从ram复位时执行
  •          * not when booting from ram!
  •          */  
  • cpu_init_crit:  
  • #ifndef CONFIG_EVT1  
  • #if 0     
  •     bl  v7_flush_dcache_all  
  • #else  
  •     bl  disable_l2cache    //禁止l2cache  
  •   
  •     mov r0, #0x0    @   
  •     mov r1, #0x0    @ i   
  •     mov r3, #0x0  
  •     mov r4, #0x0  
  • lp1:  
  •     mov r2, #0x0    @ j  
  • lp2:      
  •     mov r3, r1, LSL #29     @ r3 = r1(i) <<29  
  •     mov r4, r2, LSL #6      @ r4 = r2(j) <<6  
  •     orr r4, r4, #0x2        @ r3 = (i<<29)|(j<<6)|(1<<1)  
  •     orr r3, r3, r4  
  •     mov r0, r3          @ r0 = r3  
  •     bl  CoInvalidateDCacheIndex    //清除数据缓存 8 * 1024  
  •     add r2, #0x1        @ r2(j)++  
  •     cmp r2, #1024       @ r2 < 1024  
  •     bne lp2         @ jump to lp2  
  •     add r1, #0x1        @ r1(i)++  
  •     cmp r1, #8          @ r1(i) < 8  
  •     bne lp1         @ jump to lp1  
  •   
  •     bl  set_l2cache_auxctrl    //锁定l2cache  
  •       
  •     bl  enable_l2cache    //使能l2cache地址对齐  
  • #endif  
  • #endif  
  •       
  •     bl  disable_l2cache    //禁止l2cache  
  •   
  •     bl  set_l2cache_auxctrl_cycle    //锁定l2cache  
  •   
  •     bl  enable_l2cache    //使能l2cache  
  •       
  •        /*
  •         * Invalidate L1 I/D
  •         */  
  •         mov r0, #0                  @ set up for MCR  
  •         mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs    //禁止TLB  
  •         mcr p15, 0, r0, c7, c5, 0   @ invalidate icache    //禁止指令缓存  
  •   
  •        /*
  •         * disable MMU stuff and caches
  •         */  
  •         mrc p15, 0, r0, c1, c0, 0  
  •         bic r0, r0, #0x00002000     @ clear bits 13 (--V-)  
  •         bic r0, r0, #0x00000007     @ clear bits 2:0 (-CAM)  
  •         orr r0, r0, #0x00000002     @ set bit 1 (--A-) Align  
  •         orr r0, r0, #0x00000800     @ set bit 12 (Z---) BTB  
  •         mcr     p15, 0, r0, c1, c0, 0    //禁止MMC和cache  
  •   
  •   
  •         /* Read booting information */  
  •         ldr r0, =PRO_ID_BASE  
  •         ldr r1, [r0,#OMR_OFFSET]  
  •         bic r2, r1, #0xffffffc1    //读取启动信息  
  • #ifdef CONFIG_VOGUES  
  •     /* PS_HOLD(GPH0_0) set to output high */  
  •     ldr r0, =ELFIN_GPIO_BASE  
  •     ldr r1, =0x00000001  
  •     str r1, [r0, #GPH0CON_OFFSET]  
  •   
  •     ldr r1, =0x5500  
  •     str r1, [r0, #GPH0PUD_OFFSET]  
  •   
  •     ldr r1, =0x01  
  •     str r1, [r0, #GPH0DAT_OFFSET]  
  • #endif  
  •   
  •     /* NAND BOOT */  
  •     cmp r2, #0x0        @ 512B 4-cycle    //识别各种启动方式,并将识别到的启动识别码写入R3中  
  •     moveq   r3, #BOOT_NAND  
  •   
  •     cmp r2, #0x2        @ 2KB 5-cycle  
  •     moveq   r3, #BOOT_NAND  
  •   
  •     cmp r2, #0x4        @ 4KB 5-cycle   8-bit ECC  
  •     moveq   r3, #BOOT_NAND  
  •   
  •     cmp r2, #0x6        @ 4KB 5-cycle   16-bit ECC  
  •     moveq   r3, #BOOT_NAND  
  •   
  •     cmp r2, #0x8        @ OneNAND Mux  
  •     moveq   r3, #BOOT_ONENAND  
  •   
  •     /* SD/MMC BOOT */  
  •     cmp     r2, #0xc  
  •     moveq   r3, #BOOT_MMCSD   
  •   
  •     /* NOR BOOT */  
  •     cmp     r2, #0x14  
  •     moveq   r3, #BOOT_NOR     
  • #if 0   /* Android C110 BSP uses OneNAND booting! */  
  •     /* For second device booting */  
  •     /* OneNAND BOOTONG failed */  
  •     cmp     r2, #0x8  
  •     moveq   r3, #BOOT_SEC_DEV  
  • #endif  
  •   
  •     /* Uart BOOTONG failed */  
  •     cmp     r2, #(0x1<<4)  
  •     moveq   r3, #BOOT_SEC_DEV  
  •       
  •     ldr r0, =INF_REG_BASE  
  •     str r3, [r0, #INF_REG3_OFFSET]    //将启动标识码写入INF_REG3中  
  •   
  •     /*
  •      * Go setup Memory and board specific bits prior to relocation.    //重定位前初始化存储器和板特殊位
  •      */  
  •   
  •     ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */    //分配给u-boot的sram的结尾 sram为0xd0020000-d003ffff 分配大小为90k  
  •     sub sp, sp, #12 /* set stack */  
  •     mov fp, #0  
  •       
  •     bl  lowlevel_init   /* go setup pll,mux,memory */    //调用lowlevel_init函数初始化pll memory等与板子相关的内容 函数位于board目录下  
  •   
  •     /* To hold max8698 output before releasing power on switch,
  •      * set PS_HOLD signal to high
  •      */  
  •     ldr r0, =0xE010E81C  /* PS_HOLD_CONTROL register */    //PS_HOLD输出高电平,PS_HOLD使能。PMIC相关  
  •     ldr r1, =0x00005301  /* PS_HOLD output high */  
  •     str r1, [r0]  
  •   
  •     /* get ready to call C functions */  
  •     ldr sp, _TEXT_PHY_BASE  /* setup temp stack pointer */    //建立临时栈指针,内容为0x23e00000  
  •     sub sp, sp, #12  
  •     mov fp, #0          /* no previous frame, so fp=0 */  
  •   
  •     /* when we already run in ram, we don't need to relocate U-Boot.
  •      * and actually, memory controller must be configured before U-Boot    //如果程序已经在ram中运行,我们不需要重新定位u-boot。
  •      * is running in ram.    //实际上存储器一定在u-boot在ram中运行前被初始化了
  •      */  
  •     ldr r0, =0xff000fff  
  •     bic r1, pc, r0      /* r0 <- current base addr of code */    //r1=当前PC  
  •     ldr r2, _TEXT_BASE      /* r1 <- original base addr in ram */  
  •     bic r2, r2, r0      /* r0 <- current base addr of code */    //r2=定位后运行地址  
  •     cmp     r1, r2                  /* compare r0, r1                  */  
  •     beq     after_copy      /* r0 == r1 then skip flash copy   */    //如果r1=r2,跳过复制部分  
  • #if defined(CONFIG_EVT1)  
  •     /* If BL1 was copied from SD/MMC CH2 */  
  •     ldr r0, =0xD0037488  
  •     ldr r1, [r0]    //取0xd0037488地址的值  
  •     ldr r2, =0xEB200000  
  •     cmp r1, r2  
  •     beq     mmcsd_boot    //如果等于0xEB200000,跳转到mmcsd_boot  
  • #endif  
  •   
  •     ldr r0, =INF_REG_BASE    //读取存储的INF_REG3中的启动类型  
  •     ldr r1, [r0, #INF_REG3_OFFSET]  
  •     cmp r1, #BOOT_NAND      /* 0x0 => boot device is nand */  
  •     beq nand_boot  
  •     cmp r1, #BOOT_ONENAND   /* 0x1 => boot device is onenand */  
  •     beq onenand_boot  
  •     cmp     r1, #BOOT_MMCSD  
  •     beq     mmcsd_boot  
  •     cmp     r1, #BOOT_NOR  
  •     beq     nor_boot  
  •     cmp     r1, #BOOT_SEC_DEV  
  •     beq     mmcsd_boot  
  •   
  • nand_boot:  
  •     mov r0, #0x1000    //以下函数实现代码的搬移  
  •     bl  copy_from_nand  
  •     b   after_copy  
  •   
  • onenand_boot:  
  •     bl  onenand_bl2_copy  
  •     b   after_copy  
  •   
  • mmcsd_boot:  
  • #if DELETE  
  •     ldr     sp, _TEXT_PHY_BASE        
  •     sub     sp, sp, #12  
  •     mov     fp, #0  
  • #endif  
  •     bl      movi_bl2_copy  
  •     b       after_copy  
  •   
  • nor_boot:  
  •     bl      read_hword  
  •     b       after_copy  
  •   
  •   
  • after_copy:  
  • #if defined(CONFIG_ENABLE_MMU)  
  • enable_mmu:  
  •     /* enable domain access */  
  •     ldr r5, =0x0000ffff    //定义使能域的访问权限  
  •     mcr p15, 0, r5, c3, c0, 0       @load domain access register  
  •   
  •     /* Set the TTB register */  
  •     ldr r0, _mmu_table_base  
  •     ldr r1, =CFG_PHY_UBOOT_BASE  
  •     ldr r2, =0xfff00000  
  •     bic r0, r0, r2  
  •     orr r1, r0, r1  
  •     mcr p15, 0, r1, c2, c0, 0    //将MMU启用前的的mmu_table_base转成sdram中的地址,并写入cp15的c2中  
  •   
  •     /* Enable the MMU */  
  • mmu_on:  
  •     mrc p15, 0, r0, c1, c0, 0    //启用mmu  
  •     orr r0, r0, #1  
  •     mcr p15, 0, r0, c1, c0, 0  
  •     nop  
  •     nop  
  •     nop  
  •     nop  
  • #endif  
  •   
  • skip_hw_init:  
  •     /* Set up the stack                         */  
  • stack_setup:  
  • #if defined(CONFIG_MEMORY_UPPER_CODE)  
  •     ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)  
  • #else  
  •     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                        */  
  • #if defined(CONFIG_USE_IRQ)  
  •     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  
  • #endif  
  •     sub sp, r0, #12     /* leave 3 words for abort-stack    */    //为取址终止异常预留3个字空间  
  • #endif  
  •   
  • 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...                    */    //清除bss端内存  
  •     add r0, r0, #4  
  •     cmp r0, r1  
  •     ble clbss_l  
  •       
  •     ldr pc, _start_armboot  
  •   
  • _start_armboot:    //第一阶段结束,进入c程序阶段  
  •     .word start_armboot  
  • #if defined(CONFIG_ENABLE_MMU)  
  • _mmu_table_base:  
  •     .word mmu_table  
  • #endif  
  •   
  • /*
  • * copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)
  • * r0: size to be compared
  • * Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size
  • */  
  •     .globl copy_from_nand  
  • copy_from_nand:  
  •     push    {lr}        /* save return address */  
  •   
  •     mov r9, r0  
  •       
  •     mov r9, #0x100      /* Compare about 8KB */  
  •     bl  copy_uboot_to_ram    //从nandflash中读取512k到0x23e00000中  
  •   
  •     tst     r0, #0x0  
  •     bne copy_failed  
  • #if defined(CONFIG_EVT1)  
  •     ldr r0, =0xd0020000    //iram的起始地址  
  • #else     
  •     ldr r0, =0xd0030000    //iram的中间地址  
  • #endif  
  •     ldr r1, _TEXT_PHY_BASE  /* 0x23e00000 */  
  • 1:  ldr r3, [r0], #4    //取r0+4地址的值到r3中  
  •     ldr r4, [r1], #4    //取r1+4地址的值到r4中  
  •     teq r3, r4  
  •     bne compare_failed  /* not matched */    //如果r3和r4不相等,比较失败  
  •     subs    r9, r9, #4  
  •     bne 1b  
  •   
  •     pop {pc}        /* all is OK */    //复制成功,返回  
  •   
  • copy_failed:  
  •     nop         /* copy from nand failed */  
  •     b   copy_failed  
  •   
  • compare_failed:  
  •     nop         /* compare failed */  
  •     b   compare_failed  
  •   
  • /*
  • * we assume that cache operation is done before. (eg. cleanup_before_linux())
  • * actually, we don't need to do anything about cache if not use d-cache in U-Boot
  • * So, in this function we clean only MMU. by scsuh
  • *
  • * void theLastJump(void *kernel, int arch_num, uint boot_params);
  • */  
  • #if defined(CONFIG_ENABLE_MMU)  
  •     .globl theLastJump  
  • theLastJump:  
  •     mov r9, r0    //保存内核地址  
  •     ldr r3, =0xfff00000  
  •     ldr r4, _TEXT_PHY_BASE  
  •     adr r5, phy_last_jump  
  •     bic r5, r5, r3  
  •     orr r5, r5, r4  
  •     mov pc, r5  
  • phy_last_jump:  
  •     /*
  •      * disable MMU stuff    //关闭MMU
  •      */  
  •     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  
  •   
  •     mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */  
  •   
  •     mov r0, #0  
  •     mov pc, r9    //跳转到内核地址  
  • #endif  
  • /*
  • *************************************************************************
  • *
  • * 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       @ carve out a frame on current user stack  
  •     stmia   sp, {r0 - r12}          @ Save user registers (now in svc mode) r0-r12  
  •   
  •     ldr r2, _armboot_start  
  •     sub r2, r2, #(CFG_MALLOC_LEN)  
  •     sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack  
  •     ldmia   r2, {r2 - r3}           @ get values for "aborted" pc and cpsr (into parm regs)  
  •     add r0, sp, #S_FRAME_SIZE       @ grab pointer to old stack  
  •   
  •     add r5, sp, #S_SP  
  •     mov r1, lr  
  •     stmia   r5, {r0 - r3}           @ save sp_SVC, lr_SVC, pc, cpsr  
  •     mov r0, sp              @ save current stack into r0 (param register)  
  •     .endm  
  •   
  •     .macro  irq_save_user_regs  
  •     sub sp, sp, #S_FRAME_SIZE  
  •     stmia   sp, {r0 - r12}          @ Calling r0-r12  
  •     add r8, sp, #S_PC           @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.  
  •     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 (enter in banked mode)  
  •     sub r13, r13, #(CFG_MALLOC_LEN) @ move past malloc pool  
  •     sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ move to reserved a couple spots for abort stack  
  •   
  •     str lr, [r13]           @ save caller lr in position 0 of saved stack  
  •     mrs lr, spsr            @ get the spsr  
  •     str lr, [r13, #4]           @ save spsr in position 1 of saved stack  
  •   
  •     mov r13, #MODE_SVC          @ prepare SVC-Mode  
  •     @ msr   spsr_c, r13  
  •     msr spsr, r13           @ switch modes, make sure moves will execute  
  •     mov lr, pc              @ capture return pc  
  •     movs    pc, lr              @ jump to next instruction & switch modes.  
  •     .endm  
  •   
  •     .macro get_bad_stack_swi  
  •     sub r13, r13, #4            @ space on current stack for scratch reg.  
  •     str r0, [r13]           @ save R0's value.  
  •     ldr r0, _armboot_start      @ get data regions start  
  •     sub r0, r0, #(CFG_MALLOC_LEN)   @ move past malloc pool  
  •     sub r0, r0, #(CFG_GBL_DATA_SIZE+8)  @ move past gbl and a couple spots for abort stack  
  •     str lr, [r0]            @ save caller lr in position 0 of saved stack  
  •     mrs r0, spsr            @ get the spsr  
  •     str lr, [r0, #4]            @ save spsr in position 1 of saved stack  
  •     ldr r0, [r13]           @ restore r0  
  •     add r13, r13, #4            @ pop stack entry  
  •     .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_swi  
  •     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  
  • #if defined(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  
  •     .align 5  
  • .global arm_cache_flush  
  • arm_cache_flush:  
  •        mcr     p15, 0, r1, c7, c5, 0           @ invalidate I cache  
  •        mov     pc, lr                          @ back to caller  
  •   
  • /*
  • *     v7_flush_dcache_all()
  • *
  • *     Flush the whole D-cache.
  • *
  • *     Corrupted registers: r0-r5, r7, r9-r11
  • *
  • *     - mm    - mm_struct describing address space
  • */  
  •        .align 5  
  • .global v7_flush_dcache_all  
  • v7_flush_dcache_all:  
  •   
  •     ldr r0, =0xffffffff  
  •     mrc p15, 1, r0, c0, c0, 1       @ Read CLIDR  
  •     ands    r3, r0, #0x7000000  
  •     mov r3, r3, LSR #23             @ Cache level value (naturally aligned)  
  •     beq     Finished  
  •     mov r10, #0  
  • Loop1:           
  •     add r2, r10, r10, LSR #1        @ Work out 3xcachelevel  
  •     mov r1, r0, LSR r2              @ bottom 3 bits are the Ctype for this level  
  •     and r1, r1, #7                  @ get those 3 bits alone  
  •     cmp r1, #2  
  •     blt Skip                        @ no cache or only instruction cache at this level  
  •     mcr p15, 2, r10, c0, c0, 0      @ write the Cache Size selection register  
  •     mov r1, #0  
  •     mcr p15, 0, r1, c7, c5, 4       @ PrefetchFlush to sync the change to the CacheSizeID reg  
  •     mrc p15, 1, r1, c0, c0, 0       @ reads current Cache Size ID register  
  •     and r2, r1, #0x7                @ extract the line length field  
  •     add r2, r2, #4                  @ add 4 for the line length offset (log2 16 bytes)  
  •     ldr r4, =0x3FF  
  •     ands    r4, r4, r1, LSR #3          @ R4 is the max number on the way size (right aligned)  
  •     clz r5, r4                      @ R5 is the bit position of the way size increment  
  •     ldr r7, =0x00007FFF  
  •     ands    r7, r7, r1, LSR #13         @ R7 is the max number of the index size (right aligned)  
  • Loop2:           
  •     mov r9, r4                          @ R9 working copy of the max way size (right aligned)  
  • Loop3:           
  •     orr r11, r10, r9, LSL r5            @ factor in the way number and cache number into R11  
  •     orr r11, r11, r7, LSL r2            @ factor in the index number  
  •     mcr p15, 0, r11, c7, c6, 2      @ invalidate by set/way  
  •     subs    r9, r9, #1                  @ decrement the way number  
  •     bge Loop3  
  •     subs    r7, r7, #1                  @ decrement the index  
  •     bge Loop2  
  • Skip:            
  •     add r10, r10, #2                    @ increment the cache number  
  •     cmp r3, r10  
  •     bgt Loop1  
  • Finished:  
  •     mov pc, lr  
  •       
  •        .align  5  
  • .global disable_l2cache  
  • disable_l2cache:  
  •     mrc     p15, 0, r0, c1, c0, 1  
  •     bic     r0, r0, #(1<<1)  
  •     mcr     p15, 0, r0, c1, c0, 1  
  •     mov pc, lr  
  •   
  •   
  •        .align  5  
  • .global enable_l2cache  
  • enable_l2cache:  
  •     mrc     p15, 0, r0, c1, c0, 1  
  •     orr     r0, r0, #(1<<1)  
  •     mcr     p15, 0, r0, c1, c0, 1  
  •     mov     pc, lr  
  •   
  •        .align  5  
  • .global set_l2cache_auxctrl  
  • set_l2cache_auxctrl:  
  •     mov r0, #0x0  
  •     mcr     p15, 1, r0, c9, c0, 2  
  •     mov     pc, lr  
  •   
  •        .align  5  
  • .global set_l2cache_auxctrl_cycle  
  • set_l2cache_auxctrl_cycle:  
  •     mrc     p15, 1, r0, c9, c0, 2  
  •     bic     r0, r0, #(0x1<<29)  
  •     bic     r0, r0, #(0x1<<21)  
  •     bic     r0, r0, #(0x7<<6)  
  •     bic     r0, r0, #(0x7<<0)  
  •     mcr     p15, 1, r0, c9, c0, 2  
  •     mov     pc,lr  
  •   
  •     .align 5  
  • CoInvalidateDCacheIndex:  
  •     ;/* r0 = index */  
  •     mcr     p15, 0, r0, c7, c6, 2  
  •     mov     pc,lr  
  • #if defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_CINTEGRATOR)  
  • /* Use the IntegratorCP function from board/integratorcp/platform.S */  
  • #elif defined(CONFIG_S5PC11X)  
  • /* For future usage of S3C64XX*/  
  • #else  
  •     .align  5  
  • .globl reset_cpu  
  • reset_cpu:  
  •     ldr r1, rstctl  /* get addr for global reset reg */  
  •     mov r3, #0x2    /* full reset pll+mpu */  
  •     str r3, [r1]    /* force reset */  
  •     mov r0, r0  
  • _loop_forever:  
  •     b   _loop_forever  
  • rstctl:  
  •     .word   PM_RSTCTRL_WKUP  
  • #endif  

State 1最后,调用里start_armboot函数,这个函数是State2的入口函数。


4.Stage2之入口start_armboot

      start_armboot函数是纯C写的,位于lib_arm/board.c中。此函数经过一系列的动作之后,最终进入main_loop循环。main_loop位于common/main.c中,它主要用于执行common下定义的一些cmd。在正常启动的情况下,main_loop会在abortboot处等待n秒中(n一般是设置在uboot环境变量中,可以用getenv冲env中读取,一般设置成3s),然后从env中读取bootcmd的值,用run_command执行bootcmd命令。对于原始Android210来讲,bootcmd=nand read C0008000 600000 400000;bootm C0008000。

      bootcmd中调用里两个命令,分别是nand和bootm。

      nand命令,对应的源文件是common/cmd_nand.c。它的主要功能是...

      bootm命令,对应的源文件是common/cmd_bootm.c。命令格式:

[cpp] view plaincopy


  • U_BOOT_CMD(  
  •     bootm,  CFG_MAXARGS,    1,  do_bootm,  
  •     "bootm   - boot application image from memory\n",  
  •     "[addr [arg ...]]\n    - boot application image stored in memory\n"  
  •     "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"  
  •     "\t'arg' can be the address of an initrd image\n"  
  • #if defined(CONFIG_OF_LIBFDT)  
  •     "\tWhen booting a Linux kernel which requires a flat device-tree\n"  
  •     "\ta third argument is required which is the address of the\n"  
  •     "\tdevice-tree blob. To boot that kernel without an initrd image,\n"  
  •     "\tuse a '-' for the second argument. If you do not pass a third\n"  
  •     "\ta bd_info struct will be passed instead\n"  
  • #endif  
  • #if defined(CONFIG_FIT)  
  •     "\t\nFor the new multi component uImage format (FIT) addresses\n"  
  •     "\tmust be extened to include component or configuration unit name:\n"  
  •     "\taddr: - direct component image specification\n"  
  •     "\taddr#   - configuration specification\n"  
  •     "\tUse iminfo command to get the list of existing component\n"  
  •     "\timages and configurations.\n"  
  • #endif  
  • );  

可以看到命令名为bootm,对应执行函数为do_bootm:

[cpp] view plaincopy


  • /*******************************************************************/  
  • /* bootm - boot application image from image in memory */  
  • /*******************************************************************/  
  • int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  
  • {  
  •     image_header_t  *hdr;  
  •     ulong       addr;  
  •     ulong       iflag;  
  •     const char  *type_name;  
  •     uint        unc_len = CFG_BOOTM_LEN;  
  •     uint8_t     comp, type, os;  
  •   
  •     void        *os_hdr;  
  •     ulong       os_data, os_len;  
  •     ulong       image_start, image_end;  
  •     ulong       load_start, load_end;  
  •     ulong       mem_start;  
  •     phys_size_t mem_size;  
  •   
  •     struct lmb lmb;  
  •   
  •     memset ((void *)&images, 0, sizeof (images));  
  •     images.verify = getenv_yesno ("verify");  
  •   
  •         ...........  
  •    
  •         lmb_reserve(&lmb, load_start, (load_end - load_start));  
  •   
  • #if defined(CONFIG_ZIMAGE_BOOT)  
  • after_header_check:  
  •     os = hdr->ih_os;  
  • #endif  
  •   
  •     switch (os) {  
  •     default:            /* handled by (original) Linux case */  
  •     case IH_OS_LINUX:  
  • #ifdef CONFIG_SILENT_CONSOLE  
  •         fixup_silent_linux();  
  • #endif  
  •         do_bootm_linux (cmdtp, flag, argc, argv, &images);  
  •         break;  
  •   
  •     case IH_OS_NETBSD:  
  •         do_bootm_netbsd (cmdtp, flag, argc, argv, &images);  
  •         break;  
  •         .............  
  •   
  •     return 1;  
  • }  

其中有do_bootm_linux函数,这个函数是启动kernel的函数。对于Android210来讲,这个文件位于lib_arm/bootm.c中。do_bootm_linux:

[cpp] view plaincopy


  • void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],  
  •              bootm_headers_t *images)  
  • {  
  •     ulong   initrd_start, initrd_end;  
  •     ulong   ep = 0;  
  •     bd_t    *bd = gd->bd;  
  •     char    *s;  
  •     int machid = bd->bi_arch_number;  
  •     void    (*theKernel)(int zero, int arch, uint params);  
  •     int ret;  
  •   
  • #ifdef CONFIG_CMDLINE_TAG  
  •     char *commandline = getenv ("bootargs");  
  • #endif  
  •   
  •     /* find kernel entry point */  
  •     if (images->legacy_hdr_valid) {  
  •         ep = image_get_ep (&images->legacy_hdr_os_copy);  
  • #if defined(CONFIG_FIT)  
  •     } else if (images->fit_uname_os) {  
  •         ret = fit_image_get_entry (images->fit_hdr_os,  
  •                     images->fit_noffset_os, &ep);  
  •         if (ret) {  
  •             puts ("Can't get entry point property!\n");  
  •             goto error;  
  •         }  
  • #endif  
  •     } else {  
  •         puts ("Could not find kernel entry point!\n");  
  •         goto error;  
  •     }  
  •     theKernel = (void (*)(int, int, uint))ep;  
  •   
  •     s = getenv ("machid");  
  •     if (s) {  
  •         machid = simple_strtoul (s, NULL, 16);  
  •         printf ("Using machid 0x%x from environment\n", machid);  
  •     }  
  •   
  •     ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_ARM,  
  •             &initrd_start, &initrd_end);  
  •     if (ret)  
  •         goto error;  
  •   
  •     show_boot_progress (15);  
  •   
  •     debug ("## Transferring control to Linux (at address %08lx) ...\n",  
  •            (ulong) theKernel);  
  •   
  • #if defined (CONFIG_SETUP_MEMORY_TAGS) || \  
  •     defined (CONFIG_CMDLINE_TAG) || \  
  •     defined (CONFIG_INITRD_TAG) || \  
  •     defined (CONFIG_SERIAL_TAG) || \  
  •     defined (CONFIG_REVISION_TAG) || \  
  •     defined (CONFIG_LCD) || \  
  •     defined (CONFIG_VFD) || \  
  •     defined (CONFIG_MTDPARTITION)  
  •     setup_start_tag (bd);  
  • #ifdef CONFIG_SERIAL_TAG  
  •     setup_serial_tag (¶ms);  
  • #endif  
  • #ifdef CONFIG_REVISION_TAG  
  •     setup_revision_tag (¶ms);  
  • #endif  
  • #ifdef CONFIG_SETUP_MEMORY_TAGS  
  •     setup_memory_tags (bd);  
  • #endif  
  • #ifdef CONFIG_CMDLINE_TAG  
  •     setup_commandline_tag (bd, commandline);  
  • #endif  
  • #ifdef CONFIG_INITRD_TAG  
  •     if (initrd_start && initrd_end)  
  •         setup_initrd_tag (bd, initrd_start, initrd_end);  
  • #endif  
  • #if defined (CONFIG_VFD) || defined (CONFIG_LCD)  
  •     setup_videolfb_tag ((gd_t *) gd);  
  • #endif  
  •   
  • #ifdef CONFIG_MTDPARTITION  
  •     setup_mtdpartition_tag();  
  • #endif  
  •   
  •     setup_end_tag (bd);  
  • #endif  
  •   
  •     /* we assume that the kernel is in place */  
  •     printf ("\nStarting kernel ...\n\n");  
  •   
  • #ifdef CONFIG_USB_DEVICE  
  •     {  
  •         extern void udc_disconnect (void);  
  •         udc_disconnect ();  
  •     }  
  • #endif  
  •   
  •     cleanup_before_linux ();  
  •   
  •     theKernel (0, machid, bd->bi_boot_params);  
  •     /* does not return */  
  •     return;  
  •   
  • error:  
  •     do_reset (cmdtp, flag, argc, argv);  
  •     return;  
  • }  

do_bootm_linux中最后一个参数是bootm_headers_t *images。

如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460

回复评论 (5)

你怎么还玩S5PV210,人家都玩S6PV310啦
点赞  2013-5-22 16:14
引用: 原帖由 青叶漂零 于 2013-5-22 16:14 发表
你怎么还玩S5PV210,人家都玩S6PV310啦
版主哥哥,你笔误吧。你说的是S5pv310 吧。其实就是4210 ,这个已经停产了。——因为被4412 代替了
现在S5pv210 很适合玩啊。便宜,还有就是4412 ,贵点。
O(∩_∩)O~
我看你写个名字出来,我还以为出了一个新的处理器呢。
如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
点赞  2013-5-22 17:10
这篇文章挺适合看的。
如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
点赞  2014-3-20 09:26
引用: Wince.Android 发表于 2014-3-20 09:26
这篇文章挺适合看的。

应该是挺适合初学者看的。
如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
点赞  2014-3-20 09:27
谢谢GM
点赞  2014-3-20 10:57
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复