10@ uboot第一階段分析(上)

 uboot第一階段分析(上)

-> 硬件的初始化,關看門狗,關中斷,設置cpu 頻率,設置時鐘,ram 初始化
-> 爲加載第二階段code, 開闢內存空間
-> 複製第二階段code        到 RAM 空間
-> 設置好 棧
-> 跳轉到 第二階段的 c 代碼入口點。  (在跳轉之前要清 BSS 段,初始值爲0的全局變量和 靜態變量放到此處)



我們先來分析uboot啓動代碼的第一階段,以arm920t爲例。

#include <config.h>
#include <version.h>
#include <status_led.h>

/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/


.globl _start                                                          //定義一個全局變量或者函數,該處指的是函數。
_start:     b       start_code         復位向量 0x0    //定義的各種異常向量表,爲每種異常指定了一個地址
     ldr     pc, _undefined_instruction                    未定義指令異常向量 0x4               //當異常到來時,就跑到該異常向量地址出去執行
     ldr     pc, _software_interrupt      軟中斷向量 0x8
     ldr     pc, _prefetch_abort            欲取指令異常向量 0xc
     ldr     pc, _data_abort                  數據操作異常向量 0x10
     ldr     pc, _not_used                    未使用 0x14
     ldr     pc, _irq                     外中斷異常向量 0x18
     ldr     pc, _fiq                     快中斷異常向量 0x1c

_undefined_instruction:     .word undefined_instruction       賦值操作 以下同,即_undefined_instruction = 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      //地址對齊
    
//當處理器碰到異常時,PC會被強制設置爲對應的異常向量,從而跳轉到相應的處理程序,然後再返回到主程序
繼續執行。 相應的處理函數在最下面。arm有7種運行模式,當進入某一種異常模式的時候,比如是中斷模式。

1 將r0—r12    寄存器的值保存在該異常模式的棧裏,(事先之前就要將該模式下的棧設置好,放在  r13)
2 異常模式下的r14保存用戶模式下即將執行指令的地址,爲當前PC值加4或者加8
3 cpsr保存在該異常模式下的spsr裏 
4 cpsr的工作模式被設爲這個異常工作模式 比如由 10000 --》 10011
5 PC(程序計數器)被強制成相關異常向量處理函數地址,從而跳轉到相應的異常處理程序中,比如 pc= 0x18
當異常處理完畢後,ARM會執行以下幾步操作從異常返回:

(1)將連接寄存器LR的值減去相應的偏移量後送到PC中
(2) 將SPSR複製回CPSR中
(3) 若在進入異常處理時設置了中斷禁止位,要在此清除


/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/

//以下是保存變量的數據區

_TEXT_BASE:                           //賦值,將uboot在內存的起始基地址TEXT_BASE賦值給_TEXT_BASE
     .word     TEXT_BASE

.globl _armboot_start                //定義一個全局函數變量_armboot_start,將_start的值賦給_armboot_start ,
_armboot_start:                         無論是nor flash啓動 nand flash啓動還是內存啓動_start的值爲TEXT_BASE
     .word _start

/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start          //_bss_start=_bss_start(鏈接腳本的地址)
_bss_start:
     .word __bss_start

.globl _bss_end            // _bss_end = _end(鏈接腳本的地址)
_bss_end:
     .word _end

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START        //IRQ_STACK_START = 0x0badc0de
IRQ_STACK_START:
     .word     0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START       //FIQ_STACK_START = 0x0badc0de
FIQ_STACK_START:
     .word 0x0badc0de
#endif

//保存變量的數據區完畢
/*
* the actual start code
*/

start_code:       一上電覆位,便跑到這裏
     /*
     * set the cpu to SVC32 mode
     */
     mrs     r0,cpsr         //設置cpsr_c的那個字節,設置成1101 0011 即屏蔽外中斷 屏蔽快中斷 arm狀態 svc管理模式 即超級保護模式,可以訪問被保護的資源
     bic     r0,r0,#0x1f
     orr     r0,r0,#0xd3
     msr     cpsr,r0

     bl coloured_LED_init   //在原始的uboot源碼中是沒有此處的
     bl red_LED_on

