U-BOOT全线移植

【摘要】本节介绍了bootloader的基本概念。首先分析了为什么要针对特定的CPU和开发板移植bootloader的必要性。然后介绍了两种如何在裸板中烧写bootloader的方法以及如何确定烧写地址。其次介绍了产品发布的启动加载模式和开发使用的下载模式(更新内核文件系统及bootloader自身)。最后介绍了bootloader的两个通用启动阶段的流程及代码特性和运行位置。

【关键词】bootloader,烧写,复位地址,固化loader,启动加载,stage1,位置无关

一 bootloader介绍

1.1 Bootloader移植的必要性
Bootloader是与系统硬件环境高度相关的初始化软件,它担负着初始化硬件和引导操作系统的双重责任。一些ARM平台可以共用同一种Bootloader,但是总的说来,每一个特定系统的Bootloader都会有所不同。Bootloader广泛用于有操作系统的手持终端设备、智能家电及机顶盒等嵌入式设备上,它负责完成硬件初始化、操作系统引导和系统配制等。Bootloader移植是在特定硬件平台上操作系统移植至关重要的一步。

 

1.2 BootLoader所支持的CPU和嵌入式系统板
每种不同的CPU体系结构都有不同的BootLoader。有些BootLoader也支持多种体系结构的CPU,比如U-BOOT就同时支持ARM、MIPS、POWERPC等体系结构。除了依赖于CPU的体系结构外,BootLoader实际上也依赖于具体的嵌入式板级设备的配置。也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种CPU而构建的,要想让运行在一块板子上的BootLoader程序也能运行在另一块板子上,通常也都需要修改BootLoader的源程序。

 

1.3. Boot Loader的烧录和存储
系统加电或复位后,所有的CPU通常都从某个由CPU制造商预先安排的地址上取指令。比如,at91rm9200的CPU在复位时通常都从地址0x00000000取它的第一条指令。而MPC8260高端启动则时从0xfff00000开始取指。这个地址依据特定的CPU而定。通常片外启动时,基于CPU构建的嵌入式系统通常都有某种类型的固态存储设备(EEPROM或FLASH等,at91rm9200是0x10000000)被映射到这个预先安排的地址上。因此在系统加电后,CPU将首先执行Boot Loader程序。

 

那么bootloader最初是怎么烧写到flash中的呢?对于一个裸板怎么让它跑起来呢?有两种方式:

²      通过片内固化的loader加载bootloader:通常某些CPU内部ROM中固化了一段程序可以用于最初的程序下载,如AT91RM9200。这时下载的程序是在内部RAM中运行的,大小有一定限制,然后由这段程序继续交互下载真正要烧写到flash中的程序,将其保存在外部RAM中,最终烧写到flash中。

²      通过JTAG或者仿真器下载:通常这些烧录工具可以直接操作flash,对其进行编程烧录。需要专门的工具。这种情况多用于那些没有固化loader的CPU,如三星系列。

 


上图是一个同时装有Boot Loader、内核的启动参数、内核映像和根文件系统映像的固态存储设备的典型空间分配结构图。上述顺序是可变的,但bootloader首地址一定要在CPU复位取指的地址上。

 

1.4 Boot Loader的操作模式(Operation Mode)
主机和目标机之间一般通过串口建立连接,BootLoader软件在执行时通常会通过串口来进行数据传输,如输出打印信息到串口,从串口读取用户控制字符。

 

大多数Boot Loader都包含两种不同的操作模式:启动加载模式和下载模式,这种区别仅对于开发人员才有意义。从最终用户的角度看,BootLoader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。

²      启动加载(Boot loading)模式:这种模式也称为自主模式bootstrap。也即Boot Loader将存储在目标板Flash中的内核和文件系统的镜像装载到SDRAM中,整个过程无需用户的介入。这种模式是BootLoader的正常工作模式,因此在嵌入式产品发布的时候,BootLoader显然必须工作在这种模式下。

²      下载Downloading模式:在这种模式下,目标机上的BootLoader将通过串口连接或网络连接等通信手段从宿主机Host下载文件,比如下载内核映像和根文件系统映像等。从主机下载的文件通常首先被BootLoader保存到目标机的RAM中,然后再被BootLoader写到目标机上的FLASH类固态存储设备中。BootLoader的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新(bootloader自身也可以这样更新)也会使用Boot Loader的这种工作模式。工作于这种模式下的BootLoader通常都会向它的终端用户提供一些简单的命令行接口。

 

像U-BOOT等这样功能强大的BootLoader通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。比如,U-BOOT在启动时处于正常的启动加载模式,但是它会延时几秒(在配置文件中可以设定)等待终端用户按下任意键而将其切换到下载模式(相当于bios下按del键可进入系统配置界面一样,设置从光盘启动可进行重装),如果在给定时间内没有用户按键,则U-BOOT继续启动,进行正常的启动加载。

 

1.5 Bootloader与主机之间进行文件传输所用的通信设备及协议
最常见的情况就是,目标机上的BootLoader通过串口与主机之间进行文件传输,传输协议通常是kermit / xmodem / ymodem协议中的一种。但是,串口传输的速度是有限的,因此如果该Bootloader对目标板的网卡支持良好,还可以通过以太网连接并借助TFTP (Trivial File Transfer Protocol)协议来下载文件是个更好的选择。此时,主机方所用的软件也要考虑,比如,在通过以太网连接和TFTP协议来下载文件时,主机方必须有一个软件用来提供TFTP服务,如Windows平台上的tftpd.exe等或Linux下面的tftp服务器。

 

1.6 Bootloader的通用执行流程

从操作系统的角度看,Bootloader的总目标就是正确地调用内核来执行。另外,由于Bootloader的实现依赖于 CPU的体系结构,因此大多数Bootloader都分为stagel和stage2两大部分。依赖于CPU体系结构的代码,比如设备初始化代码等,通常都放在stagel中,而且通常都用汇编语言来实现,以达到短小精悍和高效的目的。而stage2则通常用C语言来实现,这样可以实现更复杂的功能,而且代码会具有更好的可读性和可移植性。

 

Bootloader的stagel为位置无关代码,通常在FLASH中运行。所有的指令为相对寻址,可以在任何位置运行。通常包括以下步骤(以执行的先后顺序):

Ø       硬件设备初始化(配置SDRAM存储控制器及IO),中断初始化;

Ø       为加载Bootloader的stage2准备RAM空间(这个地址由链接脚本指定,为运行域地址,通常为RAM的高端地址),测试内存空间是否有效;

Ø       拷贝Bootloader的stage2到RAM空间中;

Ø       设置好堆栈;

Ø       跳转到stage2的C入口点。

 

Bootloader的stage2通常被拷贝到RAM中运行,这样可以提高运行速度。通常包括以下步骤(以执行的先后顺序):

Ø       初始化本阶段要使用到的硬件设备;

Ø       检测系统内存映射(memory map);

Ø       没有用户干预时将kernel映像和根文件系统映像从flash读到RAM空间中;

Ø       为内核设置启动参数;

Ø       调用内核。

 U-boot基础

现在为Linux开放源代码Bootloader有很多,blob redbootU-BOOT等,其中U-BOOT是目前用来开发嵌入式系统引导代码使用最为广泛的Bootloader。它支持POWERPCARMMIPS X86等处理器,支持嵌入式操作系统有LinuxVxworksNetBSD等。

 

2.1 U-boot源代码目录结构

|-- board  平台依赖,存放电路板相关的目录文件

|-- common  通用多功能函数的实现

|-- cpu  平台依赖,存放cpu相关的目录文件

|-- disk  通用。硬盘接口程序

|-- doc  文档

|-- drivers  通用的设备驱动程序,如以太网接口驱动

|-- dtt

|-- examples  应用例子

|-- fs  通用存放文件系统的程序

|-- include  头文件和开发板配置文件,所有开发板配置文件放在其configs

|-- lib_arm  平台依赖,存放arm架构通用文件

|-- lib_generic  通用的库函数

|-- lib_i386  平台依赖,存放x86架构通用文件

|-- lib_m68k  平台依赖

|-- lib_microblaze  平台依赖

|-- lib_mips  平台依赖

|-- lib_nios   平台依赖

|-- lib_ppc平台依赖,存放ppc架构通用文件

|-- net  存放网络的程序

|-- post  存放上电自检程序

|-- rtc  rtc的驱动程序

