嵌入式linux怎么查看boot的,【嵌入式Linux学习七步曲之第三篇 Linux系统bootlaoder移植】U-BOOT全线移植分析系列之四--U-boot如何引导Linux内核启动? - Sa...

U-BOOT全线移植分析系列之四

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

【摘要】本节介绍了U-boot使用go或bootm启动linux内核的方法。首先介绍了mkimage的参数意义和bootm的详细执行流程。然后分析了如何利用mkimage生成内核映象的方法。对于bootm方式的内核是否压缩、-a、-e、运行地址等16种组合情况,给出了详细的测试过程,提出了6种可用方法种的三种最优解。

【关键字】:U-boot;AT91RM9200;bootm;mkimage;-a;-e;-c

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

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

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

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的地址是怎么设置的??要详细看下uboot在ramdisk这块是如何跟内核交互的?

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

typedef struct image_header {

uint32_tih_magic;/* Image Header Magic Number*/

uint32_tih_hcrc;/* Image Header CRC Checksum*/

uint32_tih_time;/* Image Creation Timestamp*/

uint32_tih_size;/* Image Data Size*/

uint32_tih_load;/* DataLoadAddress*/

uint32_tih_ep;/* Entry Point Address*/

uint32_tih_dcrc;/* Image Data CRC Checksum*/

uint8_tih_os;/* Operating System*/

uint8_tih_arch;/* CPU architecture*/

uint8_tih_type;/* Image Type*/

uint8_tih_comp;/* Compression Type*/

uint8_tih_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 imagedata 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),XX为0x40或者0x00

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

Bootm命令在/common/cmd_bootm.c中do_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:

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

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

switch (hdr->ih_comp) {

case IH_COMP_NONE://非压缩内核

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

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

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,

intargc, char *argv[],

ulongaddr,

ulong*len_ptr,

intverify)

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

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:

*r3:ptr 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: Endof 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如何指定入口参数( -e0xxxxxx)

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

3> -c如何指定?

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

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

若没有对zImage/Image用gzip命令压缩过,则-c none。

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

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

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

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

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

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

4.5.1非压缩的Image内核

(1)Mkimage之前用gzip对Image进行压缩

<1> -a=-e = 0x20008000,tftpaddr= 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

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

(2)Mkimage之前未对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的地址

Addr(ramdisk)=0x2110 0000

Addr(tftpaddr)=0x2100 0000

Addr(ramdisk)-Addr(tftpaddr)=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

Addr(ramdisk)- 2M = 0x20f0 0000=Addr(tftpaddr)成功启动

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内核

(1)Mkimage之前用gzip对zImage进行压缩,即-c gzip

<1> -a=-e = 0x20008000,tftpaddr= 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??

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

(2)Mkimage之前未对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=none,tftpaddr= 0x20f00000

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

-a= 0x20008000,-e = 0x20008040,–c=none,tftpaddr=0x20008000

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

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

-a=-e = 0x20008000,–c=gzip,tftpaddr= 0x21000000

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

<2>压缩的zImage内核:

-a=-e = 0x20008000,–c=none,tftpaddr= 0x21000000

-a= 0x20008000,-e = 0x20008040,–c=none,tftpaddr=0x20008000

-a=-e = 0x20008000,–c=gzip,tftpaddr= 0x21000000

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

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

常见方法:

<1>非压缩的Image内核:

-a=-e = 0x20008000,–c=gzip,tftpaddr= 0x21000000

<2>压缩的zImage内核:

-a=-e = 0x20008000,–c=none,tftpaddr= 0x21000000

-a= 0x20008000,-e = 0x20008040,–c=none,tftpaddr=0x20008000

待续:

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

Go引导内核的详细方法?

Ramdisk与initrd怎么传给内核?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值