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命令來啓動內核,
2、-a參數後是內核的運行地址,-e參數後是入口地址。
3、 在這裏,有個非常關鍵的問題,對於uboot啓動內核,我們經常用bootm命令來啓動內核,
bootm->do_bootm->do_bootm_linux->set_xxx_tag,然後the_kernel
1)如果我們沒用mkimage對內核進行處理的話,那直接把內核下載到0x30008000再運行就行,
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
!!!!! 要緊記這兩種情況
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,啓動內核
run_command分別解析nand命令和bootm命令,nand命令負責把linux內核讀到內存中,bootm負責去啓動內核鏡像,調用do_bootm----->do_bootm_linux,啓動內核