U-BOOT全线移植(2)

时间:2021-07-19 16:36:25

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怎么传给内核?