uboot源码分析——stage 1

来源:互联网 发布:mac ppt动画顺序调整 编辑:程序博客网 时间:2024/06/12 16:20

我们人为的把uboot的启动分为stage1stage2,区分的标准是以编程语言和代码的作用。

stage1主要用arm汇编及一部分C的混合编程,完成底层硬件的初始化设置;

stage2则完全用C实现,在进行一些硬件(外设)初始化的同时,为linux启动提供参数和软硬件环境。


Stage1源码分析


通过分析Makefileu-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:bstart_codeldrpc, _undefined_instructionldrpc, _software_interruptldrpc, _prefetch_abortldrpc, _data_abortldrpc, _not_usedldrpc, _irqldrpc, _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:.wordTEXT_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 = 0x33F80000

SMDK2410mni2440同样是64MSDRAM,这里应该是直接把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.ldstekkamanninja把它放到了根目录下)

__bss_start = .

 

#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:.word0x0badc0de /* 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 */mrsr0, cpsrbicr0, r0, #0x1forrr0, r0, #0xd3msrcpsr, r0

没什么好说的,设置处理器工作在32位系统模式。

 

#ifdefined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)/* * relocate exception table */ldrr0, =_startldrr1, =0x0movr2, #16copyex:subsr2, r2, #1ldrr3, [r0], #4strr3, [r1], #4bnecopyex#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 pWTCON0x15300000#  define INTMSK0x14400008/* Interupt-Controller base addresses */#  define CLKDIVN0x14800014/* clock divisor register */#else#  define pWTCON0x53000000#  define INTMSK0x4A000008/* Interupt-Controller base addresses */#  define INTSUBMSK0x4A00001C#  define CLKDIVN0x4C000014/* clock divisor register */# endif#define CLK_CTL_BASE0x4C000000/* tekkaman */#define MDIV_4050x7f << 12/* tekkaman */#define PSDIV_4050x21 /* tekkaman */#define MDIV_2000xa1 << 12/* tekkaman */#define PSDIV_2000x31 /* tekkaman */  ldrr0, =pWTCONmovr1, #0x0strr1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */movr1, #0xffffffffldrr0, =INTMSKstrr1, [r0]# if defined(CONFIG_S3C2410)ldrr1, =0x7ffldrr0, =INTSUBMSKstrr1, [r0]# endif #if defined(CONFIG_S3C2440)ldrr1, =0x7fffldrr0, =INTSUBMSKstrr1, [r0]#endif #if defined(CONFIG_S3C2440)/* FCLK:HCLK:PCLK = 1:4:8 */ldrr0, =CLKDIVNmovr1, #5strr1, [r0]mrcp15, 0, r1, c1, c0, 0orrr1, r1, #0xc0000000mcrp15, 0, r1, c1, c0, 0movr1, #CLK_CTL_BASEmovr2, #MDIV_405addr2, r2, #PSDIV_405strr2, [r1, #0x04] /* MPLLCON tekkaman */ #else/* FCLK:HCLK:PCLK = 1:2:4 *//* default FCLK is 120 MHz ! */ldrr0, =CLKDIVNmovr1, #3strr1, [r0] mrcp15, 0, r1, c1, c0, 0orrr1, r1, #0xc0000000mcrp15, 0, r1, c1, c0, 0/*write ctrl register tekkaman*/movr1, #CLK_CTL_BASE/* tekkaman*/movr2, #MDIV_200addr2, r2, #PSDIV_200strr2, [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_INITblcpu_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 */movr0, #0mcrp15, 0, r0, c7, c7, 0/* flush v3/v4 cache */mcrp15, 0, r0, c8, c7, 0/* flush v4 TLB */ /* * disable MMU stuff and caches */mrcp15, 0, r0, c1, c0, 0bicr0, r0, #0x00002300@ clear bits 13, 9:8 (--V- --RS)bicr0, r0, #0x00000087@ clear bits 7, 2:0 (B--- -CAM)orrr0, r0, #0x00000002@ set bit 2 (A) Alignorrr0, r0, #0x00001000@ set bit 12 (I) I-Cachemcrp15, 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. */movip, lr bllowlevel_init movlr, ipmovpc, lr#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

首先是对指令Cache、数据Cache的操作,全部关闭。“CachesCPU内部的一个2级缓存,它的作用是将常用的数据和指令放在CPU内部。Caches是通过CP15管理的,刚上电的时候,CPU还不能管理Caches。上电的时候指令Cache可关闭,也可不关闭,但数据Cache一定要关闭,否则可能导致刚开始的代码里面,去取数据的时候,从Cache里面取,而这时候RAM中数据还没有Cache过来,导致数据预取异常 。”

Disable MMU

跳转到lowlevel_init

 

