文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>uboot学习笔记(转)

uboot学习笔记(转)

时间:2009-06-01  来源:tancotq

u-boot-1.1.6学习笔记 Vicegod 2008-5-28 1、 u-boot-1.1.6 目录结构  .  |-- board -->平台依赖,存放电路板相关源文件的目录,例如:dave、smdk2410等  |-- cpu -->平台依赖,存放与具体CPU型号相关源文件的目录,例如:arm720t、arm920t、i386等  |-- lib_arm ----------------------------------------------------------------------------------------------------->  |-- lib_avr32 -->  |-- lib_blackfin -->  |-- lib_i386 -->平台依赖,用于存放对相应体系结构通用的文件,主要用于实现相关平台通用的函数  |-- lib_m68k -->比如lib_arm :  |-- lib_microblaze -->存放对ARM体系结构通用的文件,主要用于实现ARM平台通用的函数  |-- lib_mips -->  |-- lib_nios -->  |-- lib_nios2 -->  |-- lib_ppc ------------------------------------------------------------------------------------------------------->  |-- lib_generic -->通用,对所有体系结构通用的库函数的实现,比如vsprintf、string等函数的实现  |-- include -->通用,头文件和开发板配置文件,所有开发板的配置文件都在 include/configs目录下  |-- common -->通用,通用的多功能函数实现,比如U-BOOT的命令setenv、bootm、cp等函数的实现  |-- drivers -->通用,通用设备的驱动程序  |-- disk -->通用,硬盘接口驱动程序  |-- dtt -->通用,传感器的驱动程序  |-- fs -->通用,存放文件系统相关的程序
 |-- nand_spl -->通用,Nand Flash boot的程序
 |-- net -->通用,存放网络相关的程序  |-- post -->通用,存放上电自检的程序  |-- rtc -->通用,实时时钟(RTC)的驱动程序  |-- examples -->应用例程,一些独立运行的应用程序的例子,例如helloworld  |-- tools -->工具,存放制作S-Record或者U-boot格式的映像等工具,例如mkimage  `-- doc -->文档,开发使用文档 2、u-boot 启动流程:  |--> lowlevel_init: |  |--> cup_init_crit: | |--> cpu_init_crit: | _start: --> reset: | |--> reset: --> relocate: --> _start_armboot: --> Start_armboot() --> main_loop() ---|  ↑ |  |__________|  u-boot-1.1.6/cpu/xxx/Start.S _start:  u-boot-1.1.6/cpu/xxx/Start.S reset:  u-boot-1.1.6/cpu/xxx/Start.S cup_init_crit:  u-boot-1.1.6/board/yyy/lowlevel_init.S lowlevel_init:  u-boot-1.1.6/cpu/xxx/Start.S relocate:  u-boot-1.1.6/cpu/xxx/Start.S _start_armboot:  u-boot-1.1.6/lib_arm/board.c start_armboot()  u-boot-1.1.6/common/main.c main_loop()   说明:xxx(板子上具体的cpu型号,如arm920t)  yyy(开发板的型号,如smdk2410)
 
    3、u-boot-1.1.6/cpu/xxx/start.S分析 #include <config.h> #include <version.h> /* 这段代码的主要作用是初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备
好正确的环境 */
#if defined(CONFIG_OMAP1610) #include <./configs/omap1510.h> #elif defined(CONFIG_OMAP730) #include <./configs/omap730.h> #endif /*************************************************************************  *  * 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 /************************************************分析****************************************************  * 从中我们可以看出,ARM支持7种异常。问题是发生了异常后ARM是如何响应的呢?  * 第一个复位异常很好理解,它放在0x0的位置,一上电就执行它,而且我们的程序总是从 * 复位异常处理程序开始执行的,因此复位异常处理程序不需要返回。那么什么时候会执行 * 到后面几个异常处理函数呢?步骤是这样的:  *
 * 当一个异常出现以后,ARM会自动执行以下几个步骤:
 * (1) 把下一条指令的地址放到连接寄存器LR(通常是R14),这样就能够在处理异常返回时从正确的位置继续执行。  * (2) 将相应的CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中。从异常退出的时候,就可以由SPSR来恢复CPSR。  * (3) 根据异常类型,强制设置CPSR的运行模式位。  * (4) PC(程序计数器)被强制成相关异常向量处理函数地址,从而跳转到相应的异常处理程序中。  *  * 当异常处理完毕后,ARM会执行以下几步操作从异常返回:  * (1) 将连接寄存器LR的值减去相应的偏移量后送到PC中  * (2) 将SPSR复制回CPSR中  * (3) 若在进入异常处理时设置了中断禁止位,要在此清除  *  * ARM规定了异常向量的地址:  * b reset ; 复位 0x0  * ldr pc, _undefined_instruction ; 未定义的指令异常 0x4  * ldr pc, _software_interrupt ; 软件中断异常 0x8  * ldr pc, _prefetch_abort ; 预取指令 0xc  * ldr pc, _data_abort ; 数据 0x10  * ldr pc, _not_used ; 未使用 0x14  * ldr pc, _irq ; 慢速中断异常 0x18  * ldr pc, _fiq ; 快速中断异常 0x1c  * 这样理解这段代码就非常简单了。碰到异常时,PC会被强制设置为对应的异常向量,从而跳转到 * 相应的处理程序,然后再返回到主程序继续执行。  *  * .balignl 16,0xdeadbeef, 将地址对齐到16的倍数,如果地址寄存器的值(PC)跳过4个字节才是16的倍数, * 则使用0xdeadbeef填充这4个字节,如果它跳过1、2、3个字节,则填充值不确定。如果地址寄存器的值(PC) * 是16的倍数,则无需移动。
 ********************************************************************************************************/
/*************************************************************************  *  * 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   .globl _armboot_start _armboot_start:  .word _start   /* These are defined in the board-specific linker script.*/ .globl _bss_start _bss_start:  .word __bss_start   .globl _bss_end _bss_end:
 .word _end
  #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   /*************************************************分析**********************************************************  * 上面这段代码,主要保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者其它的使用。 * 还有一些变量的值是通过连接脚本得到的,比如TEXT_BASE位于/u-boot-1.1.6/board/xxx(开发板目录名称)/config.mk * 文件里。__bss_start、_end位于/u-boot-1.1.6/board/xxx(开发板目录名称)/u-boot.lds文件里,具体值是由编译器算出来的。  ***************************************************************************************************************/   /* the actual reset code*/ /* 系统的复位代码。系统一上电,就跳到这里运行 */ reset:  /*  * set the cpu to SVC32 mode  */
 mrs r0,cpsr /* 取得当前程序状态寄存器cpsr到r0 */
 bic r0,r0,#0x1f /* 这里使用位清除指令,把中断全部清除,只置位模式控制位 为中断提供服务通常是 OS *设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。 */  orr r0,r0,#0xd3 /* 计算为超级保护模式 */  msr cpsr,r0 /* 设置cpsr为超级保护模式 */   /***********************************************分析*************************************************************  * 设置cpu运行在SVC32模式。ARM共有7种模式:  * 用户模式(usr): arm处理器正常的程序执行状态  * 快速中断模式(fiq): 用于高速数据传输或通道处理  * 外部中断模式(irq): 用于通用的中断处理  * 超级保护模式(svc): 操作系统使用的保护模式  * 数据访问终止模式(abt): 当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护  * 系统模式(sys): 运行具有特权的操作系统任务  * 未定义指令中止模式(und): 当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真  * * 通过设置ARM的CPSR寄存器,让CPU运行在操作系统保护模式,为后面进行其它操作作好准备了。  ****************************************************************************************************************/    /*  * we do sys-critical inits only at reboot,  * not when booting from ram!  */   #ifndef CONFIG_SKIP_LOWLEVEL_INIT
 bl cpu_init_crit
/****************************************************************************** * BL为相对寻址,以程序计数器PC 的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址 * ARM 指令集中的4条跳转指令可以完成从当前指令向前或向后的32MB 的地址空间的跳转,  * 用的是相对寻址,它们是:B、BL、BLX、BX  *******************************************************************************/ #endif   #ifndef CONFIG_SKIP_RELOCATE_UBOOT /* 重定位Boot代码到RAM内存,将Boot代码从FLASH移到RAM中 */ relocate: /* relocate U-Boot to RAM */  adr r0, _start /* r0 <- current position of code */ /************************************************************************** * 把_start的相对地址移到r0, 相对寻址以程序计数器PC 的当前值为基地址, * 指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址。 * 它是与位置无关的,主要看Boot在哪里运行,也就是PC指针在哪里 (假设_start偏移量为0), * 例如这段代码在 0x02000000 (FLASH起始地址)运行,即此时PC=0x02000000,那么 adr r0, _start 得到 r0 = 0x02000000; * 如果在地址 0x81008000(Boot在RAM中加载地址)运行,即此时PC=0x81008000,那么r0就是 0x81008000 了。 * * 此处要注意ldr与adr的区别,看下面的代码片段: * ldr r0, _start * adr r0, _start * ldr r0, =_start * nop * mov pc, lr * _start:
* nop
* 下面是反汇编的结果: * 0c008000 <_start-0x14>: * c008000: e59f000c ldr r0, [pc, #12] ; c008014 <_start> * c008004: e28f0008 add r0, pc, #8 ; 0x8 * c008008: e59f0008 ldr r0, [pc, #8] ; c008018 <_start+0x4> * c00800c: e1a00000 nop (mov r0,r0) * c008010: e1a0f00e mov pc, lr * * 0c008014 <_start>: * c008014: e1a00000 nop (mov r0,r0) * * 分析: * ldr r0, _start * 从内存地址 _start 的地方把值读入。执行这个后,r0 = 0xe1a00000 * * adr r0, _start * 取得 _start 的地址到 r0,但是请看反编译的结果,它是与位置无关的。其实取得的是相对的位置。例如这段代码在 0x0c008000 运行, * 那么 adr r0, _start 得到 r0 = 0x0c008014;如果在地址 0 运行,就是 0x00000014 了。即当前PC值加上_start的偏移量。 * * ldr r0, =_start * 这个取得标号 _start 的绝对地址。这个绝对地址是在 link 的时候确定的。看上去这只是一个指令,但是它要占用 2 个 32bit 的空间, * 一条是指令,另一条是 _start 的数据(因为在编译的时候不能确定 _start 的值,所以不能直接用 mov 指令来给 r0 赋一个 32bit 的常量, * 所以需要多出一个空间存放 _start 的真正数据,这个数据是在 link 的时候确定的,在这里就是 0x0c008014)。 * 因此可以看出,这个是绝对的寻址,不管这段代码在什么地方运行,它的结果都是 r0 = 0x0c008014 **************************************************************************/
 ldr r1, _TEXT_BASE/* test if we run from flash or RAM */ /* 把_TEXT_BASE地址处的值TEXT_BASE,也就是BOOT在RAM中运行地址移到r1 */
 cmp r0, r1 /* don't reloc during debug */ /* 比较两个地址是否相同,如果相同,就已经在RAM运行,否则就是FLASH中运行 */  beq stack_setup   /* 如果是在FLASH中运行, 则把FLASH中的Boot代码移到RAM中,然后再运行 */  ldr r2, _armboot_start /* 把_armboot_start地址处的值也就是_start绝对地址(也即在内存中的地址,这个绝对 * 地址是在 link 的时候确定的,如0x81008000)移到r2 */  ldr r3, _bss_start /* 把_bss_start地址处的值也就是__bss_start绝对地址(也即在内存中的地址,这个绝对 * 地址是在 link 的时候确定的)移到r3 */  sub r2, r3, r2 /* r2 <- size of armboot */ /* 计算引导代码大小并存到r2 */  add r2, r0, r2 /* r2 <- source end address */ /* 计算引导代码最后相对地址并存入r2 */   copy_loop:  ldmia r0!, {r3-r10} /* copy from source address [r0] */ /* 从源地址[r0]读取32个字节到寄存器,并更新r0 */  stmia r1!, {r3-r10} /* copy to target address [r1] */ /* 拷贝寄存器r3-r10的32个字节值保存到 [r1]指明的地址,并更新r1的值 */  cmp r0, r2 /* until source end addreee [r2] */ /* 循环拷贝,直到把所有引导代码都移到内存 */  ble copy_loop #endif /* CONFIG_SKIP_RELOCATE_UBOOT */    /* Set up the stack */ /* 在内存中建立起堆栈 */ 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 */   /* 初始化内存中bss段中数据为0 */ clear_bss:  ldr r0, _bss_start /* find start of bss segment*/ /* 把_bss_start地址处存储的绝对地址移到r0 */  ldr r1, _bss_end /* stop here */ /* 把_bss_end地址处存储的绝对地址移到r1 */  mov r2, #0x00000000 /* clear */   clbss_l:  str r2, [r0] /* clear loop... STR 指令用于从源寄存器中r2将一个32 位的字数据传送到存储器中[r0]*/  add r0, r0, #4  cmp r0, r1  ble clbss_l /* 小于或等于跳转 */    ldr pc, _start_armboot /*********************************************************** * 已经准备好了堆栈,就可跳到C写的代码里了,也就是  * 跳到内存中的/u-boot-1.1.6/board.c --> start_armboot中运行了  * 把_start_armboot地址处的值也就是start_armboot绝对地址值移到pc  * 神啊!终于跳到C代码了。  ***********************************************************/ _start_armboot:  .word start_armboot   /*************************************************************************
 *
 * CPU_init_critical registers  *  * setup important registers  * setup memory timing  *  *************************************************************************/ /************************************************************************** * 1、关闭 MMU和CPU 内部指令/数据 (I/D)cache。 * 2、设置 CPU 的速度和时钟频率。 * 3 、RAM 初始化。 ****************************************************************************/ cpu_init_crit:  /* flush v4 I/D caches*/  mov r0, #0  mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ /****************************************************************************************************** * MCR 指令用于将ARM 处理器寄存器中的数据传送到协处理器寄存器中,格式为: * MCR 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。 * 其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作, * 源寄存器为ARM 处理器的寄存器,目的寄存器1 和目的寄存器2 均为协处理器的寄存器。 ******************************************************************************************************/  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    / * Go setup Memory and board specific bits prior to relocation.*/  mov ip, lr /* perserve link reg across call */  bl lowlevel_init /* go setup pll,mux,memory */ /* 位于u-boot-1.1.6/board/xxx(开发板目录名称)/lowlevel_init.S */  mov lr, ip /* restore link */  mov pc, lr /* back to my caller */ /* 从cpu_init_crit子函数返回 */ /*************************************************************************  *  * 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  @ carve out a frame on current user stack  sub sp, sp, #S_FRAME_SIZE  stmia sp, {r0 - r12} @ Save user registers (now in svc mode) 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  @ get values for "aborted" pc and cpsr (into parm regs)  ldmia r2, {r2 - r3}
 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  @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.  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 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_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 /*‘.align 5’向后移动位置计数器直至32(2^5)的倍数(计数器的最低的5位为0)。如果地址已经是32倍数,则无需移动。*/ 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 4、U-Boot启动内核分析 加载内核映像和根文件系统映像,规划它们的内存占用布局:   这里包括两个方面:(1)内核映像所占用的内存范围;(2)根文件系统所占用的内存范围。在规划内存占用的布局时,主要考虑基地址和映像的大小两个
方面。
  对于内核映像,一般将其拷贝到从(MEM_START+0x8000) 这个基地址开始的大约1MB大小的内存范围内(嵌入式 Linux 的内核一般都不操过 1MB)。
为什么要把从 MEM_START 到 MEM_START+0x8000 这段 32KB 大小的内存空出来呢?这是因为 Linux 内核要在这段内存中放置一些全局数据结
构,如:启动参数和内核页表等信息。而对于根文件系统映像,则一般将其拷贝到 MEM_START+0x0010,0000 开始的地方。如果用 Ramdisk 作为根文
件系统映像,则其解压后的大小一般是1MB。
 
应该说,在将内核映像和根文件系统映像拷贝到 RAM 空间中后,就可以准备启动 Linux 内核了。但是在调用内核之前,应该作一步准备工作,即:设
置 Linux 内核的启动参数。

 
调用内核: Boot Loader 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START+0x8000 地址处。在跳转时,下列条件要满足: 1. CPU 寄存器的设置: R0=0; R1=机器类型 ID;关于 Machine Type Number,可以参见 linux/arch/arm/tools/mach-types。 R2=启动参数标记列表在 RAM 中起始基地址;   2. CPU 模式: 必须禁止中断(IRQs和FIQs); CPU 必须 SVC 模式;   3. Cache 和 MMU 的设置: MMU 必须关闭; 指令 Cache 可以打开也可以关闭; 数据 Cache 必须关闭;     /*  * (C) Copyright 2002-2006  * Wolfgang Denk, DENX Software Engineering, [email protected].  *  * (C) Copyright 2002  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>  * Marius Groeger <[email protected]>  *
 * 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  */   /*  * To match the U-Boot user interface on ARM platforms to the U-Boot  * standard (as on PPC platforms), some messages with debug character  * are removed from the default U-Boot build.  *  * Define DEBUG here if you want additional info as shown below  * printed upon startup:
 *
 * U-Boot code: 00F00000 -> 00F3C774 BSS: -> 00FC3274  * IRQ Stack: 00ebff7c  * FIQ Stack: 00ebef7c  */   #include <common.h> #include <command.h> #include <malloc.h> #include <devices.h> #include <version.h> #include <net.h>   #ifdef CONFIG_DRIVER_SMC91111 #include "../drivers/smc91111.h" #endif #ifdef CONFIG_DRIVER_LAN91C96 #include "../drivers/lan91c96.h" #endif   DECLARE_GLOBAL_DATA_PTR;   #if (CONFIG_COMMANDS & CFG_CMD_NAND) void nand_init (void); #endif  
ulong monitor_flash_len;
  #ifdef CONFIG_HAS_DATAFLASH extern int AT91F_DataflashInit(void); extern void dataflash_print_info(void); #endif   #ifndef CONFIG_IDENT_STRING #define CONFIG_IDENT_STRING "" #endif   const char version_string[] =  U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;   #ifdef CONFIG_DRIVER_CS8900 extern void cs8900_get_enetaddr (uchar * addr); #endif   #ifdef CONFIG_DRIVER_RTL8019 extern void rtl8019_get_enetaddr (uchar * addr); #endif   /*  * Begin and End of memory area for malloc(), and current "brk"  */ static ulong mem_malloc_start = 0;
static ulong mem_malloc_end = 0;
static ulong mem_malloc_brk = 0;   static void mem_malloc_init (ulong dest_addr) {  mem_malloc_start = dest_addr;  mem_malloc_end = dest_addr + CFG_MALLOC_LEN;  mem_malloc_brk = mem_malloc_start;    memset ((void *) mem_malloc_start, 0,  mem_malloc_end - mem_malloc_start); }   void *sbrk (ptrdiff_t increment) {  ulong old = mem_malloc_brk;  ulong new = old + increment;    if ((new < mem_malloc_start) || (new > mem_malloc_end)) {  return (NULL);  }  mem_malloc_brk = new;    return ((void *) old); }
 
/************************************************************************  * Init Utilities *  ************************************************************************  * Some of this code should be moved into the core functions,  * or dropped completely,  * but let's get it working (again) first...  */   static int init_baudrate (void) {  char tmp[64]; /* long enough for environment variables */  int i = getenv_r ("baudrate", tmp, sizeof (tmp));  gd->bd->bi_baudrate = gd->baudrate = (i > 0)  ? (int) simple_strtoul (tmp, NULL, 10)  : CONFIG_BAUDRATE;    return (0); }   static int display_banner (void) {  printf ("\n\n%s\n\n", version_string);  debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",  _armboot_start, _bss_start, _bss_end); #ifdef CONFIG_MODEM_SUPPORT
 debug ("Modem Support enabled\n");
#endif #ifdef CONFIG_USE_IRQ  debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);  debug ("FIQ Stack: %08lx\n", FIQ_STACK_START); #endif    return (0); }   /*  * WARNING: this code looks "cleaner" than the PowerPC version, but  * has the disadvantage that you either get nothing, or everything.  * On PowerPC, you might see "DRAM: " before the system hangs - which  * gives a simple yet clear indication which part of the  * initialization if failing.  */ static int display_dram_config (void) {  int i;   #ifdef DEBUG  puts ("RAM Configuration:\n");    for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {  printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
 print_size (gd->bd->bi_dram[i].size, "\n");
 } #else  ulong size = 0;    for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {  size += gd->bd->bi_dram[i].size;  }  puts("DRAM: ");  print_size(size, "\n"); #endif    return (0); }   #ifndef CFG_NO_FLASH static void display_flash_config (ulong size) {  puts ("Flash: ");  print_size (size, "\n"); } #endif /* CFG_NO_FLASH */     /*  * Breathe some life into the board...
 *
 * Initialize a serial port as console, and carry out some hardware  * tests.  *  * The first part of initialization is running from Flash memory;  * its main purpose is to initialize the RAM so that we  * can relocate the monitor code to RAM.  */   /*  * All attempts to come up with a "common" initialization sequence  * that works for all boards and architectures failed: some of the  * requirements are just _too_ different. To get rid of the resulting  * mess of board dependent #ifdef'ed code we now make the whole  * initialization sequence configurable to the user.  *  * The requirements for any new initalization function is simple: it  * receives a pointer to the "global data" structure as it's only  * argument, and returns an integer return code, where 0 means  * "continue" and != 0 means "fatal error, hang the system".  */ typedef int (init_fnc_t) (void);   int print_cpuinfo (void); /* test-only */   init_fnc_t *init_sequence[] = {
 cpu_init, /* basic cpu dependent setup */
 board_init, /* basic board dependent setup */  interrupt_init, /* set up exceptions */  env_init, /* initialize environment */  init_baudrate, /* initialze baudrate settings */  serial_init, /* serial communications setup */  console_init_f, /* stage 1 init of console */  display_banner, /* say that we are here */ #if defined(CONFIG_DISPLAY_CPUINFO)  print_cpuinfo, /* display cpu info (and speed) */ #endif #if defined(CONFIG_DISPLAY_BOARDINFO)  checkboard, /* display board info */ #endif  dram_init, /* configure available RAM banks */  display_dram_config,  NULL, };   void start_armboot (void) {  init_fnc_t **init_fnc_ptr;  char *s; #ifndef CFG_NO_FLASH  ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)  unsigned long addr; #endif    /* Pointer is writable since we allocated a register for it */  gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));  /* compiler optimization barrier needed for GCC >= 3.4 */  __asm__ __volatile__("": : :"memory");    memset ((void*)gd, 0, sizeof (gd_t));  gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));  memset (gd->bd, 0, sizeof (bd_t));    monitor_flash_len = _bss_start - _armboot_start;    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {  if ((*init_fnc_ptr)() != 0) {  hang ();  }  }   #ifndef CFG_NO_FLASH  /* configure available FLASH banks */  size = flash_init ();  display_flash_config (size);
#endif /* CFG_NO_FLASH */
  #ifdef CONFIG_VFD # ifndef PAGE_SIZE # define PAGE_SIZE 4096 # endif  /*  * reserve memory for VFD display (always full pages)  */  /* bss_end is defined in the board-specific linker script */  addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);  size = vfd_setmem (addr);  gd->fb_base = addr; #endif /* CONFIG_VFD */   #ifdef CONFIG_LCD # ifndef PAGE_SIZE # define PAGE_SIZE 4096 # endif  /*  * reserve memory for LCD display (always full pages)  */  /* bss_end is defined in the board-specific linker script */  addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);  size = lcd_setmem (addr);  gd->fb_base = addr;
#endif /* CONFIG_LCD */
   /* armboot_start is defined in the board-specific linker script */  mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);   #if (CONFIG_COMMANDS & CFG_CMD_NAND)  puts ("NAND: ");  nand_init(); /* go init the NAND */ #endif   #ifdef CONFIG_HAS_DATAFLASH  AT91F_DataflashInit();  dataflash_print_info(); #endif    /* initialize environment */  env_relocate ();   #ifdef CONFIG_VFD  /* must do this after the framebuffer is allocated */  drv_vfd_init(); #endif /* CONFIG_VFD */    /* IP Address */  gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");  
 /* MAC Address */
 {  int i;  ulong reg;  char *s, *e;  char tmp[64];    i = getenv_r ("ethaddr", tmp, sizeof (tmp));  s = (i > 0) ? tmp : NULL;    for (reg = 0; reg < 6; ++reg) {  gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;  if (s)  s = (*e) ? e + 1 : e;  }   #ifdef CONFIG_HAS_ETH1  i = getenv_r ("eth1addr", tmp, sizeof (tmp));  s = (i > 0) ? tmp : NULL;    for (reg = 0; reg < 6; ++reg) {  gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;  if (s)  s = (*e) ? e + 1 : e;  } #endif
 }
   devices_init (); /* get the devices list going. */   #ifdef CONFIG_CMC_PU2  load_sernum_ethaddr (); #endif /* CONFIG_CMC_PU2 */    jumptable_init ();    console_init_r (); /* fully init console as a device */   #if defined(CONFIG_MISC_INIT_R)  /* miscellaneous platform dependent initialisations */  misc_init_r (); #endif    /* enable exceptions */  enable_interrupts ();    /* Perform network card initialisation if necessary */ #ifdef CONFIG_DRIVER_TI_EMAC  extern void emac_set_mac_addr (const char *addr);  if (getenv ("ethaddr")) {  emac_set_mac_addr(gd->bd->bi_enetaddr);  }
#endif
  #ifdef CONFIG_DRIVER_CS8900  cs8900_get_enetaddr (gd->bd->bi_enetaddr); #endif   #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)  if (getenv ("ethaddr")) {  smc_set_mac_addr(gd->bd->bi_enetaddr);  } #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */    /* Initialize from environment */  if ((s = getenv ("loadaddr")) != NULL) {  load_addr = simple_strtoul (s, NULL, 16);  } #if (CONFIG_COMMANDS & CFG_CMD_NET)  if ((s = getenv ("bootfile")) != NULL) {  copy_filename (BootFile, s, sizeof (BootFile));  } #endif /* CFG_CMD_NET */   #ifdef BOARD_LATE_INIT  board_late_init (); #endif #if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
 puts ("Net: "); #endif  eth_initialize(gd->bd); #endif  /* main_loop() can return to retry autoboot, if so just run it again. */  for (;;) {  main_loop ();  }    /* NOTREACHED - no way out of command loop except booting */ }   void hang (void) {  puts ("### ERROR ### Please RESET the board ###\n");  for (;;); }   #ifdef CONFIG_MODEM_SUPPORT static inline void mdm_readline(char *buf, int bufsiz);   /* called from main loop (common/main.c) */ extern void dbg(const char *fmt, ...); int mdm_init (void) {
 char env_str[16];
 char *init_str;  int i;  extern char console_buffer[];  extern void enable_putc(void);  extern int hwflow_onoff(int);    enable_putc(); /* enable serial_putc() */   #ifdef CONFIG_HWFLOW  init_str = getenv("mdm_flow_control");  if (init_str && (strcmp(init_str, "rts/cts") == 0))  hwflow_onoff (1);  else  hwflow_onoff(-1); #endif    for (i = 1;;i++) {  sprintf(env_str, "mdm_init%d", i);  if ((init_str = getenv(env_str)) != NULL) {  serial_puts(init_str);  serial_puts("\n");  for(;;) {  mdm_readline(console_buffer, CFG_CBSIZE);  dbg("ini%d: [%s]", i, console_buffer);  
 if ((strcmp(console_buffer, "OK") == 0) ||
 (strcmp(console_buffer, "ERROR") == 0)) {  dbg("ini%d: cmd done", i);  break;  } else /* in case we are originating call ... */  if (strncmp(console_buffer, "CONNECT", 7) == 0) {  dbg("ini%d: connect", i);  return 0;  }  }  } else  break; /* no init string - stop modem init */    udelay(100000);  }    udelay(100000);    /* final stage - wait for connect */  for(;i > 1;) { /* if 'i' > 1 - wait for connection  message from modem */  mdm_readline(console_buffer, CFG_CBSIZE);  dbg("ini_f: [%s]", console_buffer);  if (strncmp(console_buffer, "CONNECT", 7) == 0) {  dbg("ini_f: connected");  return 0;
 }
 }    return 0; }   /* 'inline' - We have to do it fast */ static inline void mdm_readline(char *buf, int bufsiz) {  char c;  char *p;  int n;    n = 0;  p = buf;  for(;;) {  c = serial_getc();    /* dbg("(%c)", c); */    switch(c) {  case '\r':  break;  case '\n':  *p = '\0';  return;
 
 default:  if(n++ > bufsiz) {  *p = '\0';  return; /* sanity check */  }  *p = c;  p++;  break;  }  } } #endif /* CONFIG_MODEM_SUPPORT */
相关阅读 更多 +
排行榜 更多 +
PvZ戴夫的时空冒险重置

PvZ戴夫的时空冒险重置

策略塔防 下载
PVZTV雪版阳光加50

PVZTV雪版阳光加50

策略塔防 下载
双刃战士雪姐

双刃战士雪姐

冒险解谜 下载