Chinaunix首页 | 论坛 | 博客
  • 博客访问: 32335
  • 博文数量: 12
  • 博客积分: 445
  • 博客等级: 下士
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-06 16:49
文章分类

全部博文(12)

文章存档

2012年(12)

我的朋友

分类: 嵌入式

2012-10-21 23:04:44

13、u-boot引导linux内核
  
(1)启动zImage内核镜像  
    u-boot中的命令bootm只支持启动uImage内核镜像,不支持启动zImage内核镜像,不过我们可以用go命令来运行zImage内核。使用go命令启动内核的话,u-boot不会传递machiine ID给内核,因为go只是执行普通的应用程序,不考虑到传递参数给内核的问题。
    
    修改代码使用go命令来启动zImage内核,在smdk2440.h中修改环境量CONFIG_BOOTCOMMAND,代码如下:
  1. /*#define CONFIG_BOOTFILE    "elinos-lart" */
  2. #define CONFIG_BOOTCOMMAND  "nand read 0x30008000 kernel; go 0x30008000 
    通过u-boot中的nand read命令把zImage内核镜像从NandFlash中读到内存地址0x30008000处,然后跳到该地址运行,也就相当于启动内核了。这里的kernel是前面提到的NandFlash中的一个分区,该分区的起始地址为0x00120000,大小为0x400000。

    在main.c的main_loop函数中,通过以下代码获取环境变量CONFIG_BOOTCOMMAND
  1. s = getenv ("bootcmd");

  2.     debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
     通过getenv得到环境变量CONFIG_BOOTCOMMAND的内容并赋值给字符型指针s,然后在下面通过run_command(s,0)来解析并运行该内容,就像前面解释的那样,把zImage内核镜像从NandFlash中读到内存地址0x30008000处,然后跳到该地址运行,启动内核。

    重新编译u-boot,下载到NandFlash中运行,但是并没有像期待中的那样启动内核,效果如下:

    出现这个问题的原因是因为u-boot的machine id 和 内核的machine id不一致。我使用的zImage内核的machine id为362(宏MACH_TYPE_S3C2440),而现在u-boot的machine id为193(宏MACH_TYPE_SMDK2410),所以需要把u-boot的machine id修改为362,需要修改的是smdk2440.c文件,修改的代码如下:

  1.     /* arch number of SMDK2410-Board */
  2.     gd->bd->bi_arch_number = MACH_TYPE_S3C2440;  //MACH_TYPE_SMDK2410

  3.     /* adress of boot parameters */
  4.     gd->bd->bi_boot_params = 0x30000100;
     
    重新编译u-boot,下载到NandFlash中运行,发现还是出现同样的问题。出现这个问题的原因前面已经提到过了,go命令启动内核的话,u-boot不会传递machiine ID给内核,因为go只是执行普通的应用程序,不考虑到传递参数给内核的问题。

     修改linux内核代码,修改arch/arm/kernel/head.S文件,直接把SMDK2440的参数赋给内核,修改的代码如下:
  1. __HEAD
  2. ENTRY(stext)
  3.     mov r0, #0
  4.     ldr r1, =0x16A
  5.     ldr r2, =0x30000100

  6.     setmode    PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
  7.                         @ and irqs disabled
  8.     mrc    p15, 0, r9, c0, c0        @ get processor id
    
    烧写新的zImage内核到NandFlash中,从NandFlash启动,可以看到u-boot已经可以顺利加载内核了,效果如下:


(2)启动uImage内核镜像
    u-boot可以使用bootm命令来启动uImage内核,这 个方法可以将machine ID传给内核,实现正常启动。  那么uImage又是什么的?它是uboot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。

    64字节的头结构如下:

typedef struct image_header {

uint32_t ih_magic;

uint32_t ih_hcrc;

uint32_t ih_time;

uint32_t ih_size;

uint32_t ih_load;

uint32_t ih_ep;

uint32_t ih_dcrc;

uint8_t ih_os;

uint8_t ih_arch;

uint8_t ih_type;

uint8_t ih_comp;

uint8_t ih_name[IH_NMLEN];

} image_header_t;


     uImage和zImage都是压缩后的内核映像。而uImage是用mkimage工具根据zImage制作而来的。


     mkimage工具是编译u-boot之后,在tools目录下生成的,把它拷到ubuntu的/bin目录下,就可以在任何地方使用它来制作uImage镜像了。mkimage的参数介绍如下:

-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 30008000 ---- image的载入地址(hex),通常为0xX00008000
-e 300080XX---- 内核的入口地址(hex),XX为0x40或者0x00
-n linux-XXX --- image的名字,任意
-d nameXXX ---- 无头信息的image文件名,你的源内核文件
uImageXXX ---- 加了头信息之后的image文件名,任意取

 

    关于-a和-e这两个参数,具体如下:

① -a和-e后面跟的分别是image的载入地址和内核的入口地址,两者可以一样,也可以不一样,依情况而定。

② 当-a后面指定的地址和bootm xxxx后面的地址一样时,-e后面的地址必须要比-a后面的地址多0x40,也就是映像头的大小64个字节。因为当他们地址一样时,uboot是不会搬运映像的。

 当-a后面指定的地址和bootm xxxx后面的地址不一样时,uboot会将bootm xxxx地址处的映像搬运到-a指定的地址处,此时,-e和-a必须要一样,因为映像头并没有搬运过去,载入地址就是内核的入口地址。需要注意的是,因为uboot要重新搬运内核映像,所以要注意bootm xxxx的地址和-a之间的地址不要导致复制时的覆盖。

    

    现在利用mkimage工具来制作uImage,在linux源码的arch/arm/boot/目录下执行下面这个命令,就会在该目录下生成uImage。

    mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n linux-2.6.37.4 -d zImage uImage


    把生成的uImage烧写到NandFlash中。


    修改u-boot代码smdk2440.h中的环境量CONFIG_BOOTCOMMAND,代码如下

  1. /*#define CONFIG_BOOTFILE    "elinos-lart" */
  2. #define CONFIG_BOOTCOMMAND  "nand read 0x30008000 kernel; bootm 0x30008000 

   重新编译u-boot,下载到NandFlash中,从NandFlash启动,可以看到成功加载内核,效果如下:

阅读(1270) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~