`-- tools  工具

 

详细实例:

²      board开发板相关的源码,不同的板子对应一个子目录,内部放着主板相关代码。 Board/at91rm9200dk/at91rm9200.c, config.mk, Makefile, flash.c ,u-boot.lds都和具体开发板的硬件和地址分配有关。

 

²      common:与体系结构无关的代码文件,实现了u-boot所有命令,其中内置了一个shell脚本解释器(hush.c, a prototype Bourne shell grammar parser), busybox中也使用了它。

 

²      cpu:与cpu相关代码文件,其中的所有子目录都是以u-boot支持的cpu命名

cpu/at91rm9200/at45.c, at91rm9200_ether.c, cpu.c, interrupts.c serial.c, start.S, config.mk, Makefile等。其中:

cpu.c负责初始化CPU、设置指令Cache和数据Cache等;

interrupt.c负责设置系统的各种中断和异常,比如快速中断、开关中断、时钟中断、软件中断、预取中止和未定义指令等;

start.S负责u-boot启动时执行的第一个文件,它主要是设置系统堆栈和工作方式,为跳转到C程序入口点做准备;

at91rm9200_ether.cserial.c很重要,这是系统能够下载资源的前提。

 

²      disk:设备分区处理代码。

²      docu-boot相关文档。

 

²      driversu-boot所支持的设备驱动代码网卡、支持CFIFlash、串口和USB总线等。

²      fs: u-boot所支持文件系统访问存取代码, 如jffs2

 

²      includeu-boot head文件,主要是与各种硬件平台相关的头文件,如include/asm-arm/arch-at91rm9200/AT91RM9200.h(硬件寄存器名称及地址的定义), hardware.h 内存及flash地址以及IO物理地址和虚拟地址的定义),include/asm-arm/proc-armv(与具体的CPU无关,无需移植)。

 

²      net:与网络有关的代码,BOOTP协议、TFTP协议、RARP协议代码实现无需移植。

 

²      lib_arm:与arm体系相关的代码。

²      tools:编译后会生成mkimage工具,用来对生成的raw bin文件加入u-boot特定的image_header.

 

2.2 U-Boot支持的主要功能

主要功能如下:

²      系统引导,支持NFS挂载RAMDISK(压缩或非压缩)形式的根文件系统;

²      支持NFS挂载、从FLASH中引导压缩或非压缩系统内核;

²      基本辅助功能,强大的操作系统接口功能;可灵活设置、传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,尤对Linux支持最为强劲;

²      支持目标板环境参数多种存储方式,如FLASHNVRAMEEPROM

²      CRC32校验,可校验FLASH中内核、RAMDISK镜像文件是否完好;

²      设备驱动,串口、SDRAMFLASH、以太网、LCDNVRAMEEPROM、键盘、USBPCMCIAPCIRTC等驱动支持;

²      上电自检功能 SDRAMFLASH大小自动检测;SDRAM故障检测;CPU型号;

²      特殊功能,XIP内核引导。

 

2.3 U-boot命令介绍及环境变量

²      ?得到所有命令列表

²      Helphelp usb, 列出USB功能的使用说明

²      ping:注意只能开发板PING别的机器(AT91RM9200不支持,需要进行配置)

²      setenv: 设置环境变量

Ø       setenv serverip 192.168.0.1

Ø       setenv ipaddr 192.168.0.56

Ø       setenv bootcmd ‘tftp 32000000 vmlinux; kgo 32000000’

²      saveenv:保存环境变量。在设置好环境变量以后, 保存变量值

²      tftptftp 32000000 vmlinux, serverIP=环境变量中设置的serverip)中/tftpboot/下的vmlinux通过TFTP读入到物理内存32000000

²      bootp- 通过网络用 BootP/TFTP 协议来启动映象

²      tftpboot- 通过网络用 TFTP 协议、设置服务器和客户机的 IP 地址进行映象文件传送

²      kgo: 起动没有压缩的linux内核,kgo 32000000AT91RM9200不支持)

²      bootm:起动UBOOT  TOOLS制作的压缩LINUX内核, bootm 3200000

²      protect: FLASH进行写保护或取消写保护,protect on 1:0-3(就是对第一块FLASH0-3扇区进行保护)protect off 1:0-3取消写保护

²      erase删除FLASH的扇区, erase 1:0-2(就是对每一块FLASH0-2扇区进行删除)

²      cp: 在内存中复制内容, cp 32000000 0 40000(把内存中0x32000000开始的0x40000字节复制到0x0)

²      mw: 对RAM中的内容写操作, mw 32000000 ff 10000(把内存0x32000000开始的0x10000字节设为0xFF)

²      md: 修改RAM中的内容, md 32000000(内存的起始地址)

²      flinfo: 列出flash的信息

²      loadb: 准备用KERMIT协议接收来自kermit或超级终端传送的文件。

²      nfs nfs 32000000 192.168.0.12:aa.txt,把192.168.0.12(LINUX NFS文件系统)中的NFS文件系统中的aa.txt 读入内存0x32000000处。

 

最常用的几个命令如下:

²      go- 在地址 'addr' 处开始程序执行

²      run- 运行一个环境变量所定义的命令

²      bootm- 内存中进行运行经过mkimage加工的程序映象

²      loadb- 通过串口线(kermit mode) 来装载二进制文件

²      printenv- 打印环境变量

²      setenv- 设置环境变量

²      saveenv保存环境变量到内存

²      tftp-通过网络下载文件

²      protecteraseflash读写

 

下面是 U-BOOT 中的简单环境变量

²      baudrate波特率

²      bootdelay         boot 延迟

²      bootcmd   Boot 命令

²      bootargs   Boot 参数,传递给内核

²      bootfile 默认下载启动的内核映象

²      ipaddr       客户机 IP 地址

²      serverip    服务器地址

²      loadaddr   装载地址

²      ethaddr     网卡 MAC 地址

 

2.4 U-Boot的启动流程分析

和大多数的Bootloader一样,U-BOOT的启动分为两个阶段两个部分,依赖于CPU体系结构的代码主要放在stage1,且用汇编来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且具有更好的可读性和可移植性。

 

下面分别分析一下这两个阶段的启动流程:

第一阶段:基本的硬件初始化,为第二阶段程序运行建立环境(cpu/ at91rm9200/start.s文件的代码部分):

××××××××××××××××××××××××××××

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start) // 程序的入口在/cpu/××××/start.s中定义

SECTIONS

{

        . = 0x00000000; // 程序链接的地址

 

        . = ALIGN(4);

        .text      :

        {

          cpu/at91rm9200/start.o  (.text)

          *(.text)

        }

 

        . = ALIGN(4);

        .rodata : { *(.rodata) }

 

        . = ALIGN(4);

        .data : { *(.data) }

 

        . = ALIGN(4);

        .got : { *(.got) }

 

  __u_boot_cmd_start = .;

  .u_boot_cmd : { *(.u_boot_cmd) }

  __u_boot_cmd_end = .;

 

        armboot_end_data = .; //代码段结束地址

 

        . = ALIGN(4);

        .bss : { *(.bss) }

 

        armboot_end = .;  //整个U-boot印象的结束地址

}

××××××××××××××××××××××××××××

 

在此需要定义程序入口,由于一个可执行的Image必须要有一个入口点,并且只能有一个全局入口,通常这个入口就在ROM (flash)0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本u-boot.lds来完成,该阶段需要依次完成的工作一般包括:

²      CPU自身的初始化,它包括:CPU运行模式的设置(管理模式)、设置异常的入口地址和异常处理函数、运行时钟频率的设置等工作。

²      初始化GPIO和内存控制器。

²      为拷贝Stage2准备RAM空间。

²      进行自拷贝,将U-BOOTStage2拷贝到RAM中。

²      设置好堆栈。

²      跳转到Stage2的入口,从而转到RAM中执行,该工作是调用指令ldr pc, start armboot来完成的。

××××××××××××××××××××××××××

1.1.2开始,u-boot有初始化SDRAM并拷贝自己到SDRAM运行的代码,而之前的版本就没有这个功能(详细查看下代码??的确如此,因此对于以前的版本TEXT_BASE没有起作用?实际测试下??)board/ at91rm9200dkconfig.mk文件(TEXT_BASE = 0x21f0000032M RAM的设置,为第二阶段程序在RAM中的运行地址)用于设置程序编译连接的起始地址,在程序中要特别注意与地址相关指令的使用

Board/at91rm9200dk/config.mk

TEXT_BASE = 0x21f00000u-boot将被载入SDRAM高端部分

注意,对于不同的系统RAM大小可能不一样,要根据实际情况调整

/config.mk

ifdef BOARD

sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk     # include board specific rules

endif

CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS)              /

        -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE)     

LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)

export      TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS

 

对于U-Boot 1.1.2以前的版本,并没有自拷贝的部分,若flash中首地址存放的是非压缩的u-boot.bin的,则启动部分是一直运行在flash中的;但对于AT91RM9200来说,他通常有三个文件loader.bin, boot.bin, u-boot.binflash中首先运行的是boot.bin其将压缩的u-boot.bin.gz解压拷贝到TEXT_BASE处运行,此时已经在RAM中了,因此也无需实现自拷贝了。

 

对于U-Boot 1.1.2以后的版本,若像AT91RM9200boot.bin这样的过渡程序,则将u-boot.bin.gz解压到RAM中,此时运行地址和链接地址相同,无需拷贝;若没有,则u-boot.bin将在flash中执行初始化部分,然后将自身拷贝到RAM中执行。

// 比较运行地址和链接地址,如果当前已经在RAM中运行了,则无需拷贝到RAM

relocate:                               /* relocate U-Boot to RAM           */

        adr     r0, _start              /* r0 <- current position of code   */

        ldr     r1, _TEXT_BASE          /* test if we run from flash or RAM */

        cmp     r0, r1                  /* don't reloc during debug         */

        beq     stack_setup

 

        ldr     r2, _armboot_start

        ldr     r3, _bss_start

        sub     r2, r3, r2              /* r2 <- size of armboot            */

        add     r2, r0, r2              /* r2 <- source end address         */

 

copy_loop:

        ldmia   r0!, {r3-r10}           /* copy from source address [r0]    */

        stmia   r1!, {r3-r10}           /* copy to   target address [r1]    */

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

        ble     copy_loop

 

当程序在Flash中运行时,执行程序跳转时必须要使用相对跳转指令,而不能使用绝对地址的跳转(即直接对PC操作)。如果使用绝对地址,那么,程序的取指是相对于当前PC位置向前或者向后的32MB空间内,而不会跳入SDRAM

×××××××××××××××××××××××××××××

 

在上述操作运行完成后,就进入到/lib_arm/board.c 中的start_armboot()函数运行,并建立起了一个基本的环境,此时的物理内存空间的分布就变成了如图所示的情况。

转入boatloader stage2的系统内存布局

 

第二阶段:运行U-BOOT的主体部分

该阶段以程序跳转到lib_arm/board.c中的start_armboot函数为标志,该函数同时也是C语言的开始函数,是整个启动代码的主体函数,同时还是整个U-BOOT的主体函数,该函数主要完成以下工作:

²      调用一系列的初始化函数,初始化本阶段使用到的硬件,如:

×××××××××××××××××××

init_fnc_t *init_sequence[] = {

        cpu_init,           /* basic cpu dependent setup */

        board_init,                /* basic board dependent setup */

        interrupt_init,            /* set up exceptions */

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

        dram_init,         /* configure available RAM banks */

        display_dram_config,

#if defined(CONFIG_VCMA9)

        checkboard,

#endif

        NULL,

};

×××××××××××××××××××××

env_init:设置环境变量,初始化环境;

init_baudrate:设置串口的波特率;

serial_init:设置串口的工作方式;

dram_init:设置SDRAM的起始地址和大小;

     

²      检查存储器分配和使用情况:获取flashbank分区情况、是否擦除、是否上锁等信息为以后flash相关命令使用;初始化系统内存分配函数,供后面的代码使用malloc等函数,U-BOOT没有使用其他现成的库所有函数的实现均在文件中),如果系统有液晶等显示设备,一并在此分配显示内存。

²      打印内存,flash、环境变量设置等信息。

²      等待几秒时间,如果有键盘输入,则进入命令模式,接收用户输入的命令并解释执行(如启动操作系统,更新flash内容)。

²      如果在给定的时间内没有用户输入或者在执行命令操作时收到了用户要求启动内核的命令(boot)则将把操作系统内核和根文件系统映像文件从flash中拷贝到RAM中相应位置,并在设置内核启动参数后跳转到内核映像的首地址处执行。

×××××××××××××××××××××××××××××

U-BOOT调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START0x8000地址处。在跳转时,要满足下列条件:

a) CPU寄存器的设置:R00R1=机器类型 ID,本系统的机器类型ID193R2=启动参数标记列表在RAM中的起始基地址; 

b) CPU模式:必须禁止中断(IRQsFIQs)CPU必须工作在SVC模式;

c) CacheMMU的设置:MMU 必须关闭;指令Cache可以打开也可以关闭;数据Cache必须关闭。

系统采用下列代码来进入内核函数:

void (*theKernel)(int zero, int arch);

theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);

theKernel(0, bd->bi_arch_number);其中,hdrimage_header_t类型的结构体,hdr->ih_epentry point,指向内核的第一条指令地址,即Linux操作系统下的/kernel/arch/arm/boot/compressed/head.S汇编程序theKernel()函数调用应该不会返回,如果该调用返回,则说明出错。

×××××××××××××××××××××××××××××

 U-BOOTAT91RM9200上的移植

3.1 at91rm9200的启动方式

在这里我主要介绍通过片内引导和片外引导片内引导通常主要采用串口下载并引导u-boot,并将程序被烧写到 Flash上,然后就可以通过跳线的方式从片外引导执行已经烧写到片外Flash上的引导程序(bootloader)

 

3.1.1 片内引导

1)       片内引导的基本原理

系统上电,检测BMS,选择系统的启动方式,如果BMS为高电平,则系统从片内ROM启动。AT91RM9200的内部ROM上电后被映射到了0x00x100000,在这两个地址处都可以访问到ROM。由于9200ROM中固化了一个BOOTLOAER程序。所以PC0X0处开始执行这个BOOTLOAER(准确的说应该是一级BOOTLOADER)。这个BOOTLOADER依次完成以下步骤:

²      PLL SETUP。设置PLLB产生48M时钟频率提供给USB DEVICE。同时DEBUG USART也被初始化为48M的时钟频率。

²      相应模式下的堆栈设置

²      检测主时钟源(Main oscillator

²      中断控制器(AIC)的设置

²      变量的初始化

²      跳到主函数

 

完成以上步骤后,我们可以认为BOOT过程结束,接下来的就是LOADER的过程,或者也可以认为是装载二级BOOTLOERAT91RM9200按照DATAFLASHEEPROM、连接在外部总线上的8位并行FLASH的顺序依次来找合法的BOOT程序。所谓合法的指的是在这些存储设备的开始地址处连续的存放的32个字节,也就是8条指令必须是跳转指令或者装载PC的指令,其实这样规定就是把这8条指令当作是异常向量表来处理。必须注意的是第6条指令要包含将要装载的映像的大小。关于如何计算和写这条指令可以参考用户手册。一旦合法的映像找到之后,则BOOT程序会把找到的映像搬到内部SRAM中去,所以映像的大小是非常有限的,不能超过16K的大小。当BOOT程序完成了把合法的映像搬到SRAM的任务以后,接下来就进行存储器的REMAP,经过REMAP之后,SRAM从映设前的0X200000地址处被映设到了0X0地址并且程序从0X0处开始执行。而ROM这时只能在0X100000这个地址处看到了。至此9200就算完成了一种形式的启动过程。

 

如果BOOT程序在以上所列的几种存储设备中未找到合法的映像,则自动初始化DEBUG USART口和USB DEVICE口以准备从外部载入映像,大多数情况都是如此。DEBUG口的初始化包括设置参数115200 8 N 1以及运行XMODEM协议。对USB DEVICE进行初始化以及运行DFU协议。现在用户可以从外部(假定为PC平台)载入你的映像了。在PC平台下,以WIN2000为例,你可以用超级终端来完成这个功能,但是还是要注意你的映像的大小不能超过13K。一旦正确从外部装载了映像,接下来的过程就是和前面一样重映设然后执行映像了。

 

注意:通常所说的片内引导是指没有烧写合法的印象的情况下,但并不意外着烧些了合法印象的情况下不能采用片内引导的方式。通常第一次下载了启动印象后就会选择片外启动的方式了。并且烧些的印象通常第6条指令都不含将要装载的映像的大小,所以片内启动时一般不能运行这些印象。关于片内引导的详细过程可以参看at91rm9200的芯片说明书――引导程序一章。

 

Boot program Flow Diagram

Device Setup

|

Boot SPI DataFlash Boot --> Download from DataFlash --> run

|

TWI EEPROM Boot --> Download from EEPROM --> run

|

Parallel Boot --> Download from 8-bit Device -->

|

| Xmodem protocol

| |---DBGU Serial Download ---------------------> run

|____|

| DFU protocol

|-----USB download -----------------------> run

at91rm9200片内引导流程图

 

2)       at91rm9200片内引导u-boot的实现过程

at91rm9200内部本身有128k的片内rom,其固化了一个bootloaderuploader,其他存储设备上没有合法的映象时,片内引导将启动uploaderuploader开启xmodem协议,等待用户上传程序,上传的程序将载入片内SRAM,重映射,然后pc跳转到片内SRAM执行上传的用户程序,即loader.bin

注:片内SRAM只有16k,除去3-4k片内启动程序的占用的部分数据空间,因此下载的程序大小限制在12k内。

 

裸板只能用片内引导方式,载入一个12k以内的小程序loader.bin到内部SRAM运行,而这个小程序初始化SDRAM,再把u-boot.bin下载到SDRAM的高端运行(u-boot大于12k,不能直接下载的原因就在于此)pc跳到SDRAMu-boot位置运行u-bootu-boot启动后再用u-boot自己的命令把boot.bin u-boot.gz下载到SDRAM的低端,再用flash烧写命令烧到flash去,以后就可以片外flash启动了。

 

3.1.2 片外引导

如果BMS为低电平,则AT91RM9200会从片外的FLASH启动,这时片外的FLASH的起始地址就是0X0,要求已经在此地址烧些了启动映象了,接下来的过程和片内启动的过程是一样的,只不过这时就需要自己写启动代码了,至于怎么写,大致的内容和ROMBOOT差不多,不同的硬件设计可能有不一样的地方,但基本的都是一样的。由于片外FLASH可以设计的大,所以这里编写的BOOTLOADER可以一步到位,也就是说不用像片内启动可能需要BOOT好几级了

 

对于AT91RM9200,通常选择在flash的首地址处放的是boot.bin,由其将u-boot.bin.gz解压到高端RAM中,再运行真正的u-boot.bin,也就是实际的启动映象。

 

3.2 loader.bin, boot.bin, u-boot.bin代码执行流分析

以上三个文件是at91rm9200启动所需要的三个bin,他们的实现代码并不难。

3.2.1 loader.bin

执行流程,这个文件主要在片内启动从串口下载U-boot.bin代码时会用到,一般固化在CPU的内部ROM中,用户无需改动。

loader/entry.S init cpu

b main ---> crt0.S

--> copydata --> clearbss --> b boot

main.c --> boot -->

/*Get internel rom service address*/

/* Init of ROM services structure */

pAT91 = AT91C_ROM_BOOT_ADDRESS;

/* Xmodem Initialization */

--> pAT91->OpenSBuffer

--> pAT91->OpenSvcXmodem

/* System Timer initialization */

---> AT91F_AIC_ConfigureIt

/* Enable ST interrupt */

AT91F_AIC_EnableIt

AT91F_DBGU_Printk("XMODEM: Download U-BOOT ");

Jump.S

// Jump to Uboot BaseAddr exec

Jump((unsigned int)AT91C_UBOOT_BASE_ADDRESS) 跳到下载的U-boot.bin执行

 ××××××××××××××××××××××××××××××××××

lader.bin主要有3个功能,初始化SDRAM,启动xmodem接收u-boot并写到SDRAM中,pc跳转到SDRAM运行。

 

xmodem的实现

只需要接收部分,发送部分用win下的超级终端等工具就可。先找来协议文档,熟悉协议,看看现有的xmodem协议源码。协议本身并不复杂,只是它的握手部分实现有点技巧。接收端要不停的发送字符“C”到串口,发送端收到“C”后发送数据SOH和第一个数据包。接收端检测到SOH后停止发送“C”并开始处理数据。官方的loader启动了一个时间服务,每隔1s发送一个“C,在这个我使用了偷懒的算法。

    while(Getchar()!=AT91C_XMODEM_SOH)

    {

        if (0xFFFF==++n )

        {

            SendChar(AT91C_XMODEM_CRCCHR);

            n=0;

        }

    }

 

握手解决了,后面的处理都没什么问题。

 

SDRAM    

unsigned char *pSdram = (unsigned char *)AT91C_UBOOT_BASE_ADDRESS;

    for ( n = 0; n<128 ; n ++ )

    {

                *pSdram++=data[n];

    }

 

PC跳转

添加一个文件jump.S到工程

                AREA    reset, CODE, READONLY

                EXPORT  Jump

Jump

        mov pc, r0               

               END

;---------------------------------------------------------------------------------

 

main中使用下面的函数跳转

Jump((unsigned int)AT91C_UBOOT_BASE_ADDRESS);

 

loader的调试过程

xmodem部分可以传一个调试文件,传进去后全部send回串口,看返回的信息就可以判断是否正常工作。

SDRAM,依然是写入后再读出来看看是否一致,在这里卡了很久,发现每隔2个地址就不能使用,后来发现是SDRAM没有初始化,重写后正常。

Jump测试,得传入一个可以运行的程序到内存才能判断,用先前编译好的u-boot-1.0.0试一试,出现u-boot的提示符了,也就是说jump没问题。

×××××××××××××××××××××××××××××××××××

 

3.2.2 boot.bin执行流程

该文件会在从片内启动时由U-boot.bin下载到板子上,以后还会被烧写到片外Flash中,以便在片外启动时用它来引导并解压u-boot.gz,并跳转到解压后的u-boot来执行。

boot/entry.S

b main --> crt0.S --> copydata --> clearbss --> b boot

T91F_DBGU_Printk(" ");

AT91F_DBGU_Printk("************************************** ");

AT91F_DBGU_Printk("** Welcome to at91rm9200 ** ");

AT91F_DBGU_Printk("************************************** ");

boot/misc.s /* unzip uboot.bin.gz */

----> decompress_image(SRC,DST,LEN) --> gunzip

//jump to ubootBaseAddr exec 这里跳转到解压后的u-boot地址处直接开始执行u-boot

asm("mov pc,%0" : : "r" (DST));

修改main.c中下面2

#define SRC 0x10010000   (u-boot.gz将烧入flash的位置)

#define DST 0x21f00000  (u-boot.gz被解压后载入SDRAM的位置,和loader中保持一致)

 

3.2.1 uboot.bin执行流程

u-boot/cpu/at91rm9200/start.S

start --->reset

---> copyex ---> cpu_init_crit

---> /* set up the stack */ --> start_armboot

u-boot/lib_arm/board.c

init_fnc_t *init_sequence[] = {

cpu_init, /* basic cpu dependent setup */

board_init, /* basic board dependent setup */

interrupt_init, /* set up exceptions */

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

dram_init, /* configure available RAM banks */

display_dram_config,

checkboard,

NULL,

};

---> start_armboot ---> call init_sequence

---> flash_init --> display_flash_config

---> nand_init ---> AT91F_DataflashInit

---> dataflash_print_info --> env_relocate

---> drv_vfd_init --> devices_init --> jumptable_init

---> console_init_r --> misc_init_r --> enable_interrupts

---> cs8900_get_enetaddr --> board_post_init -->

 

u-boot/common/main.c

for (;;)

{ /* shell parser */

main_loop () --> u_boot_hush_start --> readline

--> abortboot

-->printf("Hit any key to stop autoboot: %2d ", bootdelay);

}

 

以上是at91rm9200启动并进入u-boot的执行流分析。后面u-boot还会将uImage解压到特定的位置并开始执行内核代码。

 

3.3 AT91RM9200开发板的存储器情况

第一级地址译码由存储控制器执行,即由具有附加功能的高级系统总线(ASB) 执行。译码将32位地址总线决定的4G的地址空间分为16 256M字节的区域。区域1 8 对应EBI,和外部片选NC0 NCS7相联系。区域0为内部存储器地址,第二级译码提供1M字节内部存储空间。区域15为外设地址,且提供对高级外设总线(APB) 的访问。其它区域未使用,使用它们进行访问时将向发出访问请求的主机发出异常中断。注意,地址的转换都是按照字节为单位的。

物理存储空间分布

 

3.3.1 内部存储器映射

内部ROMAT91RM9200集成了一个128-K字节的内部ROM。任何时候,ROM均被映射到地址0x10 0000。若复位时BMS 为高,即片内启动时,则在复位后到重新映射命令执行前,ROM有两个地址,可访问地址0x0。重映射之后SRAM将变为0地址,内部ROM地址就只为0x10 0000

ROM容量为128KB,即对应0x20000。所以范围为0x1000000x120000

 

内部RAMAT91RM9200集成了高速,16-K 字节的内部SRAM。复位后到重新映射命令执行前,只可访问SRAM 0x20 0000的地址空间。重新映射后, SRAM 在地址0x0有效。

RAM容量为16KB,即对应0x4000,所以范围为0x2000000x204000

 

USB 主机端口:AT91RM9200集成了一个USB主机端口开放主机控制器接口(OHCI)ASB可直接访问该接口寄存器,且同标准内部存储器一样映射到地址0x30 0000

 

内部存储器映射

 

3.3.2 外部存储器映射

 

嵌入式存储设备通常主要是外部RAM 和作为永久存储媒质的Flash

现在所用的AT91RM9200开发板所用的SDRAMK4S281632F,其容量为4banks×2Mbits×16,即128Mbits16MbytesSDRAM共有两片K4S281632F,数据总线位宽16,两片组成32位位宽,所以SDRAM容量为32MB

 

现在所用的Flash芯片为Intel28F128J3A,容量为16M,地址映射从0x100000000x10FF FFFF。现在将Flash分为128个扇区,每个扇区为128KB0x20000,每个扇区分为两个擦除块,为64KB0x10000

-------------------------------------------------------------------

Chip Select 0――Flash0x1000 00000x10FF FFFF

0x1000 00000扇区)

                boot.bin                    Flash

0x1001 00000扇区)

                u-boot.bin.gz     Flash

0x1002 0000(第1扇区)

                uImage                    Flash

.。。。。

0x1012 0000(第9扇区)

                ramdisk                    Flash

.

0x107E 0000(第127扇区)

                uboot环境变量    Flash

-------------------------------------------------------------------

Chip Select 1――SDRAM0x2000 00000x2200 0000

0x2000 0000

                                       SDRAM

.。。。。

0x2100 0000

                uImage            SDRAM

0x2110 0000

                ramdisk            SDRAM

------------------------------------------------------------------

 

0x0000 0000

                  ROM

0x1000 0000

           boot.bin       FLASH

0x1001 0000

          uboot.gz        FLASH

0x1002 0000

          ulmage         FLASH

0x1012 0000

          ramdisk        FLASH

        U-BOOT环境变量

8M_FLASH 63 扇区       FLASH

16M_FLASH 127扇区      

0x2000 0000

                        SDRAM

0x2100 0000

          ulmage        SDRAM

0x2110 0000

         ramdisk        SDRAM

 

 

各种文件的内存分布图

3.4 U-BOOTat91rm9200上移植修改的文件

为了使u-boot-1.0.0支持新的开发板,一种简便的做法是在u-boot已经支持的开发板中参考选择一种较接近板的进行修改幸运的是在u-boot-1.0.0中已经有了at91rm9200的支持。 下面将详细阐述对其进行移植所需要关注的几个方面:

l       修改原因:

硬件平台不同部分:由于目标板对GPIO、串口等硬件的使用不同或选择的RAMflash等芯片的不同,都需要对相应的控制寄存器和硬件设备进行不同的初始化。

bootloader增加新的功能:比如,有时想在目标平台上增加USBEthernet下载功能等,同样需要在源码中加入相应的代码。

l       移植相关内容:

²      include/configs/at91rm9200dk.h 它包括开发板的CPU、系统时钟、RAMFlash系统及其它相关的配置信息。与具体的板子相关,是移植的最重要文件。

²      include/asm-arm/AT91RM9200.h, 该文件描述了9200寄存器的结构及若干宏定义。具体内容要参考相关处理器手册。相同CPU的此文件相同,拷贝一份即可,无需修改。

 

²      cpu/at91rm9200/目录下别为cpu.cinterrupts.cserial.c等文件。

Ø       cpu.c 无需改动,缓存,中断堆栈初始化,MMU映射等

Ø       interrupts.c无需修改。各种中断的处理函数,U-boot运行无需中断,同时实现为重启;定时中断实现为查询方式,主要用于Xmodem协议传输文件。

Ø       serial.c 无需修改,串口初始化,接收发送等。

Ø       上述文件都是与CPU相关的,与板子本身的配置无关。通常选择一个相同的CPU下的相关文件即可,无需修改。

 

²      board/at91rm9200dk/目录下分别为flash.cat91rm9200dk.cconfig.mkMakefileu-boot.lds

Ø      flash.c : u-boot读、写和删除Flash设备的源代码文件。由于不同开发板中Flash存储器的种类各不相同(是移植的重点,可以从其他CPU目录下看是否有相同的flash,所以,修改flash.c时需参考相应的Flash芯片手册。

Ø      at91rm9200dk.c

板级初始化,DRAM地址初始化。修改文件

/* arch number of AT91RM9200DK-Board */

gd->bd->bi_arch_number = 251;

/* adress of boot parameters */

gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;

体系结构号,CPU相关,同CPU此值相同。

bi_boot_params内核启动参数的首地址,通常为PHYS_SDRAM + 0x100SDRAM100处,很重要,Linux内核移植时,此值需要匹配。

Ø      config.mk

TEXT_BASE = 0x21f00000u-boot将被载入SDRAM高端部分

注意,对于不同的系统RAM大小可能不一样,要根据实际情况调整

Ø      Makefile 无需修改,除非改动了at91rm9200dk.c的名字,目标文件要改动。

OBJS        := at91rm9200dk.o flash.o

Ø      u-boot.lds 链接脚本设置u-boot中各个目标文件的连接地址。无需修改

 

²      Makefile

u-boot-1.0.0/Makefile

at91rm9200dk_config : unconfig

./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk

其中ARMCPU的种类, at91rm9200ARM CPU对应的代码目录,at91rm9200dk是自已主板对应的目录。

 

3.5 移植的具体步骤

关于u-boot的移植如下,由于u-boot的软件设计体系非常清晰,它的移植工作并不复杂,相信各位的代码阅读功力不错的话,参照如下就可以完成。

×××××××××××××××××××××××××××××××××××

If the system board that you have is not listed, then you will need to port U-Boot to your hardware platform. To do this, follow these steps:

1. Add a new configuration option for your board to the toplevel "Makefile" and to the "MAKEALL" script, using the existing entries as examples. Note that here and at many other places boards and other names are listed in alphabetical sort order. Please keep this order.

2. Create a new directory to hold your board specific code. Add any files you need. In your board directory, you will need at least the "Makefile", a ".c", "flash.c" and "u-boot.lds".

3. Create a new configuration file "include/configs/.h" for your board

4. If you're porting U-Boot to a new CPU, then also create a new directory to hold your CPU specific code. Add any files you need.

5. Run "make _config" with your new name.

6. Type "make", and you should get a working "u-boot.srec" file

7. Debug and solve any problems that might arise. [Of course, this last step is much harder than it sounds.]

××××××××××××××××××××××××××××××××××××

 

(一)在board文件夹下面建立自己的开发板的文件夹。一般的,要选取与自己的开发板硬件设置最为接近的型号。在uboot1.1.1中,已经支持at91rm9200,所以可以选取at91rm9200dk作为模板进行修改。设置你的开发板的名字,随意即可,我的设置为:myboard

[root@dding u-boot-1.1.1]$ cd board

[root@dding board]$ cp -R at91rm9200dk/ myboard/

[root@dding board]$ cd myboard

[root@dding myboard]$ ls

at91rm9200dk.c  config.mk  flash.c  Makefile  u-boot.lds

 

(二)可以看到,这里共有5个文件。首先,要修改主文件的名字,即要把at91rm9200dk.c更改为myboard.c。其次,要更改config.mkTEXT_BASE的数值,其为ubootRAM中的运行地址。注意,由于at91rm9200中是由boot.binuboot映象直接拷贝到RAM中了,TEXT_BASE值必须和boot.bin拷贝的地址一致。否则uboot发现运行地址和链接地址不同时会再次执行自拷贝过程,可能将自己覆盖。由于接下来,因为在at91rm9200dk用的是AMDflash,而我的开发板上用的是Intel28F128J3A,那么需要另外找Intelflash.C,以减少工作量。在strong ARM构架里有xm250,它的flashIntel的,修改的东西并不是很多。需要注意的是,xm250flash位宽是32,而我的位宽是16,要根据这个进行相应的修改。最后,修改Makefile,主要是修改生成文件的名字。具体操作如下:


[root@dding myboard]$ mv at91rm9200dk.c myboard.c
[root@dding myboard]$ cat config.mk
TEXT_BASE = 0x21f80000
[root@dding myboard]$ vi config.mk

修改成:TEXT_BASE = 0x21f00000,然后保存退出。

[root@dding myboard]$ vi Makefile

include $(TOPDIR)/config.mk

LIB     = lib$(BOARD).a

OBJS    := myboard.o flash.o

SOBJS   :=

$(LIB): $(OBJS) $(SOBJS)

        $(AR) crv $@ $(OBJS) $(SOBJS)

clean:

        rm -f $(SOBJS) $(OBJS)

[root@dding myboard]$ rm flash.c

[root@dding myboard]$ cp ../xm250/flash.c ./

[root@dding myboard]$ ls

config.mk  flash.c  Makefile  myboard.c  u-boot.lds

[root@dding myboard]$ vi flash.c

 

     34 #undef FLASH_PORT_WIDTH32   /*不定义位宽32*/
     35 #define FLASH_PORT_WIDTH16  /*
定义位宽16*/

216         switch (value) {
    217 
    218         case (FPW) INTEL_ID_28F128J3A: 
/*
就是这个芯片*/

    219                 info->flash_id += FLASH_28F128J3A;
    220                 info->sector_count = 128;
    221                 
info->size = 0x01000000;
    222                 break;                          /* => 16 MB     */

    223 
    224         case (FPW) 
INTEL_ID_28F640J3A:    

225                 info->flash_id += FLASH_28F640J3A;
    226                 info->sector_count = 64;
    227                 info->size = 0x00800000;
    228                 break;                          /* => 8 MB     */

 

[root@dding myboard]$ cd ../..

[root@dding u-boot-1.1.1]$ vi Makefile

#########################################################################

## AT91RM9200 Systems

#########################################################################

at91rm9200dk_config     :       unconfig

        @./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk

myboard_config  :       unconfig
        @./mkconfig $(@:_config=) arm at91rm9200
 myboard

#########################################################################

在这里,可以在命令模式下输入“/at91rm9200”快速查找at91rm9200dk,仿照它的例子,写出自己板子的配置。注意的是,第二行开头要用TAB,不是空格,否则报错。选项arm表示目标板架构,at91rm9200表示CPU中对应的目录myboard是你自己的开发板名字,对应board下的目录。

 

(三)修改主要的配置文件。配置选项比较多,主要是配置cpu,波特率,flashsdram的类型大小,环境变量的偏移量等等,容易出错。应该首先了解硬件情况,仔细对应芯片资料进行修改。见上面的《AT91RM9200开发板的存储器情况

[root@dding u-boot-1.1.1]$ cd include/configs
[root@dding configs]$ cp at91rm9200dk.h myboard.h
[root@dding configs]$ vi myboard.h

 

#define CONFIG_ myboard     1    /* on an myboard Board      */

#undef CONFIG_USE_IRQ                    /* we don't need IRQ/FIQ stuff */

#define CONFIG_CMDLINE_TAG        1    /* enable passing of ATAGs     */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG     1

 

#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128*1024)

#define CONFIG_BAUDRATE 115200

 

#define CONFIG_BOOTDELAY      3               // uboot延时等待时间

/* #define CONFIG_ENV_OVERWRITE  1 */

 

#define CONFIG_COMMANDS            /

                       ((CONFIG_CMD_DFL      | /

                       CFG_CMD_DHCP ) & /

                      ~(CFG_CMD_BDI | /

                       CFG_CMD_IMI | /

                       CFG_CMD_AUTOSCRIPT | /

                       CFG_CMD_FPGA | /

                       CFG_CMD_MISC | /

                       CFG_CMD_LOADS ))

 

/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */

#include <cmd_confdefs.h>

 

#define CONFIG_NR_DRAM_BANKS 1              // sdram banks,我的是一个,通常都是一个

#define PHYS_SDRAM 0x20000000                      // sdram起始地址,at91rm9200统一为0x20000000

#define PHYS_SDRAM_SIZE 0x2000000  /* 32 M */  

// sdram容量32MB,需要根据实际情况修改,芯片为两片三星的16×16M K4S281632F

#define CFG_MEMTEST_START PHYS_SDRAM

#define CFG_MEMTEST_END   CFG_MEMTEST_START + PHYS_SDRAM_SIZE – 0x10 0000

SDRAM高端部分此时运行着U-boot,测试时不能对自身进行

 

#define CONFIG_DRIVER_ETHER  支持以太网驱动

#define CONFIG_NET_RETRY_COUNT 20

 

// flashintel16M 28F128J3A in 128 Sectors

#define PHYS_FLASH_1 0x10000000    //起始地址,at91rm9200统一为0x10000000

#define PHYS_FLASH_SIZE 0x100 0000  /* 16M main flash */

#define CFG_FLASH_BASE          PHYS_FLASH_1            // PHYS_FLASH_1  flash起始地址别名

#define CFG_MAX_FLASH_BANKS 1 // flash最大banks

#define CFG_MAX_FLASH_SECT 128          //扇区总数

#define CFG_FLASH_ERASE_TOUT    (2*CFG_HZ) /* Timeout for Flash Erase */

#define CFG_FLASH_WRITE_TOUT    (2*CFG_HZ) /* Timeout for Flash Write */

PHYS_FLASH_SIZECFG_MAX_FLASH_SECT通常都未用,因此上述错误没有体现出来

 

#define     CFG_ENV_IS_IN_FLASH     1      // 环境变量保存在flash

#define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x20000×127)  // 环境变量在flash中的地址

#define CFG_ENV_SIZE   0x20000     // 环境变量的大小,一个sector

#define CFG_LOAD_ADDR 0x21000000  /* default load address */

// 内核印象默认的加载地址,需要与自启动的参数匹配下

 

// 关于U-boot的启动代码等大小和地址对任何CPU都无需改动,但是实际往flash中存储时需要按照此地址来进行

//boot.bin 0x1000 0000

//u-boot.gz 0x1001 0000

#define CFG_BOOT_SIZE             0x6000 /* 24 KBytes */            // boot.bin的大小

#define CFG_U_BOOT_BASE      (PHYS_FLASH_1 + 0x10000)  // u-boot.gz的存放位置,此位置不能随意更改,必须和boot.bin中的地址一致

#define CFG_U_BOOT_SIZE         0x10000   /* 64 KBytes */  // u-boot.gz占据的flash空间,半个sector

 

#define CFG_BAUDRATE_TABLE {115200 , 19200, 38400, 57600, 9600 }

 

#define CFG_PROMPT "Uboot> " /* Monitor Command Prompt */ // U-boot的提示符,可随意更改

#define     CFG_CBSIZE 256 /* Console I/O Buffer Size */

#define CFG_MAXARGS 16 /* max number of command args */

#define     CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */

 

四、编译u-boot

[root@dding configs]$ cd ../..

[root@dding u-boot-1.1.1]$ make myboard_config

Configuring for myboard board...

[root@dding u-boot-1.1.1]$ make CROSS_COMPILE=arm-linux-

 

生成三个文件:u-boot.bin, u-boot, u-boot.srec

u-boot.bin is a raw binary image

u-boot is an image in ELF binary format

u-boot.srec is in Motorola S-Record format (objcopy -O srec -R.note -R.comment -S [inputfile] [outfile]

u-boot ELF格式的文件,可以被大多数Debug程序识别;

u-boot.bin二进制bin文件,纯粹的U-BOOT二进制执行代码,不保存ELF格式和调试信息。这个文件一般用于烧录到用户开发板中;

u-boot.srec— Motorola S-Record格式,可以通过串行口下载到开发板中。

然后把生成的uboot.bin保存,并且压缩一下得到uboot.bin.gz

 

一种方式是通过JTAG口将u-boot.bin烧写到Flash的零地址,复位后就可以启动系统了。此时无需boot.bin

 

但是对于at91rm9200,我们是通过boot.bin来过渡的,烧写的是u-boot.bin.gz。以上工作完成我们可以通过串口将u-boot.bin下载到主板的SDRAM中,它会自动执行, 并出现uboot>

 

这里我们可以通过串口把boot.bin, u-boot.bin.gz下载到主板,再用u-boot的提供的写flash功能分别把boot.bin, u-boot.bin.gz写入到flash中,完成以上工作后,对主板跳线选择片外启动,板子复位后会自动启动u-boot。其首先运行boot.bin,其将u-boot.bin.gz解压缩到RAM中为u-boot.bin,并跳转至u-boot.bin开始执行。

 U-boot如何引导Linux内核启动?

4.1  GO命令引导未用mkimage生成的内核

4.1.1 非压缩内核Image

1)       运行地址!=链接地址0x20008000,不能启动

Uboot> tftp 21000000 Image;tftp 21100000 ramdisk;go 21000000

。。。。

done

Bytes transferred = 6993691 (6ab71b hex)

## Starting application at 0x21000000 ...

Error: a 在哪提示的?

 

2)       运行地址=链接地址0x20008000不能启动,难道是ramdisk的问题

Uboot> tftp 20008000 Image;tftp 21100000 ramdisk;go 20008000

。。。。

done

Bytes transferred = 6993691 (6ab71b hex)

## Starting application at 0x21000000 ...

Error: a

 

4.1.2 压缩内核zImage

1)       运行地址!=链接地址0x20008000,能启动,内核自解压成功,但是解压后的内核运行错误

Uboot> tftp 21000000 zImage;tftp 21100000 ramdisk;go 21000000

。。。。。。。。。。。

done

Bytes transferred = 6993691 (6ab71b hex)

## Starting application at 0x21000000 ...

Uncompressing Linux............................................................. done, booting the kernel.

€?~??鄜屈

 

2)       运行地址==链接地址0x20008000,能启动,内核自解压成功,但是解压后的内核运行错误

 

Uboot> tftp 20008000 zImage;tftp 21100000 ramdisk; go 20008000

## Starting application at 0x20008000 ...

Uncompressing Linux............................................................. done, booting the kernel.

€?~??鄜屈

 

上面的ramdisk都是添加了uboot的头的,去掉头部再试试。去掉了还是不行,go方法的ramdisk的地址是怎么设置的??要详细看下ubootramdisk这块是如何跟内核交互的?

 

4.2 Mkimage参数意义解析

通过mkimage这个tool可以给zImage添加一个header

typedef struct image_header {

        uint32_t    ih_magic; /* Image Header Magic Number      */

        uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */

        uint32_t    ih_time;    /* Image Creation Timestamp   */

        uint32_t    ih_size;     /* Image Data Size           */

        uint32_t    ih_load;    /* Data     Load  Address             */

        uint32_t    ih_ep;              /* Entry Point Address             */

        uint32_t    ih_dcrc;    /* Image Data CRC Checksum        */

        uint8_t             ih_os;               /* Operating System         */

        uint8_t             ih_arch;    /* CPU architecture         */

        uint8_t             ih_type;    /* Image Type                 */

        uint8_t             ih_comp;  /* Compression Type                */

        uint8_t             ih_name[IH_NMLEN];    /* Image Name                */

} image_header_t;

 

header是如何生成的?利用u-boot里面的mkimage工具来生成uImage   u-boot源码包/tools/mkimage.c )

这里解释一下参数的意义:

-A ==> set architecture to 'arch'

-O ==> set operating system to 'os'

-T ==> set image type to 'type' “kernel或是ramdisk”

-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,即不进行文件的拷贝,在当前位置执行)

 

对于ARM linux内核映象用法:

-A arm     -------- 架构是arm
-O linux    -------- 
操作系统是
linux
-T kernel  -------- 
类型是
kernel
-C none/bzip/gzip    -------- 
压缩类型

-a 20008000 ---- image
的载入地址(hex),通常为0xX00008000
-e 200080XX---- 
内核的入口地址(hex)XX0x40或者
0x00
-n linux-XXX --- image
的名字,任意

-d nameXXX             ---- 
无头信息的image文件名,你的源内核文件
uImageXXX    ---- 
加了头信息之后的image文件名,任意取

 

4.3 Bootm的流程分析

Bootm命令在/common/cmd_bootm.cdo_bootm函数

 

》》》》》》》》》》》获取当前内核的地址,默认地址或者bootm的第一个参数

默认的加载地址或传递给bootm命令(优先)与实际的内核存放地址需要一致

if (argc < 2) {

                addr = load_addr; // load_addr = CFG_LOAD_ADDR;

        } else {

                addr = simple_strtoul(argv[1], NULL, 16);

        }

printf ("## Booting image at %08lx .../n", addr);

 

》》》》》》》》》》》》获得image头,没有mkimage的就返回了

memmove (&header, (char *)addr, sizeof(image_header_t));

 

》》》》》》》》》》》》打印头部信息

print_image_hdr ((image_header_t *)addr);

实例:

Image Name:   dd-kernel-2.4.19

   Image Type:   ARM Linux Kernel Image (gzip compressed)

   Data Size:    869574 Bytes = 849.2 kB

   Load Address: 20008000

   Entry Point:  20008000

 

》》》》》》》》》》》》校验image头部

printf ("   Verifying Checksum ... ");       printf ("OK/n");

 

》》》》》》》》》》》》检查image支持的体系结构即—A 选项是否为arm或者ppc

 

》》》》》》》》》》》》检查image的类型

TYPE_MULTI 是否指内核与文件系统一起,内核后面有个分界线

switch (hdr->ih_type)

case IH_TYPE_KERNEL:

                name = "Kernel Image";

                break;

        case IH_TYPE_MULTI:

 

》》》》》》》》》》判断内核的压缩类型

此处的内核是否压缩非zImageImage的概念,而是指内核在被mkimage处理前是否用gunzip等压缩过

switch (hdr->ih_comp) {  

        case IH_COMP_NONE:         // 非压缩内核

                if(ntohl(hdr->ih_load) == addr) {      

// 当前内核存放的地址与-a指定的一致,则不搬动,-e必须必-a0x40

                       printf ("   XIP %s ... ", name);

                } else {

//当前内核存放的地址与-a指定的不一致,则将内核搬到-a地址,此时-a与-e必相同

memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

。。。。

case IH_COMP_GZIP:

                printf ("   Uncompressing %s ... ", name);

                if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,

//压缩内核,将除去头部的内核解压到-a 指定的地址了,要求-a与-e相同

// 为防止解压缩时覆盖,对于压缩内核,内核存放地址最好在—a后面

                           (uchar *)data, (int *)&len) != 0) {

                       do_reset (cmdtp, flag, argc, argv);

                }

                break;

 

》》》》》》》》》》》》》》》》判断操作系统类型

switch (hdr->ih_os) {

        default:                    /* handled by (original) Linux case */

        case IH_OS_LINUX:

            do_bootm_linux  (cmdtp, flag, argc, argv, addr, len_ptr, verify);        

//前四个为传给bootm的,addr为内核最初的存放地址,没有用处

            break;

 

#ifdef CONFIG_PPC

static boot_os_Fcn do_bootm_linux;

#else

extern boot_os_Fcn do_bootm_linux;

由上可知,对于ppc和其他体系结构的do_bootm_linux函数实现是不一样的

》》》》》》》》》》》》》》启动Linux内核

do_bootm_linux (cmd_tbl_t *cmdtp, int flag,

                int    argc, char *argv[],

                ulong        addr,

                ulong        *len_ptr,

                int    verify)

 

》》》》》》》》》》》》获取命令行参数

if ((s = getenv("bootargs")) == NULL)

                s = "";

        strcpy (cmdline, s);

 

》》》》》》》》》》》》赋内核启动地址

kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep;

注意,对于压缩过的内核,会将内核解压到-a指定的地址,此时-a -e 地址必须相同

 

》》》》》》》》》》》判断bootm的命令参数中是否有initrd

        if (argc >= 3) {

                addr = simple_strtoul(argv[2], NULL, 16);

                printf ("## Loading RAMDisk Image at %08lx .../n", addr);

 

若有initrd则赋值,否则为0

 

》》》》》》》》》》》》》》》启动Linux内核

/*

         * Linux Kernel Parameters:

         *   r3ptr to board info data

         *   r4: initrd_start or 0 if no initrd

         *   r5: initrd_end - unused if r4 is 0

         *   r6: Start of command line string

         *   r7: End   of command line string

         */

//*kbd = *(gd->bd); 在上面赋值的

        (*kernel) (kbd, initrd _start, initrd_end, cmd_start, cmd_end);

 

启动流程的总结:

 

对于gzip压缩的内核bootm命令会首先判断bootm xxxx 这个指定的地址xxxx是否与-a指定的加载地址相同。

(1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之(此时-e选型必须同-a

(2)如果相同的话那就让其原封不动的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部。

 

对于gzip压缩过的内核,因为u-boot要对其解压,因此运行地址是不能等于-a指定的地址的,且必须有一定的间隔,否则解压到-a的内核会覆盖当前运行的程序。此时要求-a等于-e指定的地址。

 

4.4 如何用mkimage生成uImage

 

1> mkimage 如何指定入口参数 ( -e  0xxxxxx)

2> mkimage 指定了入口参数后, 你用tftpboot 下载kernel到哪个地址?

3> -c 如何指定?

 

uboot里面的解压和内核自解压的区别: u-boot 里面的解压实际上是bootm 实现的 , 把 mkimage -C bzip2或者gzip 生成的 uImage进行解压 ; 而kernel的自解压是对zImage进行解压,发生在bootm解压之后。

 

U-boot 对内核添加头部时,前面已经用gzip压缩过一次内核了,而不是指原有的内核印象是否是压缩内核。指uImage 本身被压缩了,即对原来的zImage/Image添加了U-boot的压缩方式,使得生成的uImage变小了。此时-c gzip

若没有对zImage/Imagegzip命令压缩过,则-c none

 

综合上面分析,mkimage的影响因子为:

e,内核的入口地址是否与-a相同

Tftpaddr,即将内核加载到RAM中运行的地址,决定是否搬运或解压内核

c,内核是否经过gzip压缩过,决定了是搬运还是解压

 

另外内核本身为非压缩的ImagezImage也是一个影响因子。组合情况共2^4 =16

 

4.5 Bootm命令引导mkimage生成的内核全程解析

4.5.1 非压缩的Image内核

 

1Mkimage 之前用gzipImage进行压缩

<1> -a=-e = 0x20008000tftpaddr= 0x21000000

解压到-a指定的地址,成功启动

Uboot> tftp 21000000 uImage-zip-8000;tftp 21100000 ramdisk;bootm 21000000

## Booting image at 21000000 ...

   Image Name:   dd-kernel-2.4.19-zip-8000

   Image Type:   ARM Linux Kernel Image (gzip compressed)

   Data Size:    869629 Bytes = 849.2 kB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

   Uncompressing Kernel Image ... OK

 

Starting kernel ...

 

Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #42  10 11 14:15:35 CST 2007

AT91RM9200DK login: root

 

<2> -a=-e = 0x20008000 tftpaddr= 0x20008000

解压失败,启动失败

Uboot> tftp 20008000 uImage-zip-zImage-8000;tftp 21100000 ramdisk;bootm 20008000

 

Uboot> tftp 20008000 uImage-zip-8000;tftp 21100000 ramdisk;bootm 20008000

## Booting image at 20008000 ...

   Image Name:   dd-kernel-2.4.19-zip-8000

   Image Type:   ARM Linux Kernel Image (gzip compressed)

   Data Size:    869629 Bytes = 849.2 kB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

   Uncompressing Kernel Image ... Error: inflate() returned -3

GUNZIP ERROR - must RESET board to recover

由于当前运行地址tftpaddr与解压缩后的地址-a重合了,导致解压缩失败,因此二者必须相隔一定的距离

 

<3> -a=0x20008000-e = 0x20008040 tftpaddr= 0x21000000

能够解压到-a地址,但-e指定的入口不对,启动失败

 

Uboot> tftp 21000000 uImage-zip-8040;tftp 21100000 ramdisk;bootm 21000000

 

TFTP from server 192.168.0.12; our IP address is 192.168.0.15

Filename 'uImage-zip-8040'.

Load address: 0x21000000

。。。。。。。。。

## Booting image at 21000000 ...

   Image Name:   dd-kernel-2.4.19-zip-8040

   Image Type:   ARM Linux Kernel Image (gzip compressed)

   Data Size:    869629 Bytes = 849.2 kB

   Load Address: 20008000

   Entry Point:  20008040

   Verifying Checksum ... OK

   Uncompressing Kernel Image ... OK

 

Starting kernel ... 死了

 

<4> -a=-e = 0x20008000 tftpaddr= 0x20008000

解压失败,入口也不对,启动失败

 

2Mkimage 之前未对Image进行压缩

 

<1> -a=-e = 0x20008000 tftpaddr= 0x21000000

搬动到-a指定的地址,成功启动

Uboot> tftp 21000000 uImage-nzip-8000;tftp 21100000 ramdisk;bootm 21000000

## Booting image at 21000000 ...

   Image Name:   dd-kernel-2.4.19-nzip-8000

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    1873059 Bytes =  1.8 MB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... Bad Data CRC

为什么总是校验失败呢?当前的内核印象为1.8M,难道太大了,后面的ramdisk将其覆盖??

下面未拷贝ramdisk,校验成功,成功启动,无法安装跟文件系统,是因为无ramdisk。说明上面确实是覆盖了,因此要对于大的内核印象要合理设置tftpaddr的地址和ramdisk的地址

 

Addrramdisk)= 0x2110 0000

Addrtftpaddr)= 0x2100 0000

Addrramdisk)-Addrtftpaddr)= 0x10 0000  1M < 1.8M

Uboot> tftp 21000000 uImage-nzip-8000;bootm 21000000

## Booting image at 21000000 ...

   Image Name:   dd-kernel-2.4.19-nzip-8000

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    1873059 Bytes =  1.8 MB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

OK

 

Starting kernel ...

 

Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #44  10 11 17:27:24 CST 2007

。。。。。。。

Kernel panic: VFS: Unable to mount root fs on 01:00

 

Addrramdisk- 2M = 0x20f0 0000  Addrtftpaddr)成功启动

 

Uboot> tftp 20f00000 uImage-nzip-8000;tftp 21100000 ramdisk;bootm 20f00000

## Booting image at 20f00000 ...

   Image Name:   dd-kernel-2.4.19-nzip-8000

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    1873059 Bytes =  1.8 MB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

OK

 

Starting kernel ...

Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #44  10 11 17:27:24 CST 2007

AT91RM9200DK login: root

 

<2> -a=-e = 0x20008000 tftpaddr= 0x20008000

不搬动,但-e地址不对,失败

 

<3> -a=0x20008000-e = 0x20008040 tftpaddr= 0x20008000

不搬动,但未成功启动,入口地址对的啊?????

Uboot> tftp 20008000 uImage-nzip-8040;tftp 21100000 ramdisk;bootm 20008000

 

## Booting image at 20008000 ...

   Image Name:   dd-kernel-2.4.19-nzip-8040

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    1873059 Bytes =  1.8 MB

   Load Address: 20008000

   Entry Point:  20008040

   Verifying Checksum ... OK

   XIP Kernel Image ... OK

 

Starting kernel ...死了????

 

<4> -a=0x20008000-e = 0x20008040 tftpaddr= 0x21000000

搬动,但-e地址不对,失败

 

4.5.2 压缩的zImage内核

 

1Mkimage 之前用gzipzImage进行压缩,即-c gzip

<1> -a=-e = 0x20008000tftpaddr= 0x21000000

解压到-a指定的地址,成功启动

Uboot> tftp 21000000 uImage-zip-zImage-8000;tftp 21100000 ramdisk;bootm 21000000

 

TFTP from server 192.168.0.12; our IP address is 192.168.0.15

Filename 'uImage-zip-zImage-8000'.

Load address: 0x21000000

## Booting image at 21000000 ...

   Image Name:   dd-zip-zImage-8000

   Image Type:   ARM Linux Kernel Image (gzip compressed)

   Data Size:    876753 Bytes = 856.2 kB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

   Uncompressing Kernel Image ... OK  // U-boot对内核解压

 

Starting kernel ...

Uncompressing Linux..............压缩内核zImage自解压......................... done, booting the kernel.

 

Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #43  10

AT91RM9200DK login: root

[root@AT91RM9200DK /root]$ls

 

<2> -a=-e = 0x20008000 tftpaddr= 0x20008000

解压失败,启动失败

Uboot> tftp 20008000 uImage-zip-zImage-8000;tftp 21100000 ramdisk;bootm 20008000

 

TFTP from server 192.168.0.12; our IP address is 192.168.0.15

Filename 'uImage-zip-zImage-8000'.

Load address: 0x20008000

## Booting image at 20008000 ...

   Image Name:   dd-zip-zImage-8000

   Image Type:   ARM Linux Kernel Image (gzip compressed)

   Data Size:    876753 Bytes = 856.2 kB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

   Uncompressing Kernel Image ... Error: inflate() returned -3

GUNZIP ERROR - must RESET board to recover

由于当前运行地址tftpaddr与解压缩后的地址-a重合了,导致解压缩失败,因此二者必须相隔一定的距离

 

<3> -a=0x20008000-e = 0x20008040 tftpaddr= 0x21000000,失败

 

Uboot> tftp 21000000 uImage-zip-zImage-8040;tftp 21000000 ramdisk;bootm 21000000

 

TFTP from server 192.168.0.12; our IP address is 192.168.0.15

Filename 'uImage-zip-zImage-8040'.

Load address: 0x21000000

。。。。。。。。。

## Booting image at 21000000 ...

Bad Magic Number 难道对于压缩内核,幻数对的条件是-a==-e地址??即压缩内核默认-a==-e??

此法肯定失败,但问题出在这,还真不对啊,不试了,感兴趣的朋友可以玩下

 

2Mkimage 之前未对zImage进行压缩,即-c none

 

<1> -a=-e = 0x20008000 tftpaddr= 0x21000000

搬动到-a指定的地址,成功启动

Uboot> tftp 21000000 uImage-nzip-zImage-8000;tftp 21100000 ramdisk;bootm 21000000

## Booting image at 21000000 ...

   Image Name:   dd-nzip-zImage-8000

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    881748 Bytes = 861.1 kB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

OK

 

Starting kernel ...

Uncompressing Linux............................................................. done, booting the kernel.

 

Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #43  10 11 14:25:14 CST 2007

AT91RM9200DK login:

 

<2> -a=-e = 0x20008000 tftpaddr= 0x20008000

不搬动,但-e地址不对,失败

Uboot> tftp 20008000 uImage-nzip-zImage-8000;tftp 21100000 ramdisk;bootm 20008000

## Booting image at 20008000 ...

   Image Name:   dd-nzip-zImage-8000

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    881748 Bytes = 861.1 kB

   Load Address: 20008000

   Entry Point:  20008000

   Verifying Checksum ... OK

   XIP Kernel Image ... OK

 

Starting kernel ... 死了。。。

 

<3> -a=0x20008000-e = 0x20008040 tftpaddr= 0x20008000

不搬动,成功启动

Uboot> tftp 20008000 uImage-nzip-zImage-8040;tftp 21100000 ramdisk;bootm 20008000

 

## Booting image at 20008000 ...

   Image Name:   dd-nzip-zImage-8040

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    881748 Bytes = 861.1 kB

   Load Address: 20008000

   Entry Point:  20008040

   Verifying Checksum ... OK

   XIP Kernel Image ... OK

 

Starting kernel ...

 

Uncompressing Linux............................................................. done, booting the kernel.

Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #43  10 11 14:25:14 CST 2007

AT91RM9200DK login:

 

<4> -a=0x20008000-e = 0x20008040 tftpaddr= 0x21000000

搬动,但-e地址不对,失败

 

4.5.3 关于压缩及非压缩内核bootm启动的全面总结

 

由上面的16个例子,我们可以看出,能够启动内核的由以下几种情况:

各种情况对应的统一ramdiskaddr= 0x21100000

<1>非压缩的Image内核:

-a=-e = 0x20008000 –c=nonetftpaddr= 0x20f00000

此法主要由于内核太大,导致tftpaddr做了一定的修正

-a= 0x20008000 -e = 0x20008040–c=nonetftpaddr=0x20008000

此法理论上可行,但我未试验成功,有兴趣的朋友可以探究下

对于非压缩的Image内核,mkimage之前不压缩的话,内核印象较大,此法不常用

 

-a=-e = 0x20008000 –c=gziptftpaddr= 0x21000000

–c=gzip压缩内核必须解压,只有这种情况成功;其他解压覆盖或者-e入口不对

 

<2>压缩的zImage内核:

-a=-e = 0x20008000 –c=nonetftpaddr= 0x21000000

-a= 0x20008000 -e = 0x20008040–c=nonetftpaddr=0x20008000

-a=-e = 0x20008000 –c=gziptftpaddr= 0x21000000

–c=gzip压缩内核必须解压,只有这种情况成功;其他解压覆盖或者-e入口不对

zImage已经压缩过一次了,一般无需再压缩,此法不常用

 

常见方法:

<1>非压缩的Image内核:

-a=-e = 0x20008000 –c=gziptftpaddr= 0x21000000

<2>压缩的zImage内核:

-a=-e = 0x20008000 –c=nonetftpaddr= 0x21000000

-a= 0x20008000 -e = 0x20008040–c=nonetftpaddr=0x20008000 

待续:

U-boot如何向Linux内核传递命令行参数?

Go引导内核的详细方法?

#生成uImage 的mkImage 命令行,其中需要关注的就是-a 与 -e 参数。 

#参数-a:指明uImage 加载的SDRAM 地址,内核默认指定加载地址为0x30008000 。 

#       u-boot 引导时,bootm 命令跳到与上相同位置执行,检查完镜像头后,它会跳到内核真正的入口点开 

始执    。 

#参数-e:指明uImage 中刨去镜像头后真正的内核入口地址。 

#    镜像头为0x40 长,故此处指定为0x30008040 。 

#       u-boot 引导时,go 命令可以直接指定此位置。go 命令不检查镜像头。 

quiet_cmd_uimage = UIMAGE  $@ 

      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel / 

                  -C none -a $(ZRELADDR) -e 0x30008040 / 

                  -n 'Linux-$(KERNELRELEASE)' -d $< $@ 


Ramdiskinitrd怎么传给内核?


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值