移植linux2.6.29内核到mini2440
移植环境:
主机:redhat 5
交叉编译器:arm-linux-gcc-4.3.2
开发板平台:S3C2440(mini2440开发板)
下载Linux内核源代码 :https://www.kernel.org/pub/linux/kernel/
到该目录下下载内核。
修改配置文件
1.修改顶层Makefile文件
直接将Makefile文件里面的 ln193
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
改为:
ARCH ?= arm
CROSS_COMPILE ?=arm-unknown-linux-gnueabi- //我的完整的交叉编译工具名字为 arm-unknown-linux-gnueabi-gcc
2.修改时钟,不修改超级终端中会出现乱码
修改arch/arm/mach-s3c2440/mach-smdk2440.c ln163
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(12000000); //修改为 12000000,默认为 16934400
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
}
3. 修改对nand的分区信息。要让内核知道nand flash的分区信息,设置成跟bootloader一致。
在arch/arm/plat-s3c24xx/common-smdk.c中修改smdk_default_nand_part[],注意这个一定要跟bootloader的一致。在我的板子中修改如下:
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "U-boot", //这里是bootloader所在的分区,可以放置u-boot
.size = 0x00060000, //对应/dev/mtdblock0
.offset = 0,
},
[1] = {
.name = "param", //这里是u-boot的参数区,其实也属于bootloader的
.offset = 0x00060000, //一部分,如果u-boot 比较大,可以把此区域覆盖掉
.size = 0x00020000, //不会影响系统启动,对应/dev/mtdblock1
},
[2] = {
.name = "Kernel",//内核所在的分区,大小为 5M,足够放下大部分自己定制的巨型内核了,比如内核使用了更大的Linux Logo图片对应/dev/mtdblock2等
.offset = 0x00080000,
.size = 0x00500000,
},
[3] = {
.name = "root", //文件系统分区,主要用来存放yaffs2 文件系统内容,对应/dev/mtdblock3
.offset = 0x00580000,
.size = 1024 * 1024 * 1024,
},
};
4 . 修改nand Flash的校验方式,去掉ECC校验
在drivers/mtd/nand/s3c2410.c第669行
将chip->ecc.mode = NAND_ECC_SOFT;
改为 chip->ecc.mode = NAND_ECC_NONE;
注意:这个去掉ECC校验的问题,在内核中明确说明是不建议这样做的,因为这样就等于忽略了对NAND FLASH坏块的检测。而我一开始也是编译的时候就去掉了ECC校验的选项,原以为在编译选项中去掉就可以了,结果一直报这样的错:
end_request: I/O error, dev mtdblock2, sector 0
FAT: unable to read boot sector
VFS: Cannot open root device "mtdblock2" or unknown-block(31,2)
Please append a correct "root=" boot option; here are the available partitions:
1f00 192 mtdblock0 (driver?)
1f01 1856 mtdblock1 (driver?)
1f02 30720 mtdblock2 (driver?)
1f03 32768 mtdblock3 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,2)
后来发现配置中去掉的这个选项在代码中并没有完全去掉,只是去掉了硬件校验的方式,换成了软件校验。只有在代码中给改成NAND_ECC_NONE,才不会校验,但是这样是不提倡的。只有这样最后我的系统才起来.
5 .修改机器码,使之与bootloader的机器码相同,这里使用的是u-boot
linux 内核中定义机器码的位置
arch/arm/tools/mach-types
379行 s3c2440 ARCH_S3C2440 S3C2440 362
U-boot中的相关配置文件include/asm-arm/mach-types.h
375行 #define MACH_TYPE_S3C2440 362
(如一致则无需修改)
6.配置及编译内核
然后用S3C2410的默认配置文件
#cp arch/arm/configs/s3c2410_defconfig .config
#make menuconfig //只需修改下面几项
[*] Enable loadable module support --->
[*] Module unloading
[*] Automatic kernel module loading
选择这两个,剩下的可以去掉
System Type ---->
[*] S3C2410 DMA support
S3C2410 Machines --->
[*] SMDK2410/A9M2410
S3C2440 Machines --->
[*] SMDK2440
[*] SMDK2440 with S3C2440 CPU module
//System Type这部分,只选这些,其他可以全部去掉,
Boot option ----->
修改启动参数为:noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200
可能根据个人板子的设置会不一样,我的是从Nand Flash中加载文件系统,其中mtdblock2是存放我的Linux文件系统的分区。不过,在bootloader可以传递内核参数的情况下这个设置是无效的。
Device Drivers --->
<*> Memory Technology Device (MTD) support --->
[*] MTD partitioning support
<*> NAND Device Support --->
<*> NAND Flash support for S3C2410/S3C2440 SoC
[ ] S3C2410 NAND Hardware ECC //这个要去掉
[*] Network device support --->
[*] Ethernet (10 or 100Mbit) --->
<*> DM9000 support
Kernel Features ->
[*]Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel
这里由于使用了codesourcery的工具链,此工具链支持EABI,,内核编译时也要选上,否则用这个编译器编出来的用户程序无法运行,最典型的错误是Busybox无法运行。
到此为止,基本完成。
下面正式编译
#make zImage
会在arch/arm/boot/下面生成zImage文件,但是此文件不能直接在用uboot启动,需要用mkimage生成uboot可执行的文件。
接着介绍使用mkimage生成镜像文件并下载运行的方法。
首先,用u-boot/tools/mkimage这个工具为你的内核加上u-boot引导所需要的文件头,具体做法如下:
[root@localhost tftpboot]#mkimage -n ‘linux-2.6.29′ -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -d zImage zImage.img
Image Name: linux-2.6.29
Created: Fri Jan 12 17:14:50 2009
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1262504 Bytes = 1232.91 kB = 1.20 MB
Load Address: 0×30008000
Entry Point: 0×30008040
这里生成的zImage文件就可以通过uboot来引导了。
这里解释一下参数的意义:
-A ==> set architecture to ‘arch’
-O ==> set operating system to ‘os’
-T ==> set image type to ‘type’
-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)
其中与内核引导最密切的是-e 30008000,也就是内核的入口地址。其它参数可以参考帮助信息。其它UBOOT格式的内核与原来相比,只是进行(可选)了压缩,并在前面加了一个0x40大小的头。这个头里放了内核的位置(0x30007fc0)和入口地址(0x30008000)和其它信息。
bootm命令执行时,先对头部信息等进行校验,然后把头信息放到一个结构里面。最后根据内核类型调用相应的启动函数。对于Linux而言就是do_bootm_linux,在启动函数里面,有这么一个操作:theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);,这是最关键的一个操作,将内核的入口地址0x30008000赋给了theKernel,在启动函数的最后,使用theKernel (0, bd->bi_arch_number, bd->bi_boot_params);启动内核。
根据传参规范,三个变量分别用r0,r1,r2传给内核,这样就巧妙地利用了函数指针进行了参数传递,实在是精妙!
上面讲完了内核的引导及传参,需要引起注意的就是在使用mkimage命令生成内核时,-e后面的地址要比-a后面的地址偏移0x40,原因很简单,就不再细说了。
之后内核还要移植DM900网卡。
现在内核还不能在开发板上运行,接下来我们还需要制作一个YAFFS的文件系统,这样有了文件系统内核才能在开发板上跑起来~