全部博文(75)
分类: LINUX
2009-06-01 10:17:46
移植linux2.6.29内核到mini2440
移植环境:
主机:CentOS 5.1
交叉编译器:arm-linux-gcc-4.3.2
开发板平台:S3C2440(mini2440开发板)
注意:红色部分仅供参考,我没有做测试,还请谅解。如果有问题欢迎提出,也欢迎交流。
准备工作:
下载Linux内核源代码:
交叉编译工具包:从光盘一般都带,没有到网上找找也有。
解压源码:tar -jxvf linux-2.6.29.4.tar.bz2
安装交叉编译工具:tar -jxvf arm-linux-gcc-4.3.2.tar.bz2 -C /
会将工具安装在/usr/local/arm/4.3.2/中
修改配置文件
1.修改顶层Makefile文件
直接将Makefile文件里面的 ln193
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
改为:
ARCH ?= arm
CROSS_COMPILE ?=arm-linux-
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); //default is 16934400, changed by yangdk
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 = "boot",
.size = SZ_128K + SZ_64K, //192k 0x00300000
.offset = 0,
},
[1]={
.name = "kernel",
.size = SZ_16K * 116, //2M - 192K 0x01e00000
.offset = SZ_16K *12, //192K
},
[2]={
.name = "rootfs",
.offset = SZ_2M,
.size = SZ_2M * 15, //30M
},
[3]={
.name = "User",
.offset = SZ_32M,
.size = SZ_32M,
}
};
另外这个文件还要修改smdk_nand_info如下:
static struct s3c2410_platform_nand smdk_nand_info = {
.tacls = 0, //default is 20
.twrph0 = 30, //default is 60
.twrph1 = 0, //defualt is 20 changed by yangdk
.nr_sets = ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
};
//有的文章介绍说这个文件还要修改但查看友善之臂的内核发现并没有改,因此我也没有修改,最终也没出现问题.
4. 添加DM9000网卡驱动
修改arch/arm/mach-s3c2440/mach-smdk2440.c
在static struct platform_device *smdk2440_devices[] __initdata = {
@@ -154,12 +169,15 @@
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
添加
&s3c_device_dm9000,
&s3c_device_rtc, //增加rtc初始化
修改arch/arm/plat-s3c24xx/devs.c,
#include
#include
后面添加
/***************tekkaman*********************/
/* DM9000 registrations */
#include
#define DM9000_BASE 0x20000300
static struct resource s3c_dm9000_resource[] = {
[0] = {
.start = DM9000_BASE,
.end = DM9000_BASE + 0x03,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DM9000_BASE + 0x04,
.end = DM9000_BASE + 0x04 + 0x7c,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}
};
static struct dm9000_plat_data s3c_device_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
};
struct platform_device s3c_device_dm9000 = {
.name= "dm9000",
.id= 0,
.num_resources= ARRAY_SIZE(s3c_dm9000_resource),
.resource= s3c_dm9000_resource,
.dev= {
.platform_data = &s3c_device_dm9000_platdata,
}
};
EXPORT_SYMBOL(s3c_device_dm9000);
/***************tekkaman*********************/
在linux-2.6.29.4arch/arm/plat-s3c24xx/include/plat/include/devs.h
extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
后面添加:
extern struct platform_device s3c_device_dm9000;
修改drivers/net/dm9000.c
添加37行
#include
#include "dm9000.h"
//**********************tekkaman*************************
#include
#include
#include
#include
#include
#include
#define DM9000_IRQ IRQ_EINT7
//**********************tekkaman*****************************
/* Board/System/Debug information/definition ---------------- */
#define DM9000_PHY 0x40 /* PHY address 0x01 */
int i;
u32 id_val;
1185行后面添加
//******************************tekkaman********************************
unsigned int value;
//config the bwscon for bank 4
value = __raw_readl(S3C2410_BWSCON);
value &= ~(S3C2410_BWSCON_WS4|
S3C2410_BWSCON_ST4|
S3C2410_BWSCON_DW4_32);
value |= (S3C2410_BWSCON_ST4|
S3C2410_BWSCON_DW4_16);
__raw_writel(value, S3C2410_BWSCON);
//config the bankcon4
value = 0;
value = (S3C2410_BANKCON_Tacs4|
S3C2410_BANKCON_Tcos4|
S3C2410_BANKCON_Tacc14|
S3C2410_BANKCON_Tcoh4|
S3C2410_BANKCON_Tcah4|
S3C2410_BANKCON_Tacp6|
S3C2410_BANKCON_PMCnorm);
__raw_writel(value,S3C2410_BANKCON4);
//config the irq pin (for mini2440)
set_irq_type(DM9000_IRQ,IRQ_TYPE_LEVEL_HIGH);
s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_EINT7);
s3c2410_gpio_pullup(S3C2410_GPF7, 0);
//******************************tekkaman********************************
5.配置及编译内核
然后用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可执行的文件。
6. 接着介绍使用mkimage生成镜像文件并下载运行的方法。
首先,用u-boot/tools/mkimage这个工具为你的内核加上u-boot引导所需要的文件头,具体做法如下:
[root@localhost tftpboot]#mkimage -n ‘linux-2.6.29.4′ -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -d zImage zImage.img
Image Name: linux-2.6.29.4
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,原因很简单,就不再细说了。
7.修改nand Flash的校验方式,去掉ECC校验。(可选,我用的是NFS没有用到FLASH)
在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,才不会校验,但是这样是不提倡的。可是这有这样最后我的系统才起来,阿弥陀佛!
8. 内核增加yaffs2支持(可选)
到网上下载ysffs2源代码,解压之后进行如下修改:
./patch-ker.sh c /2440/linux-2.6.29
上面命令完成下面三件事情
(1)修改内核fs/Kconfig
增加一行:source "fs/yaffs2/Kconfig"
(2)修改内核fs/Kconfig
增加一行ojb-$(CONFIG_YAFFS_FS) +=yaffs2/
(3)在内核fs/目录下创建yaffs2目录
将yaffs2源码目录下面的Makefile.kernel文件复制为内核fs/yaffs2/Makefie;
将yaffs2 源码目录的Kconfig文件复制到内核fs/yaffs2目录下;
将yaffs2源码目录下的*.c *.h文件复制到内核fs/yaffs2目录下.
在内核根目录下执行:
#make menuconfig 配置yaffs2文件支持
File systems --->
Miscellaneous filesystems --->
<*>YAFFS2 file system support
参考:http://blog.chinaunix.net/u1/34474/showart.php?id=1316396