接下来分析/board/tekkamanninja/mini2440/lowlevel_init.S

_TEXT_BASE:.wordTEXT_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_initsubr0, r0, r1adr r3, lowlevel_init /* r3 <- current position of code   */add     r0, r0, r3ldrr1, =BWSCON/* Bus Width Status Controller */add     r2, r0, #13*40:ldr     r3, [r0], #4str     r3, [r1], #4cmp     r2, r0bne     0b /* everything is fine now */movpc, 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 ;ldrr0,=SMRDATA adrlr0, SMRDATA;be careful!ldrr1,=BWSCON;BWSCON Addressaddr2, r0, #52;End address of SMRDATA 0ldrr3, [r0], #4strr3, [r1], #4cmpr2, r0bne%B0

明确一点,我们的目标是将SMRDATA的值写进以BWSCON为首的连续的13个寄存器,已经知道了BWSCON的地址,所以只要知道SMRDATA的地址即可。

下面的讨论是为了得到SMRDATA的加载地址:

先看uboot源码中的:

ldr     r0, =SMRDATAldr r1, =lowlevel_initsubr0, r0, r1

SMRDATA的绝对地址减去lowlevel_init的绝对地址,得到SMRDATAlowlevel_init的偏移量,查看System.map文件:

33f804e4 T  lowlevel_init33f8051c t  SMRDATA

计算二者差存放在r0中,我们假设这个值是x

启动上电时,代码在nor中执行或从nand被拷入4kstepstone

这两种情况下,不管在norflash还是在stepstone中,SMRDATAlowlevel_init的偏移量必定也是等于x,理解这一点很重要。

adrr3, lowlevel_init /* r3 <- current position of code   */add     r0, r0, r3

通过adr位置无关指令指令得到lowlevel_init,注意是位置无关指令,得到的是pc+offset,所以r3保存的是lowlevel_init的当前运行地址,这时还没有进行代码的拷贝,所以必然是在4k之内。

我们已经知道SMRDATAlowlevel_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 */cmpr0, r1 /* don't reloc during debug         */beqstack_setup/***************** CHECK_CODE_POSITION ******************************************/

Check 代码是否运行在SDRAM中。为什么要确定当前代码的运行位置呢?

这与copy code to sdram 有关,我们在把代码copysdram中的时候,代码从sdram中运行,同样会运行到这里,这时候经过判断就不需要再次copy代码了(个人理解==)。

SDRAM中运行:

  beqstack_setup直接跳到stack_setup

nor或者stepstone中运行:

 继续向下执行,其中就包括copy code to sdram。我们要模拟的是上电启动时代码的运行方式,所以,刚开始是从nor或者nand启动的,这里不进行beqstack_setup的跳转。沿着这个线索往下看代码。

 

/***************** CHECK_BOOT_FLASH ******************************************/ldrr1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM  0x4000003C*/movr0, #0 /* r0 = 0 */strr0, [r1]  movr1, #0x3c /* address of men  0x0000003C*/ldrr0, [r1]cmpr0, #0bnerelocate /* recovery  */ldrr0, =(0xdeadbeef)ldrr1, =( (4<<28)|(3<<4)|(3<<2) )strr0, [r1]/***************** CHECK_BOOT_FLASH ******************************************/

经过CHECK_CODE_POSITION 的判断,若程序能走到这一步,则说明是运行在在nor或者stepstone中。

这段代码的作用:判断代码运行在norflash还是stepstone,即启动方式时norflash还是nandflash



看代码之前先了解s3c2440Memory Map0x00x4000 0000刚好是1G

0x4000 00000x4000 1000之间的4KB就是stepstone——Boot Internal SRAM

stepstone的物理地址为0x4000 00000x4000 1000,但是当从nandflash启动时,stepstone将被映射到0地址,并且nandflash的前4k会被Copystepstone中运行。

下面来看代码:

ldrr1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM  0x4000003C*/movr0, #0 /* r0 = 0 */strr0, [r1]

这段代码的作用是将0x4000003C指向的4Byte清零。

movr1, #0x3c /* address of men  0x0000003C*/ldr r0, [r1]cmpr0, #0bnerelocate

这段代码是读0x3c地址处的值放在r0中,然后将该值与立即数0作比较。

nandflash启动时,0x4000003C0x3c这两个地址指向的是stepstone中的同一个内存单元。

norfalsh启动时,0x4000003C指向的是stepstone0x3c指向的是norflash中的对应存储单元。

此时如果读出0x3c 的值是0,那么是nandflash启动,如果是非零,那么是norflash启动。

你也许会有疑问:

若果0x3c处的值本来就是0,那么这个判断不就不准确了吗?

第一步在0x4000003C处清零,如果是nandflash启动,会不会破坏了0x3c处的代码?