#if     defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
     /*
     * relocate exception table
     */
     ldr     r0, =_start        //暫不清楚 應該是平臺不同的限制
     ldr     r1, =0x0
     mov     r2, #16
copyex:
     subs     r2, r2, #1
     ldr     r3, [r0], #4
     str     r3, [r1], #4
     bne     copyex
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
//關閉看門狗 關閉所有中斷 初始化始終 都是通過設置相關的控制寄存器
     /* turn off the watchdog */

# if defined(CONFIG_S3C2400)
#  define pWTCON       0x15300000
#  define INTMSK          0x14400008     /* Interupt-Controller base addresses */
#  define CLKDIVN       0x14800014     /* clock divisor register */
#else
#  define pWTCON          0x53000000
#  define INTMSK             0x4A000008     /* Interupt-Controller base addresses */
#  define INTSUBMSK     0x4A00001C
#  define CLKDIVN          0x4C000014     /* clock divisor register */
# endif

     ldr        r0, =pWTCON   //向看門寄存器寫0 即關閉看門狗
     mov     r1, #0x0
     str        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

     /* FCLK:HCLK:PCLK = 1:2:4 */
     /* default FCLK is 120 MHz ! */  //以下是初始化時鐘,即分頻
     ldr     r0, =CLKDIVN
     mov     r1, #3
     str     r1, [r0]
#endif     /* CONFIG_S3C2400 || CONFIG_S3C2410 */

     /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
    
    
    
#ifndef CONFIG_SKIP_LOWLEVEL_INIT

//關閉mmu 屏蔽指令緩存和數據緩存 設置cpu運行速率和時鐘初始化 ram的初始化,下面有分析!!!
     bl     cpu_init_crit    
#endif

#ifndef     CONFIG_AT91RM9200

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

//在重定位之前,一定要先初始化ram
//以下是重定位,即將uboot源碼從flash上拷貝到sdram上運行,此處考慮的是nor型flash,沒有考慮nand型flash

relocate:                    /* relocate U-Boot to RAM         */
     adr     r0, _start                 /* r0 <- current position of code   */         //adr指令是讀入代碼當前運行位置,絕對位置 也即此時此刻的位置,非常非常重要
     ldr     r1, _TEXT_BASE          /* test if we run from flash or RAM */   若此時是在nor flash進行,則-start的值爲0x0
     cmp     r0, r1                           // 如果ro=r1 即說明uboot是通過仿真器直接燒入到內存中,直接從內存啓動 否則則說明是從flash運行的        /* don't reloc during debug         */
     beq     stack_setup

     ldr     r2, _armboot_start            //_armboot_start存放的是_start的值,此是是_TEXT_BASE
     ldr     r3, _bss_start                   //此處也是絕對地址 他們都是鏈接腳本    u-boot.lds中定義的
     sub     r2, r3, r2                          /* r2 <- size of armboot            */ uboot的大小
     add     r2, r0, r2                          /* r2 <- source end address    */

copy_loop:
     ldmia     r0!, {r3-r10}          /* copy from source address [r0]    */          從源地址[r0]讀取32個字節到寄存器,並更新r0
     stmia     r1!, {r3-r10}          /* copy to   target address [r1]    */              拷貝寄存器r3-r10的32個字節值保存到[r1]指明的地址,並更新r1的值

     cmp     r0, r2                    /* until source end addreee [r2]    */
     ble     copy_loop
// 重定位完畢    
#endif                                    /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
     /* Set up the stack                                  */
     我們將uboot拷貝到內存之後,就要設置棧
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                        */
#ifdef CONFIG_USE_IRQ
     sub     r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
     sub     sp, r0, #12          /* leave 3 words for abort-stack    */
    
     // TEXT_BASE- CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - CONFIG_STACKSIZE_IRQ - CONFIG_STACKSIZE_FIQ -12
   即內存基地址分別減去 堆空間     gd_t gd空間   外中斷設置的棧空間    快中斷設置的棧空間

    
//清bss段
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
    
//到此進行跳轉到內存裏的uboot第二階段 終於要執行C語言入口函數了start_armboot,重要!!!
     ldr     pc, _start_armboot     /*lib_arm/board.c 文件中          */


_start_armboot:     .word start_armboot









