uboot源码分析——stage 1
2014-10-31 14:45
435 查看
我们人为的把uboot的启动分为stage1和stage2,区分的标准是以编程语言和代码的作用。stage1主要用arm汇编及一部分C的混合编程,完成底层硬件的初始化设置;stage2则完全用C实现,在进行一些硬件(外设)初始化的同时,为linux启动提供参数和软硬件环境。
Stage1源码分析
通过分析Makefile和u-boot.lds发现,cpu/arm920t/start.S文件经编译后最先执行。下面来分析一下这个文件。因为之前写过不少的裸机编程,所以还是比较好理解的,所以硬件操作的部分不会深入再去说明。#include <common.h> #include <config.h>包含两个头文件,include/config.h文件是自动生成的include/config.h:
#include <configs/mini2440.h> #include <asm/config.h>configs/mini2440.h,这文件是规定了针对mini2440开发板的一些配置信息。asm/config.h,你可能会觉得奇怪,为什么在/inclued/下找不到asm目录?还记得之前说过的软链接不,这里应该是asm-arm/config.h。它的内容:
#ifndef _ASM_CONFIG_H_ #define _ASM_CONFIG_H_ /* Relocation to SDRAM works on all ARM boards */ #define CONFIG_RELOC_FIXUP_WORKS #endif
接下来进入<span style="font-family: Verdana; font-size: 15.555556297302246px; line-height: 25.98958396911621px;">cpu/arm920t/start.S文件分析代码~~</span> .globl _start_start: b start_codeldr pc, _undefined_instructionldr pc, _software_interruptldr pc, _prefetch_abortldr pc, _data_abortldr pc, _not_usedldr pc, _irqldr 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定义异常向量表
_TEXT_BASE:.word TEXT_BASE指定代码的基地址TEXT_BASE,/board/tekkamanninjia/mini2440/config.mk中:
## SMDK2410 has 1 bank of 64 MB DRAM## 3000'0000 to 3400'0000## Linux-Kernel is expected to be at 3000'8000, entry 3000'8000# optionally with a ramdisk at 3080'0000## we load ourself to 33F8'0000## download area is 3300'0000 TEXT_BASE = 0x33F80000SMDK2410与mni2440同样是64M的SDRAM,这里应该是直接把SMDK2410的拿来用了。Linux-Kernel的入口地址在uboot中规定为3000'8000, 如果使用ramdisk则把ramdisk放在3080'0000。Uboot的入口地址为33F8'0000
.globl _armboot_start_armboot_start:.word _start_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__bss_start 在根目录的u-boot.lds文件中定义(按Makefile的意思是”These are defined in the board-specific linker script”.,但是我用的这个版本/board/tekkamanninja/mini2440目录下没有u-boot.lds,tekkamanninja把它放到了根目录下)__bss_start = .
#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:.word 0x0badc0de /* IRQ stack memory (calculated at run-time) */.globl FIQ_STACK_STARTFIQ_STACK_START:.word 0x0badc0de#endif如果定义了CONFIG_USE_IRQ那么标号IRQ_STACK_START所指向的地址作为IRQ的栈起始地址。起始地址为0x0badc0de你可能会觉得对这个值很奇怪,没关系,在后面会被修改,到时再说,现在先随意设置一个。CONFIG_USE_IRQ显然是一个宏,在某个.h文件中被定义。前面讲过start.S包含了几个个头文件,在configs/mini2440.h中:
//#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */#define CONFIG_USB_DEVICE 1#ifdef CONFIG_USB_DEVICE#define CONFIG_USE_IRQ 1#endif可以看到最终#define CONFIG_USE_IRQ 1,所以这一版的uboot是使用IRQ的,并且在此分配栈。FIQ同理。
/* * the actual start code */ start_code:重启以后跳到这里执行。
/* * set the cpu to SVC32 mode */mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0xd3msr cpsr, r0没什么好说的,设置处理器工作在32位系统模式。
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)/* * relocate exception table */ldr r0, =_startldr r1, =0x0mov r2, #16copyex:subs r2, r2, #1ldr r3, [r0], #4str r3, [r1], #4bne copyex#endif这段代码的本意是copy异常向量表到_start的绝对地址,但是在include/configs/mini2440.h文件中并没有定义这两个宏,所以这段代码不执行。
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)/* turn off the watchdog */ # if defined(CONFIG_S3C2400)# define pWTCON 0x15300000# define INTMSK 0x14400008 /* Interupt-Controller base addresses */# define CLKDIVN 0x14800014 /* clock divisor register */#else# define pWTCON 0x53000000# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */# define INTSUBMSK 0x4A00001C# define CLKDIVN 0x4C000014 /* clock divisor register */# endif#define CLK_CTL_BASE 0x4C000000 /* tekkaman */#define MDIV_405 0x7f << 12 /* tekkaman */#define PSDIV_405 0x21 /* tekkaman */#define MDIV_200 0xa1 << 12 /* tekkaman */#define PSDIV_200 0x31 /* tekkaman */ ldr r0, =pWTCONmov r1, #0x0str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */mov r1, #0xffffffffldr r0, =INTMSKstr r1, [r0]# if defined(CONFIG_S3C2410)ldr r1, =0x7ffldr r0, =INTSUBMSKstr r1, [r0]# endif #if defined(CONFIG_S3C2440)ldr r1, =0x7fffldr r0, =INTSUBMSKstr r1, [r0]#endif #if defined(CONFIG_S3C2440)/* FCLK:HCLK:PCLK = 1:4:8 */ldr r0, =CLKDIVNmov r1, #5str r1, [r0]mrc p15, 0, r1, c1, c0, 0orr r1, r1, #0xc0000000mcr p15, 0, r1, c1, c0, 0mov r1, #CLK_CTL_BASEmov r2, #MDIV_405add r2, r2, #PSDIV_405str r2, [r1, #0x04] /* MPLLCON tekkaman */ #else/* FCLK:HCLK:PCLK = 1:2:4 *//* default FCLK is 120 MHz ! */ldr r0, =CLKDIVNmov r1, #3str r1, [r0] mrc p15, 0, r1, c1, c0, 0orr r1, r1, #0xc0000000mcr p15, 0, r1, c1, c0, 0 /*write ctrl register tekkaman*/mov r1, #CLK_CTL_BASE /* tekkaman*/mov r2, #MDIV_200add r2, r2, #PSDIV_200str r2, [r1, #0x04]#endif#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440*/观看门狗,屏蔽中断。在/include/configs/mini2440.h文件中定义:#defineCONFIG_S3C24401/* in a SAMSUNG S3C2440 SoC */设置时钟405M左右,FCLK:HCLK:PCLK = 1:4:8 。
/* * we do sys-critical inits only at reboot, * not when booting from ram! */#ifndef CONFIG_SKIP_LOWLEVEL_INITbl cpu_init_crit#endif在看根目录下的README:- CONFIG_SKIP_LOWLEVEL_INIT[ARM only] If these variables are defined, then certain low level initializations (like setting up the memory controller) are omitted and/or U-Boot does not relocate itself into RAM.Normally these variables MUST NOT be defined. The only exception is when U-Boot is loaded (to RAM) by some other boot loader or by a debugger which performs these initializations itself.在包含的头文件中也没有找到CONFIG_SKIP_LOWLEVEL_INIT的宏定义,所以这里是要执行blcpu_init_crit的。跳转到cpu_init_crit看一下。
#ifndef CONFIG_SKIP_LOWLEVEL_INITcpu_init_crit:/* * flush v4 I/D caches */mov r0, #0mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches */mrc p15, 0, r0, c1, c0, 0bic 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) Alignorr r0, r0, #0x00001000 @ set bit 12 (I) I-Cachemcr p15, 0, r0, c1, c0, 0 /* * before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a lowlevel_init.S in your board directory. */mov ip, lr bl lowlevel_init mov lr, ipmov pc, lr#endif /* CONFIG_SKIP_LOWLEVEL_INIT */首先是对指令Cache、数据Cache的操作,全部关闭。“Caches是CPU内部的一个2级缓存,它的作用是将常用的数据和指令放在CPU内部。Caches是通过CP15管理的,刚上电的时候,CPU还不能管理Caches。上电的时候指令Cache可关闭,也可不关闭,但数据Cache一定要关闭,否则可能导致刚开始的代码里面,去取数据的时候,从Cache里面取,而这时候RAM中数据还没有Cache过来,导致数据预取异常 。”Disable MMU跳转到lowlevel_init 接下来分析/board/tekkamanninja/mini2440/lowlevel_init.S
_TEXT_BASE:.word TEXT_BASE .globl lowlevel_initlowlevel_init:/* memory control configuration *//* make r0 relative the current location so that it *//* reads SMRDATA out of FLASH rather than memory ! */ldr r0, =SMRDATAldr r1, =lowlevel_initsub r0, r0, r1adr r3, lowlevel_init /* r3 <- current position of code */add r0, r0, r3ldr r1, =BWSCON /* Bus Width Status Controller */add r2, r0, #13*40:ldr r3, [r0], #4str r3, [r1], #4cmp r2, r0bne 0b /* everything is fine now */mov pc, lr .ltorg/* the literal pools origin */ SMRDATA: .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) .word 0xb2 .word 0x30.word 0x30贴一下之前写裸板程序时初始化SDRAM的代码:
;Set memory control registers ;ldr r0,=SMRDATA adrl r0, SMRDATA ;be careful!ldr r1,=BWSCON ;BWSCON Addressadd r2, r0, #52 ;End address of SMRDATA 0ldr r3, [r0], #4str r3, [r1], #4cmp r2, r0bne %B0明确一点,我们的目标是将SMRDATA的值写进以BWSCON为首的连续的13个寄存器,已经知道了BWSCON的地址,所以只要知道SMRDATA的地址即可。下面的讨论是为了得到SMRDATA的加载地址:先看uboot源码中的:
ldr r0, =SMRDATAldr r1, =lowlevel_initsub r0, r0, r1SMRDATA的绝对地址减去lowlevel_init的绝对地址,得到SMRDATA到lowlevel_init的偏移量,查看System.map文件:
33f804e4 T lowlevel_init33f8051c t SMRDATA计算二者差存放在r0中,我们假设这个值是x。启动上电时,代码在nor中执行或从nand被拷入4k的stepstone这两种情况下,不管在norflash还是在stepstone中,SMRDATA到lowlevel_init的偏移量必定也是等于x,理解这一点很重要。
adr r3, lowlevel_init /* r3 <- current position of code */add r0, r0, r3通过adr位置无关指令指令得到lowlevel_init,注意是位置无关指令,得到的是pc+offset,所以r3保存的是lowlevel_init的当前运行地址,这时还没有进行代码的拷贝,所以必然是在4k之内。我们已经知道SMRDATA到lowlevel_init的偏移量x,那么lowlevel_init的当前地址+x就得到了SMRDATA的当前地址(加载地址)。剩下就是控制循环进行拷贝,没什么好说的。再看一下裸板程序中的代码,很简单,直接用adrlr0, SMRDATA得到了SMRDATA的加载地址。这里有两个疑问:既然可以adr r3, lowlevel_init,为什么不直接用adrr3, SMRDATA来获取SMRDATA的加载地址?个人理解:ADR伪指令格式 :ADR{cond} register, expr地址表达式expr的取值范围:当地址值是字节对齐时,其取指范围为: +255 ~ 255B;当地址值是字对齐时,其取指范围为: -1020 ~ 1020B;对于某些比较大的文件来说不能确保偏移量x的值小于1020B,而adrr3, lowlevel_init这条语句离lowlevel_init标号后很近,expr的值肯定是OK的。B.为什么不直接用adrl?这个没想明白。 执行完lowlevel_init以后跳转回cpu_init_crit,再从cpu_init_crit跳转回之前bl cpu_init_crit的地方。这里要注意lr寄存器的使用和保护。
/***************** CHECK_CODE_POSITION ******************************************/adr r0, _start /* r0 <- current position of code */ldr r1, _TEXT_BASE /* test if we run from flash or RAM */cmp r0, r1 /* don't reloc during debug */beq stack_setup/***************** CHECK_CODE_POSITION ******************************************/Check 代码是否运行在SDRAM中。为什么要确定当前代码的运行位置呢?这与copy code to sdram 有关,我们在把代码copy到sdram中的时候,代码从sdram中运行,同样会运行到这里,这时候经过判断就不需要再次copy代码了(个人理解=。=)。在SDRAM中运行: beqstack_setup直接跳到stack_setup。在nor或者stepstone中运行: 继续向下执行,其中就包括copy code to sdram。我们要模拟的是上电启动时代码的运行方式,所以,刚开始是从nor或者nand启动的,这里不进行beqstack_setup的跳转。沿着这个线索往下看代码。
/***************** CHECK_BOOT_FLASH ******************************************/ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM 0x4000003C*/mov r0, #0 /* r0 = 0 */str r0, [r1] mov r1, #0x3c /* address of men 0x0000003C*/ldr r0, [r1]cmp r0, #0bne relocate /* recovery */ldr r0, =(0xdeadbeef)ldr r1, =( (4<<28)|(3<<4)|(3<<2) )str r0, [r1]/***************** CHECK_BOOT_FLASH ******************************************/经过CHECK_CODE_POSITION 的判断,若程序能走到这一步,则说明是运行在在nor或者stepstone中。这段代码的作用:判断代码运行在norflash还是stepstone,即启动方式时norflash还是nandflash。看代码之前先了解s3c2440的Memory Map,0x0到0x4000 0000刚好是1G。0x4000 0000到0x4000 1000之间的4KB就是stepstone——Boot Internal SRAM。stepstone的物理地址为0x4000 0000到0x4000 1000,但是当从nandflash启动时,stepstone将被映射到0地址,并且nandflash的前4k会被Copy到stepstone中运行。下面来看代码:
ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM 0x4000003C*/mov r0, #0 /* r0 = 0 */str r0, [r1]这段代码的作用是将0x4000003C指向的4个Byte清零。
mov r1, #0x3c /* address of men 0x0000003C*/ldr r0, [r1]cmp r0, #0bne relocate这段代码是读0x3c地址处的值放在r0中,然后将该值与立即数0作比较。当nandflash启动时,0x4000003C和0x3c这两个地址指向的是stepstone中的同一个内存单元。当norfalsh启动时,0x4000003C指向的是stepstone,0x3c指向的是norflash中的对应存储单元。此时如果读出0x3c 的值是0,那么是nandflash启动,如果是非零,那么是norflash启动。你也许会有疑问:若果0x3c处的值本来就是0,那么这个判断不就不准确了吗?第一步在0x4000003C处清零,如果是nandflash启动,会不会破坏了0x3c处的代码?先看如下代码:
_start: b start_codeldr pc, _undefined_instructionldr pc, _software_interruptldr pc, _prefetch_abortldr pc, _data_abortldr pc, _not_usedldr pc, _irqldr 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这是定义异常向量表及异常向量的跳转地址,一共有15条指令,每条指令4字节,共有60字节。.balignl 16,0xdeadbeef表示前面的代码所占内存必须以16个字节对齐,不够的字节用0xdeadbeef来填充。我们希望得到的是64个字节,所以缺少的4字节刚好用一个0xdeadbeef来填充,且0xdeadbeef的地址为0x3c。所以0x3c地址处的值必不为零,且该值对程序没有影响。(说到判断启动方式,韦东山的视频里面还有一种方法,利用norflash和nandflash的硬件差异性,norflash是readonly的,stepstone是ReadAndWrite,向某个内存中写入一个值,再读出,如果等于写入的值,则是nand启动,反之则是nor启动) 这时面临两个选择,nandflash启动或者是norflash启动,由OM[1:0]来控制,当然,你只要选择开发板的跳线即可。从norflash启动:执行
bne relocate跳转到
/***************** NOR_BOOT *************************************************/relocate: /* relocate U-Boot to RAM */ /*********** CHECK_FOR_MAGIC_NUMBER***************/ldr r1, =(0xdeadbeef)cmp r0, r1bne loop3 /*********** CHECK_FOR_MAGIC_NUMBER***************/adr r0, _start /* r0 <- current position of code */ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ldr r2, _armboot_startldr r3, _bss_startsub r2, r3, r2 /* r2 <- size of armboot */add r2, r0, r2 /* r2 <- source end address */ copy_loop:ldmia r0!, {r3-r10} /* copy from source address [r0] */stmia r1!, {r3-r10} /* copy to target address [r1] */cmp r0, r2 /* until source end addreee [r2] */ble copy_loop/***************** NOR_BOOT *************************************************/首先是检验Magic number,0xdeadbeef如果不相等的话,进入死循环。相等的话copy code from nor to sdram。_start和_armboot_start都是0x0Source end address就是_bss_start 从nandflash启动CHECK_BOOT_FLASH的时候如果cmp r0, #0相等,则说明是nand启动。
/***************** NAND_BOOT *************************************************/ #define LENGTH_UBOOT 0x60000#define NAND_CTL_BASE 0x4E000000 #ifdef CONFIG_S3C2440/* Offset */#define oNFCONF 0x00#define oNFCONT 0x04#define oNFCMD 0x08#define oNFSTAT 0x20 @ reset NANDmov r1, #NAND_CTL_BASEldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )str r2, [r1, #oNFCONF]ldr r2, [r1, #oNFCONF]ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control str r2, [r1, #oNFCONT]ldr r2, [r1, #oNFCONT]ldr r2, =(0x6) @ RnB Clearstr r2, [r1, #oNFSTAT]ldr r2, [r1, #oNFSTAT]mov r2, #0xff @ RESET commandstrb r2, [r1, #oNFCMD]mov r3, #0 @ waitnand1: add r3, r3, #0x1cmp r3, #0xablt nand1 nand2:ldr r2, [r1, #oNFSTAT] @ wait readytst r2, #0x4beq nand2ldr r2, [r1, #oNFCONT]orr r2, r2, #0x2 @ Flash Memory Chip Disablestr r2, [r1, #oNFCONT]@ get read to call C functions (for nand_read())ldr sp, DW_STACK_START @ setup stack pointermov fp, #0 @ no previous frame, so fp=0 @ copy U-Boot to RAMldr r0, =TEXT_BASEmov r1, #0x0mov r2, #LENGTH_UBOOTbl nand_read_lltst r0, #0x0beq ok_nand_read bad_nand_read:loop2:b loop2 @ infinite loopok_nand_read:@ verifymov r0, #0ldr r1, =TEXT_BASEmov r2, #0x400 @ 4 bytes * 1024 = 4K-bytesgo_next:ldr r3, [r0], #4ldr r4, [r1], #4teq r3, r4bne notmatchsubs r2, r2, #4beq stack_setupbne go_next notmatch:loop3:b loop3 @ infinite loop#endif/***************** NAND_BOOT *************************************************/可能用到的寄存器:完成了代码的拷贝,接下来是设置栈:
stack_setup:ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */#ifdef CONFIG_USE_IRQsub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsub sp, r0, #12Mini2440.h中:#define CONFIG_USB_DEVICE 1#ifdef CONFIG_USB_DEVICE#define CONFIG_USE_IRQ 1#endif #define CONFIG_STACKSIZE (128*1024) /* regular stack */#ifdef CONFIG_USE_IRQ#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */#endif #define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 128*1024)#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */所以CONFIG_SYS_MALLOC_LEN为256k,CONFIG_ENV_SIZE为128KB,nandflash一个block的大小,等于64*2k,一个page大小为2K。
README中:NOTE: the bzip2 algorithm requires a lot of RAM, sothe malloc area (as defined by CONFIG_SYS_MALLOC_LEN) shouldbe at least 4MB.- CONFIG_SYS_MALLOC_LEN:Size of DRAM reserved for malloc() use.可见这里并没有把malloc area设置不小于4M,栈在内存中的分布如下图所示:根据“満栈减”的规则,之后栈的生长方向应该是向低地址。 接下来要清BSS段:
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... */add r0, r0, #4cmp r0, r1ble clbss_l这段代码也很简单,不用多说。
ldr pc, _start_armboot到_start_armboot标号所指向的内存中读取数据给pc,又有:
_start_armboot: .word start_armboot所以这里是把start_armboot的地址传给pc,pc跳到start_armboot函数处执行,接下来就是stage2的部分了。
相关文章推荐
- Uboot-1.1.2 do_bootm_linux函数源码分析
- Uboot 源码分析----启动代码
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- 三星uboot1.1.6源码分析——start.s(3)---从NAND复制uboot到外部RAM(2)
- uboot源码分析-运行时内存分布
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- uboot源码分析(1)
- uboot内核启动过程源码分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- Uboot 源码分析----代码整体结构分析
- uboot源码分析(3)
- uboot源码分析(1)uboot 命令解析流程简析
- uboot源码分析(3)
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- uboot源码分析及移植
- uboot源码分析(2)
- uboot源码分析(4)
- 三星uboot1.1.6源码分析——start.s(2)--从NAND复制uboot源码到RAM(1)
- uboot Makefile源码分析