本文主要是介绍基于TQ2440开发板的U-boot-1.1.6的start.S代码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
start.S汇编源文件是U-boot执行的起始代码文件,也是不容易理解的实现部分。执行流程如下:
.globl _start //定义_start是全局标签,其他文件也可以使用。.globl是GNU汇编语法。 _start: b reset //跳转到reset标签出执行,由于reset操作是在MMU工作之前/之后都有可能使用,所以这里用b来跳转。 /*下面定义ARM异常向量表对应的跳转代码*/ 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 /*其中.word的语法是用来指定该变量可以被C语言直接引用*/ .balignl 16,0xdeadbeef /* 这个指令用来填写一个长字,即内容长度为长字,即4个字节的长度,填写内容为0xdeadbeef */ |
当一个异常出现以后,ARM会自动执行以下几个步骤:
(1)把下一条指令的地址放到连接寄存器LR(通常是R14),这样就能够在处理异常返回时从正确的位置继续执行。
(2)将相应CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中。从异常退出的时候,就可以由SPSR来恢复CPSR。
(3)根据异常类型,强制设置CPSR的运行模式位。
(4)强制PC(程序计数器)从相关异常向量地址取出下一条指令执行,从而跳转到相应的异常处理程序中。
reset: /* * set the cpu to SVC32 mode */ mrs r0,cpsr /*传送CPSR的内容到通用寄存器指令*/ bic r0,r0,#0x1f /*位清除指令,即=r0&(~0x1f)*/ orr r0,r0,#0xd3 /*逻辑或指令,即=r0|0xd3*/ msr cpsr,r0 /*传送通用寄存器到CPSR指令*/
/* turn off the watchdog */ #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 INTMOD 0X4A000004 # 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 /*将0x0值传入r1寄存器*/ str /*r1, [r0] 将r1种的内容写入到r0中*/
/* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */ |
cpu_init_crit 主要完成内存管理相关的寄存器设置,CP15协处理器,配置内存区控制寄存器。另外这段代码中调用了lowlevel_init 函数,进行寄存器的具体设置,与采用的内存芯片有关。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit /*bl是带跳转返回指令*/ #endif 接下来看一下cpu_init_crit标签的实现,如下: cpu_init_crit: /* * flush v4 I/D caches */ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* ARM 处理器寄存器到协处理器寄存器的数据传送指令,清除I、D cache和分支运算缓存(BTB)*/ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB(Translation Lookaside Buffers) */
/* * 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
/* * 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 /*跳转到lowlevel_init,处理完返回*/ mov lr, ip mov pc, lr |
lowlevel_init实现是在board/tq2440/ lowlevel_init.S中,主要完成初始化内存控制器,即SDRAM的初始化。
.globl lowlevel_init lowlevel_init: /* memory control configuration */ /* make r0 relative the current location so that it */ /* reads SMRDATA out of FLASH rather than memory ! */ ldr r0, =SMRDATA ldr r1, _TEXT_BASE sub r0, r0, r1 ldr r1, =BWSCON /* Bus Width Status Controller */ add r2, r0, #13*4 0: ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 bne 0b
/* everything is fine now */ mov pc, lr |
接下来是设置堆栈,设置后的逻辑位置如下图所示:
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 */ sub sp, r0, #12 /* leave 3 words for abort-stack */ |
接下来调用:bl clock_init 用来完成初始化时钟的目的。
下面的代码是将NandFlash数据搬运到SDRAM的核心实现代码,其最主要由C语言函数CopyCode2Ram函数来完成复制目的,该函数在board/tq2440/boot_init.c中实现。
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 clear_bss
ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot */ bl CopyCode2Ram /* r0: source, r1: dest, r2: size */ |
接下来就是清除BSS段,并进入C语言阶段的高级初始化过程实现。
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
ldr pc, _start_armboot _start_armboot: .word start_armboot /*start_armboot是C代码函数,在lib_arm/board.c中实现*/ |
这篇关于基于TQ2440开发板的U-boot-1.1.6的start.S代码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!