/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
cpu_init_crit
1、關閉MMU和CPU 內部指令/數據 (I/D)cache。
2、設置CPU 的速度和時鐘頻率。
3 、RAM 初始化。



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

     /*
     * 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
#if     defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)

#else
     bl     lowlevel_init      //ram的初始化 就是配置13個寄存器的值 在       lowlevel_init.S
#endif
     mov     lr, ip
     mov     pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*
*************************************************************************
*
* 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 ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/

     .macro     bad_save_user_regs
     sub     sp, sp, #S_FRAME_SIZE
     stmia     sp, {r0 - r12}               @ Calling r0-r12
     ldr     r2, _armboot_start
     sub     r2, r2, #(CONFIG_STACKSIZE)
     sub     r2, r2, #(CFG_MALLOC_LEN)
     sub     r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
     ldmia     r2, {r2 - r3}               @ get pc, cpsr
     add     r0, sp, #S_FRAME_SIZE          @ restore sp_SVC

     add     r5, sp, #S_SP
     mov     r1, lr
     stmia     r5, {r0 - r3}               @ save sp_SVC, lr_SVC, pc, cpsr
     mov     r0, sp
     .endm

     .macro     irq_save_user_regs
     sub     sp, sp, #S_FRAME_SIZE
     stmia     sp, {r0 - r12}               @ Calling r0-r12
     add     r7, sp, #S_PC
     stmdb   r7, {sp, lr}^                   @ Calling SP, LR
     str     lr, [r7, #0]                    @ Save calling PC
     mrs     r6, spsr
     str     r6, [r7, #4]                    @ Save CPSR
     str     r0, [r7, #8]                    @ Save OLD_R0
     mov     r0, sp
     .endm

     .macro     irq_restore_user_regs
     ldmia     sp, {r0 - lr}^               @ Calling r0 - lr
     mov     r0, r0
     ldr     lr, [sp, #S_PC]               @ Get PC
     add     sp, sp, #S_FRAME_SIZE
     subs     pc, lr, #4               @ return & move spsr_svc into cpsr
     .endm

     .macro get_bad_stack
     ldr     r13, _armboot_start          @ setup our mode stack
     sub     r13, r13, #(CONFIG_STACKSIZE)
     sub     r13, r13, #(CFG_MALLOC_LEN)
     sub     r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

     str     lr, [r13]               @ save caller lr / spsr
     mrs     lr, spsr
     str     lr, [r13, #4]

     mov     r13, #MODE_SVC               @ prepare SVC-Mode
     @ msr     spsr_c, r13
     msr     spsr, r13
     mov     lr, pc
     movs     pc, lr
     .endm

     .macro get_irq_stack               @ setup IRQ stack
     ldr     sp, IRQ_STACK_START
     .endm

     .macro get_fiq_stack               @ setup FIQ stack
     ldr     sp, FIQ_STACK_START
     .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
     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

#ifdef CONFIG_USE_IRQ

     .align     5
irq:
     get_irq_stack
     irq_save_user_regs
     bl     do_irq
     irq_restore_user_regs

     .align     5
fiq:
     get_fiq_stack
     /* someone ought to write a more effiction fiq_save_user_regs */
     irq_save_user_regs
     bl     do_fiq
     irq_restore_user_regs

#else

     .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

第一階段分析小結:
  設置異常向量表
  進入svc管理模式 arm狀態
  關看門狗 關中斷 時鐘初始化
  cpu初始化(關mmu   關數據和指令緩存   cpu速率)和內存初始化
  //關閉mmu 屏蔽指令緩存和數據緩存 設置cpu運行速率和時鐘初始化 ram的初始化

 
  重定位
  設置棧
  清bss斷
  跳入到start_armboot函數 ,lib_arm/board.c     中


在這裏嚴重關注: 我們有兩種啓動方式,nand啓動和nor啓動,我們上面的重定位是nor型







relocate:                    /* relocate U-Boot to RAM         */
     adr     r0, _start          /* r0 <- current position of code   */  //adr指令是讀入代碼的當前位置,絕對位置 也即此時此刻的位置,非常非常重要
     ldr     r1, _TEXT_BASE          /* test if we run from flash or RAM */
     cmp     r0, r1        
