UBOOT-2012-10在OK6410平臺的移植(二)uboot 2012.10啓動流程

 開始之前先說說開發環境:

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)而言,我認爲這種處理程序結構比較清晰。





閱讀(7) | 評論(0) | 轉發(0) |
評論熱議
發佈了28 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章