00032: #include <config.h>
00033: #include <version.h>
1)#include <config.h>。config.h是在include目录下的,这个文件不是源码中本身存在的文件,而是配置过程中自动生成的文件。(详见mkconfig脚本)。这个文件的内容其实是包含了一个头文件:#include <configs/hi3519v101.h>".
2)经过分析后,发现start.S中包含的第一个头文件就是:include/configs/hi3519v101.h,这个文件是整个uboot移植时的配置文件。这里面是好多宏。因此这个头文件包含将include/configs/ hi3519v101.h文件和start.S文件关联了起来。因此之后在分析start.S文件时,主要要考虑的就是hi3519v101.h文件。
3)#include <version.h>。include/version.h中包含了include/version_autogenerated.h,这个头文件就是配置过程中自动生成的。里面就一行内容:#define U_BOOT_VERSION "U-Boot 1.3.4"。这里面定义的宏U_BOOT_VERSION的值是一个字符串,字符串中的版本号信息来自于Makefile中的配置值。这个宏在程序中会被调用,在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的。
00035: *************************************************************** 00035: ********** 00036: * 00037: * Jump vector table as in table 3.1 in [1] 00038: * 00039: *************************************************************** 00043: .globl _start /*系统复位位置,整个程序入口*/:_start是GNU汇编器的默认入口标签,.globl将_start声明为外部程序可访问的标签,.globl是GNU汇编的保留关键字,前面加点是GNU汇编的语法。.global就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局的,外部可以访问 . 00044: _start: b reset ---------------------------------------------------------reset代码分析------------------------------------------------------- 00125: /* 00126: * the actual reset code 00127: */ 00128: 00129: reset: 00130: /* 00131: * set the cpu to SVC32 mode 00132: */
1.设置SVC模式
对状态寄存器的修改要按照:读-改-写的顺序来执行
00133: mrs r0, cpsr //MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。 00134: bic r0, r0, #0x1f //BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中 00135: orr r0, r0, #0xd3//ORR指令用于在两个操作数上迕行逻辑戒运算,幵把结果放置到目的寄存器中 00136: msr cpsr,r0 //MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。 00137: 00138: /* 00139: * Invalidate L1 I/D 00140: */
2.关闭指令I/D缓存
00141: mov r0, #0 @ set up for MCR//r0清零 00142: mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs// r0放在C8 C7中,这个TLB是虚拟内存管理,后面再说、 00143: mcr p15, 0, r0, c7, c5, 0 @ invalidate icache//使之无效 00145: /* 00146: * disable MMU stuff and caches 00147: */
3.关闭MMU
00148: mrc p15, 0, r0, c1, c0, 0 00149: bic r0, r0, #0x00002000 @ clear bits 13 (--V-) 00150: bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) 00151: orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align 00152: orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB 00153: mcr p15, 0, r0, c1, c0, 0 00154: 00155: /* 00156: * read system register REG_SC_GEN2 00157: * check if ziju flag 00158: */
4.获取启动信息,先检测是不是自举模式,我猜测这个主要是分辨从PCIE启动还是FLASH启动
海思资料里面没有说明这些东西,无从分析。但整个逻辑应该是这样的:
芯片上电芯片内部的iROM一段代码会自动检测启动模式的引脚并把数值放在一个寄存器中,然后我们用数字去比较看哪个启动模式被激活,然后跳转执行相应的启动模式代码。
00159: ldr r0, =SYS_CTRL_REG_BASE //#define SYS_CTRL_REG_BASE 0x12020000
00160: ldr r1, [r0, #REG_SC_GEN2] // #define REG_SC_GEN2 0x0140-----》记录启动模式的寄存器,数据手册中没有这个寄存器,找不到! 00161: ldr r2, =0x7a696a75 /* magic for "ziju" */ 00162: ldr r3, [r0, #REG_SC_GEN20] // #define REG_SC_GEN20 0x0090---》pcie启动的寄存器标志,数据手册中找不到! 00162: /* pcie slave start up flag*/ 00163: cmp r3, r2 什么意思呢?就是检测是否pcie启动,如果是pcie启动,那么0x12020090中会标记pcie启动的幻数。如果与幻数一致,则跳入自举之后的操作。如果不相等则继续进行判断!因为pcie启动和flash启动操作是不一样的,这里是做了一个判断。 00164: beq after_ziju 或者说启动分为热启动和冷启动,冷启动一般都是需要自举的,不管是什么模式!热启动是指开启第二次启动,如敲reboot之后的启动,热启动会跳过一些步骤的,比如检测启动模式、DDR初始化等等。。。。貌似和这里没关系!这里认为是pcie启动的情况!使用的也是远跳转!但整个uboot我们默认从spiflash启动! 00165: cmp r1, r2 判断下记录启动模式的寄存器中的数值是否与标记pcie启动幻数是否一致!如果一致则保存sp,清除自举的启动模式标志寄存器!但冷启动一般都是走正常启动流程的!不相等我们继续看! 00166: bne normal_start_flow //跳转到正常启动流程,使用的b,不需要返回!汇编中用bl指令和mov pc,lr来实现子函数调用和返回 ------normal_start_flow代码解析------ 因为使用的是远跳转,回不来了,代码太多,后面分析 ------ normal_start_flow代码解析结束-- 00167: mov r1, sp /* save sp */ 00168: str r1, [r0, #REG_SC_GEN2] /* clear ziju flag */
--------------------------------after_ziju代码解析-------------------------
00169: after_ziju: 00170: /* init PLL/DDRC/pin mux/... */ 初始化PLL和DDRC控制器和管脚复用情况。 00171: ldr r0, _blank_zone_start //0x8840_0040
00172: ldr r1, _TEXT_BASE //0x8840_0000 00173: sub r0, r0, r1 //r0=0x40 00174: cmp r3, r2 //r2=0X7A696A75, r3=0X12020090,寄存器中的数值相减,如果相等则跳转到pcie的从模式地址 00175: beq pcie_slave_addr//跳转到pcie从模式的地址,也就是作为pcie从模式启动,我们不从pcie启动,继续分析! 00176: ldr r1, =RAM_START_ADRS #define RAM_START_ADRS 0x04010500 数据手册查不到 //上面应该是内部的RAM的起始地址。 00177: ldr sp, =STACK_TRAINING #define STACK_TRAINING 0x04017ff0 数据手册查不到
00178: b ziju_ddr_init 长跳转到自举模式的DDR初始化代码!从这里我可以推断出,芯片的启动分为两种,一种是自举模式也就是本地的spiflash或nand或emmc等启动,另一种就是pcie启动模式。不同启动模式对应不同的启动流程。但不同启动模式代码是相互交织的,需要分清楚! 00179: pcie_slave_addr: 00180: ldr r1, =0x0 00181: ldr sp, =PCIE_SLV_STACK #define PCIE_SLV_STACK 0x7000 00182: ldr r4, =SYS_CTRL_REG_BASE #define SYS_CTRL_REG_BASE 0x12020000 00183: str r2, [r4, #HI3519V101_SYSBOOT10] #define HI3519V101_SYSBOOT10 0x158 数据手册查不到
r2此时应该是保存了系统启动的一些参数,不知道什么参数,或者说是主控通过pcie加载uboot的地址?
00184: ziju_ddr_init:
自举模式的ddr初始化代码
00185: add r0, r0, r1 //r0=0x40 r1=0x8840_0000--àr0=0x88400040 00186: mov r1, #0x0 //r1=0,/* flags: 0->normal 1->pm ,使用正常启动*/ 00187: bl init_registers /* init PLL/DDRC/... */跳转到PLL和DDRC等的初始化,使用的是bl,还会跳回来! 这个函数是初始化一些寄存器,这些寄存器分了很多,包括中断、网络、哈希功能形式的寄存器,初始化的意思就是给一个值,但这值一般没什么意义,具体的寄存器,后面会再进行配置! 00188:
--------------------------------- after_ziju代码解析结束------------------
00189: /* after ziju, we need ddr traning */ 00190: /*#ifdef CONFIG_DDR_TRAINING_V2*/ 00191: ldr r0, =REG_BASE_SCTL #define SYS_CTRL_REG_BASE 0x12020000 #define REG_BASE_SCTL SYS_CTRL_REG_BASE 00192: bl start_ddr_training /* DDR training:DR布线,完全按等长约束就没有ddr training的说法。 当布线去掉等长约束或放宽约束条件,就要做ddr training,以保证时序的完整性,使信号的建立&保持时间窗口一致。ddr training是调整Addr/Cmd信号对CLK,DQ信号对DQS的延时。由于没做等长约束,信号有长,有短,就会导致信号有快,慢之差(信号在1000mil走线耗时约160~180ps,相对FR-4的板材),ddr training就是找到一套参数,使信号的建立与保持时间充足。并保存且写到配置中。*/ 00193: /*#endif*/ 00194: 00195: ldr r0, =SYS_CTRL_REG_BASE #define SYS_CTRL_REG_BASE 0x12020000 00196: ldr r2, =PCIE_SLV_DDR_INIT_FLG #define PCIE_SLV_DDR_INIT_FLG 0x8080 #define HI3519V101_SYSBOOT9 0x154 #define HI3519V101_SYSBOOT10 0x158 00197: str r2, [r0, #HI3519V101_SYSBOOT9] //写入寄存器 00198: ldr r2, =0x7a696a75 //pcie启动的幻数 00199: ldr r1, [r0, #HI3519V101_SYSBOOT10] 00200: cmp r1, r2 //比较bootrom的启动模式,如果相等则跳转到pcie从模式等待 00201: beq pcie_slave_hold 00202: ldr r1, [r0, #REG_SC_GEN2] 00203: mov sp, r1 /* restore sp */ 00204: ldr r1, [r0, #REG_SC_GEN3] 00205: mov pc, r1 /* return to bootrom */ 00206: pcie_slave_hold: 00207: ldr r2, [r0, #HI3519V101_SYSBOOT9] 00208: ldr r1, =0x7964616f /* complete flag */ 00209: cmp r1, r2 00210: bne pcie_slave_hold 00211: ldr r1, =0x0 00212: str r1, [r0, #HI3519V101_SYSBOOT9] 00213: mov pc, #0x0 //pc指针指向0x0 00214: nop 00215: nop 00216: nop 00217: nop 00218: nop 00219: nop 00220: nop 00221: nop 00222: b . /* bug here */
---------------------------------------------------------reset代码分析结束-------------------------------------------------------
_start后面加上一个冒号' :' ,表示其是一个标号Label,类似于C语言goto后面的标号。
00045: ldr pc, _undefined_instruction/*未定义指令异常,0x04*/ 00046: ldr pc, _software_interrupt/*软中断异常,0x08*/ 00047: ldr pc, _prefetch_abort/*内存操作异常,0x0c*/ 00048: ldr pc, _data_abort /*数据异常,0x10*/ 00049: ldr pc, _not_used /*/*未适用,0x14*/ 00050: ldr pc, _irq /*慢速中断异常,0x18*/ 00051: ldr pc, _fiq /*快速中断异常,0x1c*/一般用在实时性比较高的中断 00052: 00053: _undefined_instruction: .word undefined_instruction 00054: _software_interrupt: .word software_interrupt 00055: _prefetch_abort: .word prefetch_abort 00056: _data_abort: .word data_abort 00057: _not_used: .word not_used 00058: _irq: .word irq 00059: _fiq: .word fiq 00060: _pad: .word 0x12345678 /* now 16*4=64 */ 00061: __blank_zone_start: 00062: .fill 1024*5,1,0 .fill 1024*5,1,0 # 供保留1024*5项,每项一个字节,填充0,也就是填充0x1400个字节 00063: __blank_zone_end: 00064: 00065: .globl _blank_zone_start 00066: _blank_zone_start: 00067: .word __blank_zone_start 00068: 00070: .globl _blank_zone_end 00071: _blank_zone_end: 00072: .word __blank_zone_end 00073: 00074: .balignl 16,0xdeadbeef
1).balignl 16,0xdeadbeef. 这一句指令是让当前地址对齐排布,如果当前地址不对齐则自动向后走地址直到对齐,并且向后走的那些内存要用0xdeadbeef来填充。在这个.balignl 16,0xdeadbeef指令之前,一共占了4x15=60个字节的内存, 所以本代码的作者当时就简单的在15这个数上,加了个1,即16,把当前指针往后移到地址为64的位置,然后在前面插上了0xdeadbeef这个特殊的值。
2)0xdeadbeef这是一个十六进制的数字,这个数字很有意思,组成这个数字的十六进制数全是abcdef之中的字母,而且这8个字母刚好组成了英文的dead beef这两个单词,字面意思是坏牛肉。
3)为什么要对齐访问?有时候是效率的要求,有时候是硬件的特殊要求。
00075: /* 00075: **************************************************************** 00075: ******** 00076: * 00077: * Startup Code (reset vector) 00078: * 00079: * do important init only if we don't start from memory! 00080: * setup Memory and board specific bits prior to relocation. 00081: * relocate armboot to ram 00082: * setup stack 00083: * 00084: *************************************************************** 00084: **********/ 00086: _TEXT_BASE: 00087: .word TEXT_BASE
TEXT_BASE = 0x88400000,在board/hi3519v101/config.mk中可以看到。
00089: .globl _armboot_start 00090: _armboot_start: 00091: .word _start 00092: 00093: /* 00094: * These are defined in the board-specific linker script. 00095: */ 00096: .globl _bss_start 00097: _bss_start: 00098: .word __bss_start __bss_start和__bss_end定义在和开发板相关的u-boot.lds中,_bss_start和__bss_end保存的是__bss_start和__bss_end标号所在的地址。 00100: .globl _bss_end 00101: _bss_end: 00102: .word _end 00103: 00104: #ifdef CONFIG_USE_IRQ 00105: /* IRQ stack memory (calculated at run-time) */ 00106: .globl IRQ_STACK_START 00107: IRQ_STACK_START: 00108: .word 0x0badc0de 堆栈指针开始的地方,但目前我们初始化,还不知道,随便放了一个badcode 00110: /* IRQ stack memory (calculated at run-time) */ 00111: .globl FIQ_STACK_START 00112: FIQ_STACK_START: 00113: .word 0x0badc0de 00114: #endif 没用到,不分析了。 ----------------------------------------------------------------------------------------------------------------------------- 00116: _clr_remap_fmc_entry: 00117: .word FMC_TEXT_ADRS + do_clr_remap - TEXT_BASE #define FMC_TEXT_ADRS (FMC_MEM_BASE) #define FMC_MEM_BASE 0x14000000 00118: _clr_remap_ddr_entry: 00119: .word MEM_BASE_DDR + do_clr_remap - TEXT_BASE #define DDR_MEM_BASE 0x80000000 00120: _clr_remap_ram_entry: 00121: .word RAM_START_ADRS + do_clr_remap - TEXT_BASE #define RAM_START_ADRS 0x04010500 定义了三个地址入口,等待使用。。。。。 ------------------------------------------------------------------------------------------------------ 00123: _copy_abort_code: 00124: .word copy_abort_code 复制异常代码到0地址启动。 正常启动如下: 00224: normal_start_flow: 00225: /* init serial and printf a string. */ 00226: ldr sp, =STACK_TRAINING #define STACK_TRAINING 0x04017ff0 00227: bl uart_early_init 跳转到uart.S文件,进行uart的串口初始化 00228: bl msg_main_cpu_startup //输出startup字符串 00229: 00230: /* 00231: * enable cci snoop for GSF and VDMA 00232: */ 00233: ldr r0, =CCI_PORT_CTRL_0 00234: mov r3, #CCI_ENABLE_REQ 00235: str r3, [r0] 00236: 00237: 4: ldr r0, =CCI_CTRL_STATUS 00238: ldr r1, [r0] 00239: tst r1, #1 00240: bne 4b 00241: 00242: /* 00243: * enable cci snoop for core 0 00244: */ 00245: ldr r0, =CCI_PORT_CTRL_1 00246: mov r3, #CCI_ENABLE_REQ 00247: str r3, [r0] 00248: 00249: 5: ldr r0, =CCI_CTRL_STATUS 00250: ldr r1, [r0] 00251: tst r1, #1 00252: bne 5b //上面一部分是什么标准协议,不看了 00253: 00254: @if running not boot from nand/spi/emmc, 00255: @we skipping boot_type checking. 00256: mov r0, pc, lsr#24 //检测是否是热启动 00257: cmp r0, #0x0 //检测pc指针的高8位是否为0; 00258: bne check_bootrom_type //如果不相等,则是冷启动,跳转到启动模式检测 00259: 00260: check_boot_type: //冷启动,检测启动模式 00261: ldr r0, =SYS_CTRL_REG_BASE #define SYS_CTRL_REG_BASE 0x12020000 00262: ldr r0, [r0, #REG_SYSSTAT] #define REG_SYSSTAT 0x008c 00263: mov r6, r0, lsr#5
00264: and r6, #0x1 00265: cmp r6, #0 @ [5]=0 fmc 00265: /* SPI Nor/Nand and Nand */ 00266: ldreq pc, _clr_remap_fmc_entry //检测为SPI Nor/Nand and Nand启动 00267: 00268: @otherwise, [31]=1 means boot from bootrom, err 00269: beq bug 00270: check_bootrom_type: 00271: cmp r0, #0x4 00272: /* 00272: boot from bootrom,we copy the uboot.bin to ram (0x4010500)*/ 00273: ldreq pc, _clr_remap_ram_entry //片内RAM启动 00274: 00275: do_clr_remap: 00276: /* do clear remap */
我的理解是:在ROM从0x0用几句指令引导系统之后,把RAM映射到0x0就是Remap。
1.Remap的作用
当ARM处理器上电或者Reset之后,处理器从0x0 取指。因此,必须保证系统上电时,0x0 处有指令可以执行。所以,上电的时候,0x0地址处必定是ROM 或者Flash(NOR)。但是,为了加快启动的速度,也方便可以更改异常向量表,加快中断响应速度,往往把异常向量表映射到更快、更宽(32bit/16bit)的RAM 中。但是异常向量表的开始地址是由ARM架构决定的,必须位于0x0处,因此,必须把RAM映射到0x0。
2.Remap的配置
Remap的实现和ARM处理器的实现相关。
1)如果处理器有专门的寄存器可以完成Remap。那么Remap 是通过Remap 寄存器的相应bit置1 完成的。如Atmel AT91xx
2)如果处理器没有专门的寄存器,但是memory的bank控制寄存器可以用来配置bank的起始地址,那么只要把RAM的起始地址编程为0x0,也可以完成remap。如samsung s3c4510
3)如果上面两种机制都没有,那么Remap就不要做了。因为处理器实现决定了SDRAM对应的bank地址是不能改变的。如Samsung S3c2410.
3.Remap配置前后要做的工作
Remap 前后,不同之处就是RAM 的位置变了。为了达到Remap 的目的,就是加快启动的速度和异常处理速度,一定要初始化异常堆栈和建立异常向量表的。
4.如果象2410那样不能Remap的话怎么办?
2410 不是不能Remap吗?为了加快启动速度,可以这样做
1)使用它的NAND boot 模式。为什么NAND boot 会比较快,那是因为2410 里面有块小石头——“SteppingStone”,一块4KB SRAM,它是映射在0x0 的。启动程序会自动被copy 到这个石头里面。自然异常向量的入口放到这个地方,一样可以达到比NOR boot 快的启动、异常响应速度。
2)如果你对NOR Boot 情有独衷,那么你只好把你的异常向量的入口copy到SDRAM里面,实现所谓的High Vector
00277: ldr r4, =SYS_CTRL_REG_BASE 00278: ldr r0, [r4, #REG_SC_CTRL] 00279: 00280: @Set clear remap bit. 00281: orr r0, #(1<<8) 00282: str r0, [r4, #REG_SC_CTRL]
00283: 00284: /* 00285: * Set ACTLR.SMP to 1 00286: * This is a bug on Cortex-A7 MPCORE. see buglist of Cortex -A7 00287: * The D-caches are disabled when ACTLR.SMP is set to 0 reg 00287: ardless 00288: * of the value of the cache enable bit. so we must set SMP 00288: bit of 00289: * ACTLR register before enable D-cache 00290: */ 00291: mrc p15, 0, r0, c1, c0, 1 00292: orr r0, #(1 << 6) 00293: mcr p15, 0, r0, c1, c0, 1 /*以上清除重映射,清除重映射后地址0x000000 00295: @enable I-Cache now //使能I-cache 00296: mrc p15, 0, r0, c1, c0, 0 00297: orr r0, r0, #0x00001000 00297: /* set bit 12 (I) I-Cache */ 00298: mcr p15, 0, r0, c1, c0, 0 00299: 00300: @Check wether I'm running in dynamic mem bank mov r0, pc, lsr#28 cmp r0, #8 blo ddr_init //小于0,跳转到DDR初始化 00304: no_ddr_init: adrl r0, _start b copy_to_ddr //不需要DDR初始化,直接copy到DDR中 00308: ddr_init: ldr r0, _blank_zone_start ldr r1, _TEXT_BASE sub r0, r0, r1 adrl r1, _start add r0, r0, r1 mov r1, #0 /* flags: 0->normal 1->pm bl init_registers //上面分析过了 /*#ifdef CONFIG_DDR_TRAINING_V2*/ ldr sp, =STACK_TRAINING ldr r0, =REG_BASE_SCTL bl start_ddr_training /* DDR training */ /*#endif*/ //上面再DDR初始化中已经看过了 check_boot_mode: ldr r0, =SYS_CTRL_REG_BASE ldr r0, [r0, #REG_SYSSTAT] mov r6, r0, lsr#4 and r6, #0x3 cmp r6, #BOOT_FROM_EMMC //判断是不是EMMC启动 bne copy_flash_to_ddr //如果不是,则将flash代码拷贝到DDR中 #ifdef CONFIG_HIMCI_V200 emmc_boot: ldr r0, _TEXT_BASE //链接地址 ldr r1, _armboot_start //启动地址 ldr r2, _bss_start //bss段地址 sub r1, r2, r1 //bss段地址减去启动地址,剩下偏移,放入r1 bl emmc_boot_read //跳转emmc_boot_read,重定位并拷贝uboot到DDR中去 b jump_to_ddr //跳转到ddr中,不回来了 #endif copy_flash_to_ddr: /* relocate SPI nor/nand Boot to DDR */ cmp r6, #BOOT_FROM_DDR beq copy_to_ddr //重定位并拷贝uboot到内存中 ldr r0, =FMC_TEXT_ADRS /* 0x1400_0000 */ 00345: copy_to_ddr: /* now, r0 stores __reset offset from where we getstarted */ 00348: ldr r1, _TEXT_BASE /* r1 stores where we wil l copy uboot to */ /* compare source and target address, **if equal no copy to target address */ //如果是冷启动,则需要拷贝,如果是热启动,则不需要拷贝 cmp r0, r1 beq copy_abort_code //热启动,不需要拷贝 ldr r2, _armboot_start //热启动,直接运行 ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot * //基本上算是uboot的大小 /* memcpy(r1, r0, r2) */ bl memcpy jump_to_ddr: ldr r0, _TEXT_BASE ldr pc, _copy_abort_code copy_abort_code: ldr r1, =0x00000000 mov r2, #0x4000 /* memcpy(r1, r0, r2) */ bl memcpy /* Set up the stack */ stack_setup: //设置堆栈 ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot //链接地址,uboot的起始地址 sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area //堆栈大小:450kB sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo //128B #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 @ leave 3 words for abort-stack and sp, sp, #~7 @ 8 byte alinged for (ldr/str) d /* Clear BSS (if any). Is below tx (watch load addr - need space) */ clear_bss: //清理BSS段,这也是为什么栈不需要手动清空,这里帮你清空了 ldr r0, _bss_start @ find start of bss segment ldr r1, _bss_end @ stop here mov r2, #0x0 @ clear value clbss_l: str r2, [r0] @ clear BSS location cmp r0, r1 @ are we at the end yet add r0, r0, #4 @ increment clear index pointer bne clbss_l @ keep clearing till at end ldr pc, _start_armboot @ jump to C code //跳转到C语言阶段 _start_armboot: .word start_armboot
//海思的uboot第一阶段做了哪些东西
SVC模式
关cache
关MMU
检测是不是自举模式还是pcie启动,也包括是冷启动还是热启动
串口初始化
DDR初始化和DDR training
正常启动时,会检测启动方式,对代码进行相应的拷贝,重定位
设置堆栈
清bss段
跳转到第二阶段,即C语言阶段
---------------------