//如果ro=r1 即說明uboot是通過仿真器直接燒入到內存中,直接從內存啓動
     否則則說明是從flash運行的 /* don't reloc during debug         */

     beq     stack_setup

     ldr     r2, _armboot_start  //_armboot_start存放的是_start的值,是絕對地址
     ldr     r3, _bss_start   //此處也是絕對地址 他們都是鏈接腳本u-boot.lds中定義的
     sub     r2, r3, r2          /* r2 <- size of armboot            */ uboot的大小
     add     r2, r0, r2          /* r2 <- source end address         */

copy_loop:
     ldmia     r0!, {r3-r10}     /* copy from source address [r0]    */  從源地址[r0]讀取32個字節到寄存器,並更新r0
     stmia     r1!, {r3-r10}     /* copy to   target address [r1]    */  拷貝寄存器r3-r10的32個字節值保存到[r1]指明的地址,並更新r1的值

     cmp     r0, r2          /* until source end addreee [r2]    */
     ble     copy_loop

對於nand啓動,是首先我們nand 4k內容被copy至內部4k ram裏,執行,然後執行到重定位時,
     從nand上拷貝uboot鏡像到SDRAM的33f80000處

//#define S3C2440_NAND_BASE 0x4E000000
     //取得Nand Flash設置寄存器的地址
     mov r1, #S3C2440_NAND_BASE
     //將R2設爲0xFFF0
     ldr r2, =0xfff0 // initial value tacls=3,rph0=7,rph1=7
     //#define oNFCONF 0x00
     //讀取Nand Flash設置寄存器中的值到R3中
     ldr r3, [r1, #oNFCONF]
     //將R3或上R2後保存到R3中
     orr r3, r3, r2
     //將R3中的值保存到Nand Flash設置寄存器中
     //TWRPH0 - 111 - Duration = HCLK * (TWRPH0 + 1)
     //TACLS - 11 - Duration = HCLK * TACLS
     str r3, [r1, #oNFCONF]
     //#define oNFCONT 0x04
     //讀取Nand Flash控制寄存器中的值到R3中
     ldr r3, [r1, #oNFCONT]
     //將R3的[0]位置1
     orr r3, r3, #1 // enable nand controller
     //將R3中的值保存到Nand Flash控制寄存器中
     //Mode - 1:Nand Flash Controller Enable
     str r3, [r1, #oNFCONT]
     //讀取虛擬起始地址到R0中
     ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
     //預留malloc所需要的空間
     sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
     //預留bdinfo所需要的空間
     sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
     //預留中斷和快速中斷向量表空間
     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
     //預留12字節給中斷棧
     sub sp, r0, #12 /* leave 3 words for abort-stack */
     // copy u-boot to RAM
     //讀取虛擬起始地址到R0中,作爲目標地址
     ldr r0, _TEXT_BASE
     //將R1設爲0,作爲源地址
     mov r1, #0x0
     //將UBOOT大小的值保存在R2中,作爲數據大小
     mov r2, #CFG_UBOOT_SIZE
     //跳轉到nand_read_ll處執行
     //並將下一條指令的地址保存在LR中
     bl nand_read_ll
    nand_read_ll的原型爲
    int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
    之前設置的R0 R1 R2爲它的3個參數
















 
 
  



mkimage使用詳解
###############################################################################################################################
mkimage使用詳解(轉載) uboot源代碼的tools/目錄下有mkimage工具,這個工具可以用來製作不壓縮或者壓縮的多種可啓動映象文件。
mkimage在製作映象文件的時候,是在原來的可執行映象文件的前面加上一個0x40字節的頭,記錄參數所指定的信息,這樣uboot才能識別這個映象是針對哪個CPU體系結構的,哪個OS的,哪種類型,加載內存中的哪個位置, 入口點在內存的那個位置以及映象名是什麼


root@Glym:/tftpboot# ./mkimage
Usage: ./mkimage -l image
-l ==> list image header information
./mkimage -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)
參數說明:
-A 指定CPU的體系結構:
取值 表示的體系結構
alpha Alpha
arm A RM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64 Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64 Bit
m68k MC68000
-O 指定操作系統類型,可以取以下值:
openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos
-T 指定映象類型,可以取以下值:
standalone、kernel、ramdisk、multi、firmware、script、filesystem
-C 指定映象壓縮方式,可以取以下值:
none 不壓縮
gzip 用gzip的壓縮方式
bzip2 用bzip2的壓縮方式
-a 指定映象在內存中的加載地址,映象下載到內存中時,要按照用mkimage製作映象時,這個參數所指定的地址值來下載
-e 指定映象運行的入口點地址,這個地址就是-a參數指定的值加上0x40(因爲前面有個mkimage添加的0x40個字節的頭)
-n 指定映象名
-d 指定製作映象的源文件



U-BOOT下使用bootm引導內核方法


一、在開始之前先說明一下bootm相關的東西。
1、 首先說明一下,S3C2410架構下的bootm只對sdram中的內核鏡像文件進行操作
      (好像AT91架構提供了一段從flash複製內核鏡像的代碼, 不過針對s3c2410架構就沒有這段代碼,雖然可以在u-boot下添加這段代碼,不過好像這個用處不大),
       所以請確保你的內核鏡像下載到sdram 中,或者在bootcmd下把flash中的內核鏡像複製到sdram中。
2、-a參數後是內核的運行地址,-e參數後是入口地址。

3、    在這裏,有個非常關鍵的問題,對於uboot啓動內核,我們經常用bootm命令來啓動內核,
          bootm->do_bootm->do_bootm_linux->set_xxx_tag,然後the_kernel
1)如果我們沒用mkimage對內核進行處理的話,那直接把內核下載到0x30008000再運行就行,
     內核會自解壓運行(不過內核運行需要一個tag來傳遞參數,而這個tag建議是由bootloader提供的,在u-boot下默認是由bootm命令建立的)。

   !!!!! 要緊記這兩種情況
2)如果使用mkimage生成內核鏡像文件的話,會在內核的前頭加上了64byte的信息,供建立tag之用。bootm命令會首先判斷bootm xxxx 這個指定的地址xxxx是否與-a指定的加載地址相同。
(1) 如果不同的話會從這個地址開始提取出這個64byte的頭部,對其進行分析,然後把去掉頭部的內核複製到-a指定的load地址中去運行之
(2) 如果相同的話那就讓其原封不同的放在那,但-e指定的入口地址會推後64byte,以跳過這64byte的頭部。

如果啓動地址與內核鏡像的加載地址相同,那麼鏡像就不用移動,但是鏡像的入口地址必須後移64個字節
如果啓動地址與內核鏡像的加載地址不同,那麼鏡像需要移動,此時,要將去掉64字節的頭部的鏡像移動到加載地址處



二、好,接着介紹使用mkimage生成鏡像文件並下載運行的方法。

方法一、
1、首先,用u-boot/tools/mkimage這個工具爲你的內核加上u-boot引導所需要的文件頭,具體做法如下:
[root@localhost tftpboot]#mkimage -n 'linux-2.6.14' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage zImage.img // -d zImage 表示原始映像文件  zImage.img                                                                                                                                                       表示生成的最終鏡像文件
Image Name:   linux-2.6.14
Created:      Fri Jan 12 17:14:50 2007
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    1262504 Bytes = 1232.91 kB = 1.20 MB
Load Address: 0x30008000
Entry Point:  0x30008000


這裏解釋一下參數的意義:
        -A ==> set architecture to 'arch'
        -O ==> set operating system to 'os'
        -T ==> set image type to 'type'
        -C ==> set compression type 'comp'
        -a ==> set load address to 'addr' (hex)
        -e ==> set entry point to 'ep' (hex)
        -n ==> set image name to 'name'
        -d ==> use image data from 'datafile'
        -x ==> set XIP (execute in place)



2 、下載內核
U-Boot 1.1.3 (Jan 12 2007 - 16:16:36)                  經計算uboot鏡像的大小爲127K左右
U-Boot code: 33F80000 -> 33F9BAC0  BSS: -> 33F9FBAC   在這裏調用init_senqunce函數序列中的display_banner,分別打印的是 printf ("\n\n%s\n\n", version_string);
                                                                                                              debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
                                                                                                                     _armboot_start, _bss_start, _bss_end);