先看如下代码:

_start:bstart_codeldrpc, _undefined_instructionldrpc, _software_interruptldrpc, _prefetch_abortldrpc, _data_abortldrpc, _not_usedldrpc, _irqldrpc, _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地址处的值必不为零,且该值对程序没有影响。

(说到判断启动方式,韦东山的视频里面还有一种方法,利用norflashnandflash的硬件差异性,norflashreadonly的,stepstoneReadAndWrite,向某个内存中写入一个值,再读出,如果等于写入的值,则是nand启动,反之则是nor启动)

 

这时面临两个选择,nandflash启动或者是norflash启动,由OM[1:0]来控制,当然,你只要选择开发板的跳线即可。

norflash启动:

执行

bnerelocate

跳转到

/***************** NOR_BOOT *************************************************/relocate: /* relocate U-Boot to RAM    */      /*********** CHECK_FOR_MAGIC_NUMBER***************/ldrr1, =(0xdeadbeef)cmpr0, r1bneloop3      /*********** CHECK_FOR_MAGIC_NUMBER***************/adrr0, _start /* r0 <- current position of code   */ldrr1, _TEXT_BASE/* test if we run from flash or RAM */ldrr2, _armboot_startldrr3, _bss_startsubr2, r3, r2 /* r2 <- size of armboot            */addr2, r0, r2 /* r2 <- source end address         */ copy_loop:ldmiar0!, {r3-r10} /* copy from source address [r0]    */stmiar1!, {r3-r10} /* copy to   target address [r1]    */cmpr0, r2 /* until source end addreee [r2]    */blecopy_loop/***************** NOR_BOOT *************************************************/

首先是检验Magic number0xdeadbeef如果不相等的话,进入死循环。

相等的话copy code from nor to sdram

_start_armboot_start都是0x0

Source 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 NANDmovr1, #NAND_CTL_BASEldrr2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )strr2, [r1, #oNFCONF]ldrr2, [r1, #oNFCONF]ldrr2, =( (1<<4)|(0<<1)|(1<<0) )@ Active low CE Control strr2, [r1, #oNFCONT]ldrr2, [r1, #oNFCONT]ldrr2, =(0x6)@ RnB Clearstrr2, [r1, #oNFSTAT]ldrr2, [r1, #oNFSTAT]movr2, #0xff@ RESET commandstrbr2, [r1, #oNFCMD]movr3, #0@ waitnand1: addr3, r3, #0x1cmpr3, #0xabltnand1 nand2:ldrr2, [r1, #oNFSTAT]@ wait readytstr2, #0x4beqnand2ldrr2, [r1, #oNFCONT]orrr2, r2, #0x2@ Flash Memory Chip Disablestrr2, [r1, #oNFCONT]@ get read to call C functions (for nand_read())ldrsp, DW_STACK_START@ setup stack pointermovfp, #0@ no previous frame, so fp=0 @ copy U-Boot to RAMldrr0, =TEXT_BASEmovr1, #0x0movr2, #LENGTH_UBOOTblnand_read_lltstr0, #0x0beqok_nand_read bad_nand_read:loop2:bloop2@ infinite loopok_nand_read:@ verifymovr0, #0ldrr1, =TEXT_BASEmovr2, #0x400@ 4 bytes * 1024 = 4K-bytesgo_next:ldrr3, [r0], #4ldrr4, [r1], #4teqr3, r4bnenotmatchsubsr2, r2, #4beqstack_setupbnego_next notmatch:loop3:bloop3@ infinite loop#endif/***************** NAND_BOOT *************************************************/

可能用到的寄存器:



完成了代码的拷贝,接下来是设置栈:

stack_setup:ldrr0, _TEXT_BASE /* upper 128 KiB: relocated uboot   */subr0, r0, #CONFIG_SYS_MALLOC_LEN/* malloc area              */subr0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */#ifdef CONFIG_USE_IRQsubr0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsubsp, 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_SIZE128/* size in bytes reserved for initial data */

所以CONFIG_SYS_MALLOC_LEN256kCONFIG_ENV_SIZE128KBnandflash一个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:ldrr0, _bss_start /* find start of bss segment        */ldrr1, _bss_end /* stop here                        */movr2, #0x00000000 /* clear                            */ clbss_l:strr2, [r0] /* clear loop...                    */addr0, r0, #4cmp r0, r1bleclbss_l

这段代码也很简单,不用多说。

 

ldrpc, _start_armboot

_start_armboot标号所指向的内存中读取数据给pc

又有:

_start_armboot:.word start_armboot

所以这里是把start_armboot的地址传给pcpc跳到start_armboot函数处执行,接下来就是stage2的部分了。


 









0 0
原创粉丝点击