uboot之start.s分析

更新时间:2024-02-02 22:29:02 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

开始start.s分析,根据S3C2410来跟踪代码,参考了S3C2410的datasheet和网上各个帖子

一般来说,大家都是从start.s来分析UBOOT,但是事实是流程是从makefile中来的,也就是说是在敲入make smdk2410_config和make all后才进入start.s中,makefile在这里不做分析,韦东山的那本书有详细的说明,这里要提到的是makefile传进来的,我们在UBOOT中所设计到的LDFLAGS,这个标志确定了连接方式,其中的-T

board/smd2410/U-Boot.lds -Ttext 0x33F8000(展开后的)指定了程序的布局和地址,U-Boot.lds如下(参考martree的专栏):

/*******************************************************/

OUTPUT_FORMAT(\;指定输出可执行文件是elf格式,32位ARM指令,小端 OUTPUT_ARCH(arm)

;指定输出可执行文件的平台为ARM ENTRY(_start)

;指定输出可执行文件的起始代码段为_start. SECTIONS {

. = 0x00000000 ; 指明目标代码的起始地址从0x0位置开始,\代表的是当前位置 . = ALIGN(4) ; 代码以4字节对齐 .text : ;指定代码段 {

cpu/arm920t/start.o (.text) ; 代码的第一个代码部分,指明start.s是入口程序代码,被放到代码段的开头 *(.text) ;其它代码部分 }

. = ALIGN(4)

.rodata : { *(.rodata) } ;指定只读数据段,RO段 . = ALIGN(4);

.data : { *(.data) } ;指定读/写数据段,RW段 . = 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);

__bss_start = .; 把__bss_start赋值为当前位置,即bss段的开始位置 .bss : { *(.bss) }; 指定bss段

_end = .; 把_end赋值为当前位置,即bss段的结束位置 }

/****************************************/

从这里可以看出start.s是程序的入口点,下面是start.s代码

//global声明一个符号可被其它文件引用,相当于声明了一个全局变量,.globl与.global相同。

//该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。 .globl _start

_start: b reset /*跳转到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

// .word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。.long与.int作用与之//相同。

_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 /*

* Startup Code (reset vector) *

* do important init only if we don't start from RAM! * - relocate armboot to ram * - setup stack

* - jump to second stage */

// TEXT_BASE在开发板相关的目录中的config.mk文件中定义, 它定义了 // 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址 _TEXT_BASE: .word TEXT_BASE

// 声明 _armboot_start 并用 _start 来进行初始化,在board/u-boot.lds中定义。 .globl _armboot_start _armboot_start: .word _start /*

* These are defined in the board-specific linker script. */

// 声明_bss_start并用__bss_start来初始化,其中__bss_start定义在与板相关的u-boot.lds中。

// _bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在 // 的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时 // 地址的影响. _bss_end也是同样的道理. .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

// MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd

// 使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样可以最好地完成对CRSP或者SPSR的修改

// MSR {} CPSR_|SPSR_,Rm 或者是 MSR {} CPSR_f|SPSR_f,#<32-bit immediate>

// MRS与MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分 // bic r0,r1,r2 ;r0:=r1 and not r2 // orr ro,r1,r2 ;r0:=r1 or r2

// 这几条指令执行完毕后,进入SVC模式,该模式主要用来处理软件中断(SWI) reset:

mrs r0,cpsr /* set the cpu to SVC32 mode */ bic r0,r0,#0x1f /* (superviser mode, M=10011) */ orr r0,r0,#0xb3 /*disable irq and frq SVC mode*/ msr cpsr,r0

/* 关闭看门狗,S3C2410手则 */ #if defined(CONFIG_S3C2400) # define pWTCON 0x15300000

# define INTMSK 0x14400008 /* Interupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #elif defined(CONFIG_S3C2410)

# define pWTCON 0x53000000

# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C

# define CLKDIVN 0x4C000014 /* clock divisor register */ #endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /*

* 屏蔽所有中断 */

mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0]

# if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif

/* 设置FCLK:HCLK:PCLK = 1:2:4 */ /*FCLK默认为120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0]

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

/*该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在LR中,以使得执行完后能够正常返回。后面会分析*/ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif

//调试阶段的代码是直接在RAM中运行的,而最后需要把这些代码固化到Flash中,因此U-Boot需要自己从Flash转移到

//RAM中运行,这也是重定向的目的所在。

//通过adr指令得到当前代码的地址信息:如果U-boot是从RAM开始运行,则从adr,r0,_start得到的地址信息为

//r0=_start=_TEXT_BASE=TEXT_BASE=0xa3000000;如果U-boot从Flash开始运行,即从处理器对应的地址运行,

//则r0=0x0000,这时将会执行copy_loop标识的那段代码了。 // _TEXT_BASE 定义在board/pxa255_idp/config.mk中 #ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */

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

ldr r2, _armboot_start ldr r3, _bss_start

sub 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

#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 */ // 这里如果需要使用IRQ, 还有给IRQ保留堆栈空间

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif

//这里是直接减去12,但是在后面board.c中的cpu_init中代码是减8再减4的(如下),大家看到后面再反过来看看,会觉得很有意//思 /*

int cpu_init (void) { /*

* setup up stacks if necessary */

#ifdef CONFIG_USE_IRQ

IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;

FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ; #endif return 0; } */

sub sp, r0, #12 /* leave 3 words for abort-stack */

//该部分将未初始化数据段_bss_start----_bss_end中的数据清零。 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, #4 cmp r0, r1 ble clbss_l

#if 0

/* try doing this stuff after the relocation */ ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /*

* mask all IRQs by setting all bits in the INTMR - default */

mov r1, #0xffffffff ldr r0, =INTMR str r1, [r0]

/* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0]

/* END stuff after relocation */ #endif

// 通过该语句跳转到C代码执行,stage1的使命也算完成。 ldr pc, _start_armboot

_start_armboot: .word start_armboot #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit: /*

* flush v4 I/D caches */

mov r0, #0

mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /*

* 关闭MMU和缓存,这里用到了协处理器P15,参看手则,哈哈,这里有的很多看了

*/

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

/*进入lowlevel_init,这里主要是初始化存储控制器,S3C2410的是Bank0-bank6,比如位宽等,这个要根据自己的板子来进行相应的配置,比如网卡放在第几个bank,位宽多少,SDRAM放在哪里,多大等,移植UBOOT的时候就有的学了*/ mov ip, lr bl lowlevel_init mov lr, ip mov pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

//程序后面的都是中断的处理,定义了一系列的宏,然后就是中断的处理函数,篇幅太长不列出

本文来源:https://www.bwwdw.com/article/7wvw.html

Top