最近要接触到u-boot,看看网上的文章,看看代码,随便写点记录,。
貌似ARM架构的代码,都是从start.S这个汇编代码开始的,我也从这个文件入手,我不是以注释的方式来描述,而是以面向流程的方式来描述,最后把带注释的代码一贴完事儿。
>第一部分:
#include <config.h>
#include <version.h>
注意,代码中有很多个config.h,不少于十个,不过这里包含的应该是 ./include/config.h 这一个,简单的说这个start.S需要用到很多配置头文件的宏,定义这个宏的头文件只被 ./include/config.h 包含,具体原因以后分析。
>第二部分:
.globl _start
_start: b 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
_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
_pad: .word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
好像和单片机差不多,程序开头部分都是中断向量表,这里先不说其它中断,直接说第一个reset,power on其实和reset是一样的,都是从无到有的一个过程,直接看reset的代码:
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
设置CPU进入SVC32模式,超级模式。
#if (CONFIG_OMAP34XX)
/* Copy vectors to mask ROM indirect addr */
adr r0, _start @ r0 <- current position of code
add r0, r0, #4 @ skip reset vector
mov r2, #64 @ r2 <- size to copy
add r2, r0, r2 @ r2 <- source end address
mov r1, #SRAM_OFFSET0 @ build vect addr
mov r3, #SRAM_OFFSET1
add r1, r1, r3
mov r3, #SRAM_OFFSET2
add r1, r1, r3
next:
ldmia r0!, {r3 - r10} @ copy from source address [r0]
stmia r1!, {r3 - r10} @ copy to target address [r1]
cmp r0, r2 @ until source end address [r2]
bne next @ loop until equal */
#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT)
/* No need to copy/exec the clock code - DPLL adjust already done
* in NAND/oneNAND Boot.
*/
bl cpy_clk_code @ put dpll adjust code behind vectors
#endif /* NAND Boot */
#endif
这段代码并不是每种cpu都是必须的,为啥呢? 看看内容和注释,其实就是把中断向量表的内容copy到SRAM中去了,另外如果没有定义NAND或者ONENAND的boot,就调用 cpy_clk_code 这个代码,好像是将clock的代码(定时中断?)copy到中断向量表后面了。
接下来:
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
cpu的初始化,代码如下:
/*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************/
cpu_init_crit:
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
/*
* Jump to board specific initialization...
* The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle
* wake up conditions.
*/
mov ip, lr @ persevere link reg across call
bl lowlevel_init @ go setup pll,mux,memory
mov lr, ip @ restore link
mov pc, lr @ back to my caller
具体没仔细看了,还调用了 lowlevel_init.S 中的 lowlevel_init 代码。
>第三部分:
#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: @ copy 32 bytes at a time
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 */
从名字看一下,就知道,是把u-boot的代码搬到RAM中而已。
>第四部分:设置堆栈
/* Set up the stack */
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_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
>第五部分:清除BSS
/* Clear BSS (if any). Is below tx (watch load addr - need space) */
clear_bss:
ldr r0, _bss_start @ find start of bss segment
ldr r1, _bss_end @ stop here
mov r2, #0x00000000 @ 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
>最后:跳转到C代码执行。
ldr pc, _start_armboot @ jump to C code
_start_armboot: .word start_armboot
(慢慢再看再补充吧,我的目的不是S,而是整体架构,补充驱动,呵呵)