003@ uboot第一阶段分析(上)

本文详细分析了嵌入式系统启动过程中的第一阶段,包括硬件初始化、内存空间分配、代码复制、栈设置和BSS段清理。U-Boot在此阶段关闭看门狗、中断,初始化CPU和时钟,并根据启动介质(如NorFlash或NandFlash)进行代码重定位。然后设置栈,清除BSS段,最后跳转到C语言入口点start_armboot执行第二阶段。此外,还介绍了mkimage工具用于制作启动映像文件的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1:第一阶段:

-> 硬件的初始化,关看门狗,关中断,设置cpu 频率,设置时钟,ram 初始化。

-> 为加载第二阶段code,开辟内存空间

-> 复制第二阶段code       到 RAM 空间

-> 设置好 栈

-> 跳转到 第二阶段的 c 代码入口点。  (在跳转之前要清 BSS 段,初始值为0的全局变量和 静态变量放到此处)

2:第二阶段:

-> 初始化本阶段的硬件

-> 检查系统内存映射,(确定板上使用了多少内存,地址空间是什么)

-> 将 内核镜像 和 根文件系统从 flash 上读取到 RAM 空间

-> 为内核设置启动参数

-> 调用内核

我们先来分析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 (rgooch@atnf.csiro.au)
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,启动内核








 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值