RAM Configuration:                  在這裏調用init_senqunce函數序列中disply_dram_config函數
Bank #0: 30000000 64 MB       打印是內存的起始物理地址和大小
Nor Flash: 512 kB                     nor flash的初始化
Nand Flash:  64 MB                  調用nand flash的初始化
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot:  0
sbc2410=>tftp 0x31000000 zImage.img        
TFTP from server 192.168.1.115; our IP address is 192.168.1.128
Filename 'zImage.img'.
Load address: 0x31000000
Loading: #################################################################
        #################################################################
        #################################################################
        ####################################################
done
Bytes transferred = 1263324 (1346dc hex)


3.運行
sbc2410=>bootm 0x31000000
## Booting image at 31000000 ...
  Image Name:   linun-2.6.14
  Image Type:   ARM Linux Kernel Image (uncompressed)
  Data Size:    1263260 Bytes =  1.2 MB
  Load Address: 30008000
  Entry Point:  30008000
  Verifying Checksum ... OK
OK
Starting kernel ...
Uncompressing Linux.............................................................Linux version 2.6.14 (root@luofuchong) (gcc version 3.4.1) #21 Fri Oct 20 17:206CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
Machine: SMDK2410
Memory policy: ECC disabled, Data cache writeback
CPU S3C2410A (id 0x32410002)
S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 MHz
S3C2410 Clocks, (c) 2004 Simtec Electronics
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
USB Control, (c) 2006 sbc2410
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Built 1 zonelists
Kernel command line: console="ttySAC0" root="/dev/nfs" nfsroot="192".168.1.115:/frien"irq: clearing subpending status 00000002
PID hash table entries: 512 (order: 9, 8192 bytes)
timer tcon="00500000", tcnt a509, tcfg 00000200,00000000, usec 00001e4c
Console: colour dummy device 80x30
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 64MB = 64MB total
Memory: 62208KB available (1924K code, 529K data, 108K init)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
softlockup thread 0 started up.
NET: Registered protocol family 16
S3C2410: Initialising architecture
SCSI subsystem initialized
usbcore: registered new driver usbfs
usbcore: registered new driver hub
S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics
DMA channel 0 at c4800000, irq 33
DMA channel 1 at c4800040, irq 34
DMA channel 2 at c4800080, irq 35
DMA channel 3 at c48000c0, irq 36
NetWinder Floating Point Emulator V0.97 (double precision)
devfs: 2004-01-31 Richard Gooch ([email protected])
devfs: devfs_debug: 0x0
devfs: boot_options: 0x1
yaffs Oct 18 2006 12:39:51 Installing.
Console: switching to colour frame buffer device 30x40
fb0: s3c2410fb frame buffer device
fb1: Virtual frame buffer device, using 1024K of video memory
led driver initialized
s3c2410 buttons successfully loaded
s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2410
s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2410
s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2410
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
usbcore: registered new driver ub
Cirrus Logic CS8900A driver for Linux (Modified for SMDK2410)
eth0: CS8900A rev E at 0xe0000300 irq="53", no eeprom , addr: 08: 0:3E:26:0A:5B
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2410-nand: mapped registers at c4980000
s3c2410-nand: timing: Tacls 10ns, Twrph0 30ns, Twrph1 10ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bi)Scanning device for bad blocks
Bad eraseblock 1884 at 0x01d70000
Creating 4 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00020000 : "vivi"
0x00020000-0x00030000 : "param"
0x00030000-0x00200000 : "kernel"
0x00200000-0x04000000 : "root"
usbmon: debugfs is not available
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
Initializing USB Mass Storage driver...
usbcore: registered new driver usb-storage
USB Mass Storage support registered.
usbcore: registered new driver usbmouse
drivers/usb/input/usbmouse.c: v1.6:USB HID Boot Protocol mouse driver
mice: PS/2 mouse device common for all mice
s3c2410 TouchScreen successfully loaded
UDA1341 audio driver initialized
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 2, 16384 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
TCP bic registered
NET: Registered protocol family 1
IP-Config: Complete:
     device=eth0, addr="192".168.1.128, mask="255".255.255.0, gw="192".168.1.1,
    host="luofuchong", domain=, nis-domain=(none),
    bootserver="192".168.1.1, rootserver="192".168.1.115, rootpath=
