分类: LINUX
2012-11-17 21:03:40
开始之前先说说开发环境:
VMware 8.0 ubuntu 11.10 arm-linux-gcc 4.5.1 u-boot-2012.10
和其他版本一样,UBOOT 2012.10的启动还是从Start.S开始的:
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start
_start: b reset
#ifndef CONFIG_NAND_SPL
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 */
#else
. = _start + 64
#endif
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
.globl _TEXT_BASE
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE:
.word CONFIG_SYS_PHY_UBOOT_BASE
/*
* These are defined in the board-specific linker script.
* Subtracting _start from them lets the linker put their
* relative position in the executable instead of leaving
* them null.
*/
.globl _bss_start_ofs
_bss_start_ofs:
.word __bss_start - _start
.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end__ - _start
.globl _end_ofs
_end_ofs:
.word _end - _start
/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
.word 0x0badc0de
//(1)以上设置_start,各种中断函数、TEXT_BASE以及BSS段存放的顺序,start指向reset处:
/*
* the actual reset code
*/
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x3f
orr r0, r0, #0xd3
msr cpsr, r0
//(2)设置cpu处于SVC管理模式,这种模式拥有对CPU最多的管理权限
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
cpu_init_crit:
/*
* When booting from NAND - it has definitely been a reset, so, no need
* to flush caches and disable the MMU
*/
#ifndef CONFIG_NAND_SPL
/*
* 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 */
/*
* 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
/* Prepare to disable the MMU */
adr r2, mmu_disable_phys
sub r2, r2, #(CONFIG_SYS_PHY_UBOOT_BASE - CONFIG_SYS_TEXT_BASE)
b mmu_disable
.align 5
/* Run in a single cache-line */
mmu_disable:
mcr p15, 0, r0, c1, c0, 0
nop
nop
mov pc, r2
mmu_disable_phys:
#ifdef CONFIG_DISABLE_TCM
/*
* Disable the TCMs
*/
mrc p15, 0, r0, c0, c0, 2 /* Return TCM details */
cmp r0, #0
beq skip_tcmdisable
mov r1, #0
mov r2, #1
tst r0, r2
mcrne p15, 0, r1, c9, c1, 1 /* Disable Instruction TCM if present*/
tst r0, r2, LSL #16
mcrne p15, 0, r1, c9, c1, 0 /* Disable Data TCM if present*/
skip_tcmdisable:
#endif
#endif
#ifdef CONFIG_PERIPORT_REMAP
/* Peri port setup */
ldr r0, =CONFIG_PERIPORT_BASE
orr r0, r0, #CONFIG_PERIPORT_SIZE
mcr p15,0,r0,c15,c2,4
#endif
//(3)初始化cache,mmu以及外设
/*
* Go setup Memory and board specific bits prior to relocation.
*/
bl lowlevel_init /* go setup pll,mux,memory */
//(4)进入Lowlevel_init初始化,主要做的事情是:关闭看门狗,屏蔽中断,初始化系统时钟,
//uart、nand及内存控制的初始化,这些初始化都是对硬件进行的。
#ifndef CONFIG_NAND_SPL
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
/*------------------------------------------------------------------------------*/
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _bss_start_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
#endif
#ifdef CONFIG_ENABLE_MMU
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 /* load domain access register */
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CONFIG_SYS_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1 /* Set CR_M to enable MMU */
/* Prepare to enable the MMU */
adr r1, skip_hw_init
and r1, r1, #0x3fc
ldr r2, _TEXT_BASE
ldr r3, =0xfff00000
and r2, r2, r3
orr r2, r2, r1
b mmu_enable
.align 5
/* Run in a single cache-line */
mmu_enable:
mcr p15, 0, r0, c1, c0, 0
nop
nop
mov pc, r2
skip_hw_init:
#endif
clear_bss:
#ifndef CONFIG_SPL_BUILD
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000 /* clear */
clbss_l:cmp r0, r1 /* clear loop... */
bhs clbss_e /* if reached end of bss, exit */
str r2, [r0]
add r0, r0, #4
b clbss_l
clbss_e:
//#ifndef CONFIG_NAND_SPL
bl coloured_LED_init
bl red_led_on
mov r0, r5 /* gd_t */
mov r1, r4 /* dest_addr */
mov r2, sp
bl relocat_position
#endif
#endif
//(5)如果没定义CONFIG_NAND_SPL的话(也就是我们通常说的SDRAM启动)则进入
board_init_f这个函数,这是第一个C语言函数,里面进行:
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
print_cpuinfo, /* display cpu info (and speed) */
checkboard, /* display board info */
dram_init, /* configure available RAM banks */
各种初始化之后为uboot在SDRAM内存的空间做了配置。
配置如下图:
有些人可能发现,uboot的地址不是57e00000,是的,在uboot 2012.10版本中,内存分配给uboot的地址不一定就是57e00000。哪怎么程序能够运行呢?要明白,这是正在运行的这个uboot程序给内存做了分配,此时它还是处于57e00000开始的一段内存空间里,它给自己分配一个空间,这个空间的地址有可能不是程序最初运行的位置,但可以通过上面的重定位方法把自己复制到新的空间来。
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
#ifdef CONFIG_NAND_SPL
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,_nand_boot
mov pc, r0
_nand_boot: .word nand_boot
(6)如果是NAND启动的话,那么就设置SP后跳到nand_boot函数里面进行复制代码到SDRAM,然后跳到
uboot在SDRAM的起始地址开始运行。否则执行下面的else语句,这是继上面(5)重定位后运行的程序
#else
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr
_board_init_r_ofs:
.word board_init_r - _start
#endif
(7)重新定位后,跳到board_init_r函数主要执行:
board_init();
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
flash_init();
nand_init(); /* go init the NAND */
/* initialize environment */
env_relocate();
stdio_init(); /* get the devices list going. */
jumptable_init();
console_init_r(); /* fully init console as a device */
/* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts();
eth_initialize(gd->bd);
for (;;) {
main_loop();
}
程序到此就一直在这个main_loop()里面运行了。
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start
#ifdef CONFIG_ENABLE_MMU
_mmu_table_base:
.word mmu_table
#endif
#ifndef CONFIG_NAND_SPL
/*
* we assume that cache operation is done before. (eg. cleanup_before_linux())
* actually, we don't need to do anything about cache if not use d-cache in
* U-Boot. So, in this function we clean only MMU. by scsuh
*
* void theLastJump(void *kernel, int arch_num, uint boot_params);
*/
#ifdef CONFIG_ENABLE_MMU
.globl theLastJump
theLastJump:
mov r9, r0
ldr r3, =0xfff00000
ldr r4, _TEXT_PHY_BASE
adr r5, phy_last_jump
bic r5, r5, r3
orr r5, r5, r4
mov pc, r5
phy_last_jump:
/*
* disable MMU stuff
*/
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
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
mov r0, #0
mov pc, r9
#endif
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
*/
.macro bad_save_user_regs
/* carve out a frame on current user stack */
sub sp, sp, #S_FRAME_SIZE
/* Save user registers (now in svc mode) r0-r12 */
stmia sp, {r0 - r12}
ldr r2, IRQ_STACK_START_IN
/* get values for "aborted" pc and cpsr (into parm regs) */
ldmia r2, {r2 - r3}
/* grab pointer to old stack */
add r0, sp, #S_FRAME_SIZE
add r5, sp, #S_SP
mov r1, lr
/* save sp_SVC, lr_SVC, pc, cpsr */
stmia r5, {r0 - r3}
/* save current stack into r0 (param register) */
mov r0, sp
.endm
.macro get_bad_stack
ldr r13, IRQ_STACK_START_IN @ setup our mode stack
/* save caller lr in position 0 of saved stack */
str lr, [r13]
/* get the spsr */
mrs lr, spsr
/* save spsr in position 1 of saved stack */
str lr, [r13, #4]
/* prepare SVC-Mode */
mov r13, #MODE_SVC
@ msr spsr_c, r13
/* switch modes, make sure moves will execute */
msr spsr, r13
/* capture return pc */
mov lr, pc
/* jump to next instruction & switch modes. */
movs pc, lr
.endm
.macro get_bad_stack_swi
/* space on current stack for scratch reg. */
sub r13, r13, #4
/* save R0's value. */
str r0, [r13]
ldr r13, IRQ_STACK_START_IN @ setup our mode stack
/* save caller lr in position 0 of saved stack */
str lr, [r0]
/* get the spsr */
mrs r0, spsr
/* save spsr in position 1 of saved stack */
str lr, [r0, #4]
/* restore r0 */
ldr r0, [r13]
/* pop stack entry */
add r13, r13, #4
.endm
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack_swi
bad_save_user_regs
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort
.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used
.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif /* CONFIG_NAND_SPL */
总结:uboot2012.10总体的执行结构还是和老版本(例如uboot 1.1.6)一致的。主要不同的地方是在
lowlevel_init之后如果是NAND启动则先拷贝程序到SDRAM然后系统跳到SDRAM开始处重新运行;即使是在SDRAM中运行,程序也有可能需要重新定位。因为为内存分配空间时有可能分配给uboot的空间并不是我们指定的那个空间。相对于旧版本(uboot 1.1.6)而言,我认为这种处理程序结构比较清晰。