(1)启动zImage内核镜像
u-boot中的命令bootm只支持启动uImage内核镜像,不支持启动zImage内核镜像,不过我们可以用go命令来运行zImage内核。使用go命令启动内核的话,u-boot不会传递machiine ID给内核,因为go只是执行普通的应用程序,不考虑到传递参数给内核的问题。
修改代码使用go命令来启动zImage内核,在smdk2440.h中修改环境量CONFIG_BOOTCOMMAND,代码如下:
- /*#define CONFIG_BOOTFILE "elinos-lart" */
- #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:
- s = getenv ("bootcmd");
- 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文件,修改的代码如下:
- /* arch number of SMDK2410-Board */
- gd->bd->bi_arch_number = MACH_TYPE_S3C2440; //MACH_TYPE_SMDK2410
- /* adress of boot parameters */
- gd->bd->bi_boot_params = 0x30000100;
重新编译u-boot,下载到NandFlash中运行,发现还是出现同样的问题。出现这个问题的原因前面已经提到过了,用go命令启动内核的话,u-boot不会传递machiine ID给内核,因为go只是执行普通的应用程序,不考虑到传递参数给内核的问题。
修改linux内核代码,修改arch/arm/kernel/head.S文件,直接把SMDK2440的参数赋给内核,修改的代码如下:
- __HEAD
- ENTRY(stext)
- mov r0, #0
- ldr r1, =0x16A
- ldr r2, =0x30000100
- setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
- @ and irqs disabled
- 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,代码如下:
- /*#define CONFIG_BOOTFILE "elinos-lart" */
- #define CONFIG_BOOTCOMMAND "nand read 0x30008000 kernel; bootm 0x30008000
重新编译u-boot,下载到NandFlash中,从NandFlash启动,可以看到成功加载内核,效果如下:
阅读(1270) | 评论(0) | 转发(0) |