Looking up port of RPC 100003/2 on 192.168.1.115
Looking up port of RPC 100005/1 on 192.168.1.115
VFS: Mounted root (nfs filesystem).
Mounted devfs on /dev
Freeing init memory: 108K
init started:  BusyBox v1.1.3 (2006.09.20-14:52+0000) multi-call binary
Starting pid 696, console /dev/tts/0: '/etc/init.d/rcS'
Please press Enter to activate this console.


方法二、
1、首先,用u-boot/tools/mkimage這個工具爲你的內核加上u-boot引導所需要的文件頭,具體做法如下:
[root@localhost tftpboot]#mkimage -n 'linux-2.6.14' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage zImage.img
Image Name:   linux-2.6.14
Created:      Fri Jan 12 17:14:50 2007
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    1262504 Bytes = 1232.91 kB = 1.20 MB
Load Address: 0x30008000
Entry Point:  0x30008040



2 、下載內核
U-Boot 1.1.3 (Jan 12 2007 - 16:16:36)
U-Boot code: 33F80000 -> 33F9BAC0  BSS: -> 33F9FBAC
RAM Configuration:
Bank #0: 30000000 64 MB
Nor Flash: 512 kB
Nand Flash:  64 MB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot:  0
sbc2410=>tftp 0x30008000 zImage.img        
TFTP from server 192.168.1.115; our IP address is 192.168.1.128
Filename 'zImage.img'.
Load address: 0x30008000
Loading: #################################################################
               #################################################################
              #################################################################
              ####################################################
