1.1 获取Linux内核源代码
有很多方式可以获取Linux内核源代码,如果你的linux平台可以上互联网,可以直接在命令行输入以下命令获取到Linux-2.6.32.2:
#wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.2.tar.gz
当然你也可以先在Windows系统下使用迅雷等工具下载完,再复制到linux中。
1.2 解压内核源代码
假定我们刚才把内核源代码下载到了/root/mini2440目录,执行以下解压命
令:
#cd /opt/FriendlyARM/mini2440
#tar xvzf linux-2.6.32.2.tar.gz
1.3 指定交叉编译变量
我们移植目的是让Linux-2.6.32.2可以在mini2440上运行。
首先,我们要使得Linux-2.6.32.2的缺省目标平台成为ARM的平台。
修改总目录下的Makefile
原
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
改为
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
其中,ARCH是指定目标平台为arm,CROSS_COMPILE是指定交叉编译器,这里指定的是系统默认的交叉编译器,如要使用其它的,则要把编译器的全路径在这里写出。
接下来,要测试一下linux的编译是否能正常通过。
执行:
#make s3c2410_defconfig ;使用缺省内核配置文件,s3c2410_defconfig是SMDK2440的缺省配置文件,我的s3c2410_defconfig文件位于/arch/arm/configs/s3c2410_defconfig
#make ;编译时间较长
编译通过,在此我们先不必烧写到开发板验证它的正确性。
1.4 克隆建立自己的目标平台
1.4.1关于机器码
以上编译是用的Linux内核本身支持的目标平台配置,它对应于SMDK2440。现在我们要参考SMDK2440加入自已的开发板平台,我们使用的是mini2440,因此取名为MINI2440。需要说明的是,Linux-2.6.32.2本身已经包含了mini2440的支持,这样就出现了重名。那怎么办呢?在此我们依然使用MINI2440这个名称,只不过在后面的移植步骤中,把原始内核自带的mini2440代码部分直接删除就可以了,以免和我们自己移植的混淆了。首先,很关键的一点,内核在启动时,是通过bootloader传入的机器码(MACH_TYPE)确定应启动哪种目标平台的,友善之臂已经为mini2440申请了自己的机器码为1999,它位于linux-2.6.32.2/arch/arm/tools/mach_types文件中.
如果内核的机器码和bootloader传入的不匹配,就会经常出现下面的错误:
Uncompressing Linux.................................................................................................................................. done, booting
the kernel.
运行到这不就停住了
提示:在U-boot/include/asm-arm/mach-types.h中可以看到mini2440的机器码定义
接下来,我们注意到linux-2.6.32.2/arch/arm/mach-s3c2440目录下有个
mach-mini2440.c文件,它其实就是国外爱好者为mini2440移植添加的主要内容了,但我们不用它,把它直接删除。将linux-2.6.32.2/arch/arm/mach-s3c2440/目录下的mach-smdk2440.c复制一份。命名为mach-mini2440.c,
找到MACHINE_START(S3C2440, "SMDK2440"),修改为
MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")。
提示:开发板运行后,在命令行终端输入:cat /proc/cpuinfo 可以看到我们添加的开发板信息
1.4.2 修改时钟源频率
现在再来修改系统时钟源,在mach-mini2440.c(就是我们刚刚通过复制
mach-smdk2440.c得到的)的第160行static void __init smdk2440_map_io(void)函数中,把其中的16934400(代表原SMDK2440目标板上的晶振是16.9344MHz)改为mini2440开发板上实际使用的12,000,000(代表mini2440开发板上的晶振12MHz,元器件标号为X2)
1.4.3 从SMDK2440到MINI2440
因为我们要制作自己的mini2440平台体系,因此把mach-mini2440.c中所有的
smdk2440字样改为mini2440,可以使用批处理命令修改,在vim的命令模式下输入:
%s/smdk2440/mini2440/g
上面这句的意思是:把所有和“smdk2440”匹配的字符串全部替换为“mini2440”,前面的“%s“代表字符串匹配,最后的“g”代表global,是全局的意思,
除此之外,还有一个地方需要改动,在mini2440_machine_init(void)函数中,把
smdk_machine_init()函数调用注释掉,因为我们后面会编写自己的初始化函数,不需要调用smdk2440原来的.
1.4.4 编译测试
在Linux源代码根目录下执行
#make mini2440_defconfig ;使用Linux官方自带的mini2440配置
#make zImage ;编译内核,时间较长,最后会生成zImage
我的s3c2410_defconfig文件位于/arch/arm/configs/mini2440_defconfig
重新编译并把生成的内核文件zImage(位于arch/arm/boot目录)下到板子中,可以看到内核已经可以正常启动了,但此时大部分硬件驱动还没加,并且也没有文件系统,因此还无法登陆。
注意:
(1)如果你先前已经编译过内核了,请先清理一下,不然会提示编译的文件过时了。
(2)注意在先前关于机器码一项时修改的MACHINE_START(S3C2440, "SMDK2440"),修改为
MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")。
这里的MINI2440必须要大写,我自己的理解是跟机器码里面的类型一致。
1.5 关于内核配置菜单中的mini2440选项
在开始移植其他驱动之前,我们再了解一些看起来比较“神秘”的常识,那就是运行make menuconfig时,内核配置菜单中的mini2440选项是如何出现的。
在命令行执行:
#make menuconfig ;前面已经执行了make mini2440_defconfig加载了缺省配置,因此这里可以直接执行该命令
按上下键移动到System Type,按回车进入该子菜单,再找到S3C2440 Machines,按回车进入该子菜单
在此就可以看到Linux天生内核对mini2440开发板的支持选项了,那么它们是从哪里来的呢?
打开Linux-2.6.32.2/arch/arm/mach-s3c2440/Kconfig文件可以找到相关信息。
现在明白了吧,“MINI2440 development board”正是在这个Kconfig文件中定义说明的,
当然你可以根据自己的喜好改为其他显示信息。
这里的显示信息只是在内核配置菜单中出现的,要让选择的配置实际起效,还需要根据此配置在Makefile中添加相应的代码文件,请看该目录下的Makefile。
这样,配置文件就跟实际的代码文件通过配置定义联系在一起了,这里的配置定义是“CONFIG_MACH_MINI2440”,内核中还有很多类似的配置定义,并且有的配置定义还存在依赖关系,我们在此就不对它们详细说明了,随着对内核代码结构的不断熟悉,你就会逐渐学会分析和查找你所需要的各种配置和定义等。
1.6 移植Nand驱动并更改分区信息
1.6.1 Linux-2.6.32.2内核所支持的Nand Flash类型
Linux2.6.32.2已经自带了大部分Nand Flash驱动,在
linux-2.6.32.2/drivers/mtd/nand/nand_ids.c文件中,定义了所支持的各种Nand Flash类型。
1.6.2 修改Nand Flash分区表
但是系统默认的分区不是我们所需的,所以要自已修改,除此之外,还有Nand Flash的结构信息需要增加填写,以便能够适合系统自带的Nand Flash驱动接口,这可以参考SMDK2440中关于Nand Flash设备注册的一些信息。
打开/arch/arm/plat-s3c24xx/common-smdk.c,可以看到这样一个结构体:
注意这里是参考这个文件夹的内容,改动还是在mach-mini2440.c
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "Boot Agent",
.size = SZ_16K,
.offset = 0,
},
[1] = {
.name = "S3C2410 flash partition 1",
.offset = 0,
.size = SZ_2M,
},
[2] = {
.name = "S3C2410 flash partition 2",
.offset = SZ_4M,
.size = SZ_4M,
},
[3] = {
.name = "S3C2410 flash partition 3",
.offset = SZ_8M,
.size = SZ_2M,
},
[4] = {
.name = "S3C2410 flash partition 4",
.offset = SZ_1M * 10,
.size = SZ_4M,
},
[5] = {
.name = "S3C2410 flash partition 5",
.offset = SZ_1M * 14,
.size = SZ_1M * 10,
},
[6] = {
.name = "S3C2410 flash partition 6",
.offset = SZ_1M * 24,
.size = SZ_1M * 24,
},
[7] = {
.name = "S3C2410 flash partition 7",
.offset = SZ_1M * 48,
.size = SZ_16M,
}
};
这其实就是Nand Flash的分区表,在Linux-2.6.32.2中,nand驱动是被注册为平台设备的,这同样可在/arch/arm/plat-24xx/common-smdk.c文件中看出,如下:
static struct s3c2410_platform_nand smdk_nand_info = {
.tacls = 20,
.twrph0 = 60,
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
};
/* devices we initialise */
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
};
参考以上结构信息,我们也在自己的mach-mini2440.c中照此添加实现,同时需要参考友善之臂原厂内核中的Nand分区表
因此,在mach-mini2440.c中加入以下代码:
首先添加几个头文件:
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <plat/nand.h>
然后加入以下代码:static struct mtd_partition mini2440_default_nand_part[] = {
[0] = {
.name = "supervivi", //这里是bootloader所在的分区,可以放置u-boot, supervivi等内容,对应/dev/mtdblock0
.size = 0x00040000,
.offset = 0,
},
[1] = {
.name = "param", //这里是supervivi的参数区,其实也属于bootloader的一部分,如果u-boot比较大,可以把此区域覆盖掉,不会影响系统启动,对应/dev/mtdblock1
.offset = 0x00040000,
.size = 0x00020000,
},
[2] = {
.name = "Kernel", //内核所在的分区,大小为5M,足够放下大部分自己定制的巨型内核了,比如内核使用了更大的Linux Logo图片等,对应/dev/mtdblock2
.offset = 0x00060000,
.size = 0x00500000,
},
[3] = {
.name = "root", //文件系统分区,友善之臂主要用来存放yaffs2文件系统内容,对应/dev/mtdblock3
.offset = 0x00560000,
.size = 1024 * 1024 * 1024, //
},
[4] = {
.name = "nand", //此区域代表了整片的nand flash,主要是预留使用,比如以后可以通过应用程序访问读取/dev/mtdblock4就能实现备份整片nand flash了。
.offset = 0x00000000,
.size = 1024 * 1024 * 1024, //
}
};
//这里是开发板的nand flash设置表,因为板子上只有一片,因此也就只有一个表
static struct s3c2410_nand_set mini2440_nand_sets[] = {
[0] = {
.name = "NAND",
.nr_chips = 1,
.nr_partitions = ARRAY_SIZE(mini2440_default_nand_part),
.partitions = mini2440_default_nand_part,
},
};
//这里是nand flash本身的一些特性,一般需要对照datasheet填写,大部分情况下按照以下参数填写即可
static struct s3c2410_platform_nand mini2440_nand_info = {
.tacls = 20,
.twrph0 = 60,
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(mini2440_nand_sets),
.sets = mini2440_nand_sets,
.ignore_unset_ecc = 1,
};
//除此之外,还需要把nand flash设备注册到系统中,
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_nand, //把nand flash设备添加到开发板的设备列表结构
};
找到下边程序添加一条语句:
static void __init mini2440_machine_init(void){
s3c24xx_fb_set_platdata(&mini2440_fb_info);
s3c_i2c0_set_platdata(NULL);
s3c_device_nand.dev.platform_data = &mini2440_nand_info; //添加
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
}
注意:mini2440_default_nand_part、mini2440_nand_sets、mini2440_nand_info三个结构体顺序不能错。另外,这三段最好放在顶端头文件的下边,之前测试过放在下边有编译出错的情况不知时候与位置有关。。。
到这里就完成了NandFlash的驱动的移植,可以下载到开发板运行看看启动的信息了。
1.6.3 从启动信息中查看分区表
注意:虽然说开始信息里面uncorrectable error :这样的错误,但是还是可以继续成功,这里不要在意这些error。
至此,就完成了nand flash驱动的移植,此时在内核根目录执行“make zImage”,把生成的zImage烧写到开发板,可以在启动时看到如图红色信息,它们正是我们刚刚添加的nand flash分区信息,以及开发板本身nand flash的一些信息,这里可以看到是256M的nand flash。
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c24xx-nand s3c2440-nand: Tacls=3, 29ns Twrph0=7 69ns, Twrph1=3 29ns
s3c24xx-nand s3c2440-nand: NAND soft ECC
NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bi
t)
Scanning device for bad blocks
Bad eraseblock 256 at 0x000002000000
Bad eraseblock 257 at 0x000002020000
Bad eraseblock 317 at 0x0000027a0000
Bad eraseblock 1261 at 0x000009da0000
Creating 5 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x000000000000-0x000000040000 : "supervivi"
uncorrectable error :
0x000000040000-0x000000060000 : "param"
ftl_cs: FTL header not found.
0x000000060000-0x000000560000 : "Kernel"
0x000000560000-0x000040560000 : "root"
mtd: partition "root" extends beyond the end of device "NAND 256MiB 3,3V 8-bit"
-- size truncated to 0xfaa0000
ftl_cs: FTL header not found.
0x000000000000-0x000040000000 : "nand"
mtd: partition "nand" extends beyond the end of device "NAND 256MiB 3,3V 8-bit"
-- size truncated to 0x10000000
uncorrectable error :
dm9000 Ethernet Driver, V1.31
dm9000 dm9000: eth%d: Invalid ethernet MAC address. Please set using ifconfig
eth0: dm9000e at c486e300,c4872304 IRQ 51 MAC: 00:00:00:00:00:00 (chip)
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
usbcore: registered new interface driver libusual
s3c2440-usbgadget s3c2440-usbgadget: S3C2440: increasing FIFO to 128 bytes
mice: PS/2 mouse device common for all mice
S3C24XX RTC, (c) 2004,2006 Simtec Electronics
s3c2410-rtc s3c2410-rtc: rtc disabled, re-enabling
s3c2410-rtc s3c2410-rtc: rtc core: registered s3c as rtc0
i2c /dev entries driver
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
cpuidle: using governor ladder
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
s3c-sdi s3c2440-sdi: powered down.
s3c-sdi s3c2440-sdi: mmc0 - using pio, sw SDIO IRQ
usbcore: registered new interface driver hiddev
usbcore: registered new interface driver usbhid
1.7 移植yaffs2
1.7.1 获取yaffs2源代码
现在大部分开发板都可以支持yaffs2文件系统,它是专门针对嵌入式设备,特别是使用nand flash作为存储器的嵌入式设备而创建的一种文件系统,早先的yaffs仅支持小页(512byte/page)的nand flash,现在的开发板大都配备了更大容量的nand flash,它们一般是大页模式的(2K/page),使用yaffs2就可以支持大页的nand flash,下面是yaffs2的移植详细步骤。
在
可以下载到最新的yaffs2源代码,需要使用git工具,在命令行输入:
#git clone git://www.aleph1.co.uk/yaffs2
稍等片刻,就可以下载到最新的yaffs2的源代码目录。
1.7.2 为内核打上yaffs2补丁
这可以通过yaffs2目录下的脚本文件patch-ker.sh来给内核打补丁,用法如下:
[root@localhost yaffs2]# ./patch-ker.sh c /root/linux-test/linux-2.6.32.2
usage: ./patch-ker.sh c/l m/s kernelpath
if c/l is c, then copy. If l then link
if m/s is m, then use multi version code. If s then use single version code //注意这一句话,根据自己需要选用第二个参数是m还是s
[root@localhost yaffs2]# ./patch-ker.sh c s /root/linux-test/linux-2.6.32.2
*** Warning ***
You have chosen to use the single kernel variant of the yaffs VFS glue code
that only works with the latest Linux kernel tree. If you are using an older
version of Linux then you probably wanted to use the multi-version variant by
re-running the patch-ker.sh script using m as a the second argument.
ie ./patch-ker.sh c m /root/linux-test/linux-2.6.32.2
Updating /root/linux-test/linux-2.6.32.2/fs/Kconfig
Updating /root/linux-test/linux-2.6.32.2/fs/Makefile
[root@localhost yaffs2]#
注意第二个参数m/s,如果不指定,有时会执行失败。
上述命令完成下面三件事://有助于理解
<1>修改内核文件/fs/Kconfig,增加下面两行(在177行附近):
if MISC_FILESYSTEMS
source "fs/adfs/Kconfig"
source "fs/affs/Kconfig"
source "fs/ecryptfs/Kconfig"
source "fs/hfs/Kconfig"
source "fs/hfsplus/Kconfig"
source "fs/befs/Kconfig"
source "fs/bfs/Kconfig"
source "fs/efs/Kconfig"
source "fs/yaffs2/Kconfig"
source "fs/jffs2/Kconfig"
# UBIFS File system configuration
<2>修改内核文件/fs/Makefile,增加下面两行(在129行附近):
obj-$(CONFIG_GFS2_FS) += gfs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
obj-$(CONFIG_YAFFS_FS) += yaffs2/
<3>在内核文件的fs目录下创建yaffs2子目录,然后复制如下文件:
将yaffs2源码目录下的Makefile.kernel文件复制为内核fs/yaffs2/Makefile文件。
将yaffs2源码目录下的Kconfig文件复制为内核fs/yaffs2/目录下。
将yaffs2源码目录下的*.c、*.h文件(不包括子目录下的文件)复制为内核fs/yaffs2/目录下。
1.7.3 配置和编译带YAFFS2支持的内核
在 Linux 内核源代码根目录运行:make menuconfig,移动上下按键找到 File Systems,按回车进入该子菜单再找到"Miscellaneous filesystems"菜单项,按回车进入该子菜单,找到"YAFFS2 file system support",并按空格选中它,这样我们就在内核中添加了 yaffs2 文件系统的支持,按"Exit"退出内核配置。
在命令行执行:
#make zImage
最后会生成linux-2.6.32.2/arch/arm/boot/zImage,使用supervivi的“k“功能把它烧写到nand flash,按“b“启动系统,这时,如果nand flash已经存在文件系统(可以使用supervivi的“y“功能烧写友善之臂提供的现成的yaffs2文件系统映像root_qtopia-128M.img用以测试),如果可以进入文件系统了,这说明yaffs2已经移植成功。