done
Bytes transferred = 1263324 (1346dc hex)

3.運行
sbc2410=>bootm 0x30008000
## Booting image at 30008000 ...
   Image Name:   linux-2.6.14
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1261056 Bytes =  1.2 MB
   Load Address: 30008000
   Entry Point:  30008040
   Verifying Checksum ... OK
   XIP Kernel Image ... OK


============================================================對於uboot兩階段的小結,很重要!!!==================================
第一階段:
在腳本uboot.lds中 ENTRY(_start) _start的地址一般是TEXT_BASE
設置異常向量表
  進入svc管理模式 arm狀態
  關看門狗 關中斷 時鐘初始化
  cpu初始化(關mmu 關數據和指令緩存 cpu速率)和內存初始化 在函數cpu_init_crit中完成
  重定位
  設置棧
  清bss斷
  跳入到start_armboot函數

第二階段 就進入到lib_arm/board.c    中的start_kernel函數

分配gd   指針指向的空間和gd->bd   指針指向的空間
執行init_sequence        函數序列,其實主要目的是初始化並填充gd和gd->bd結構體
分配堆空間     mem_malloc_init ,這樣纔可以初始化環境變量,因爲環境變量是要從nand拷貝到內存中的堆空間裏
nand初始化      nand_init,因爲現在普及採用nand,若是用nor的話,在之前已經初始化了 flash_init    函數
環境變量初始化    env_reloacate 有四個很重要的環境變量參數:bootdelay(啓動延時),bootcmd(啓動命令),menucmd(菜單),bootargs(啓動參數,也即最原始的命令行參數)
串口設置的5個函數,這樣就能看到串口打印數據
混雜設備 misc_init_r函數


進入循環執行 main_loop函數,處理啓動命令或者用戶輸入的命令 該函數是在common/main.c     中
    第一種情況是 在bootdelay內不按空格鍵:s=getenv ("bootcmd");run_command (s, 0);    直接啓動內核了
    第二種輕狂就是 在bootdelay內按下空格鍵進入menu菜單裏: s = getenv("menucmd");run_command (s, 0);
     然後進入命令循環獲取用戶從串口裏打印的字符 len = readline         (CFG_PROMPT);run_command (lastcommand, flag); 
之後在run_command裏if ((cmdtp = find_cmd(argv[0])) == NULL)--->if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0)即根據     
命令的名字 找到該命令表結構體,調用它的cmd參數 最終還是回到do_xxx  run_command就是來解析命令的

run_command分別解析nand命令和bootm命令,nand命令負責把linux內核讀到內存中,bootm負責去啓動內核鏡像,調用do_bootm----->do_bootm_linux,啓動內核








 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章