1. 移植准备
1.1 获取Linux内核源代码(linux-2.6.32.tar.gz)
$ wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.gz
1.2 解压内核源代码
$ tar xvzf linux-2.6.32.tar.gz
得linux-2.6.32源代码目录
1.3 指定交叉编译变量
修改总目录下的 Makefile
原
export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= $(SUBARCH) CROSS_COMPILE ?=
改为:
export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= arm CROSS_COMPILE ?= /usr/local/arm/4.3.2/bin/arm-linux-
其中,ARCH 是指定目标平台为 arm,CROSS_COMPILE 是指定交叉编译器
接下来,要测试一下 linux 的编译是否能正常通过。
执行:
$ make s3c2410_defconfig
使用缺省内核配置文件,s3c2410_defconfig 是 SMDK2440 的
缺省配置文件
$ make
编译时间较长
编译通过,在此我们先不必烧写到开发板验证它的正确性。
2. 开始移植
2.1 克隆建立自己的目标平台
删除 arch/arm/mach-s3c2440/mach-mini2440.c
重新复制 arch/arm/mach-s3c2440/mach-smdk2440.c 为arch/arm/mach-s3c2440/mach-mini2440.c
修改:
MACHINE_START(S3C2440, "SMDK2440")
为:
MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")
注:此处第二个参数,写什么都不重要,重要的是第一个参数,它决定的了内核使用的机器码
请参考本人的另一篇文章,且对应机器码一定要和bootloader中传递给内核的机器码是一致的
http://my.oschina.net/hanshubo/blog/538823
2.2 修改时钟源频率
static void __init smdk2440_map_io(void)
16934400 ---> 12000000
2.3 从 SMDK2440 到 MINI2440
在mach-mini2440.c中替换所有的smdk2440为mini2440 (%s/smdk2440/mini2440/g)
并注释掉mini2440_machine_init(void)函数中的 smdk_machine_init()
2.4 编译测试
$ make mini2440_defconfig $ make zImage
3. 移植 Nand 驱动并更改分区信息
Linux2.6.32 已 经 自 带 了 大 部 分 Nand Flash 驱 动 , 在linux-2.6.32/drivers/mtd/nand/nand_ids.c 文件中,定义了所支持的各种 Nand Flash 类型。
在 mach-mini2440.c 中加入以下代码:
static struct mtd_partition mini2440_default_nand_part[] = { [0] = { .name = "vboot", .size = 0x00060000, .offset = 0, }, [1] = { .name = "Kernel", .size = 0x00500000, //5M .offset = 0x00060000, //0x00040000 + 0x00020000 }, [2] = { .name = "root", .size = 0xfaa0000, .offset = 0x00560000, }, [3] = { .name = "nand", .size = 256 * 1024 * 1024, .offset = 0x00000000, } }; 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, }, }; 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, };
注:
1、此处代码放在
static void __init mini2440_map_io(void)
函数定义的下面
2、分区部分代码每个人的情况都不一样,要根据自己的实际情况进行编写,原则:NAND FLASH里写了什么内容,
3、且此处分区的定义还和后面提到的linux command line中的 root=/dev/mtdblockX 相对应的,本人此处root的坐标是2,所以root=/dev/mtdblock2
除此之外,还需要把 nand flash 设备注册到系统中,同时加入RTC
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, // new added &s3c_device_rtc, //new added };
此时执行 make zImage 会报错如下:
CHK include/linux/version.h make[1]: `include/asm-arm/mach-types.h' is up to date. CHK include/linux/utsrelease.h SYMLINK include/asm -> include/asm-arm CALL scripts/checksyscalls.sh CHK include/linux/compile.h CC arch/arm/mach-s3c2440/mach-mini2440.o arch/arm/mach-s3c2440/mach-mini2440.c:49: error: array type has incomplete element type arch/arm/mach-s3c2440/mach-mini2440.c:50: error: array index in non-array initializer arch/arm/mach-s3c2440/mach-mini2440.c:50: error: (near initialization for 'mini2440_default_nand_part') arch/arm/mach-s3c2440/mach-mini2440.c:51: error: field name not in record or union initializer arch/arm/mach-s3c2440/mach-mini2440.c:51: error: (near initialization for 'mini2440_default_nand_part') arch/arm/mach-s3c2440/mach-mini2440.c:52: error: field name not in record or union initializer
这是因为缺少以下头文件:
#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>
加入重新编译,生成arch/arm/boot/zImage,下载至板子,重新启动,结果产生kernel panic如下:
S3C24XX NAND Driver, (c) 2004 Simtec Electronics s3c24xx-nand s3c2440-nand: Tacls=4, 39ns Twrph0=8 79ns, Twrph1=8 79ns Unable to handle kernel NULL pointer dereference at virtual address 00000018 pgd = c0004000 [00000018] *pgd=00000000 Internal error: Oops: 5 [#1] last sysfs file: Modules linked in: CPU: 0 Not tainted (2.6.32 #2) PC is at s3c24xx_nand_probe+0x2d8/0x514 LR is at s3c24xx_nand_probe+0x1a4/0x514 pc : [<c01d9d44>] lr : [<c01d9c10>] psr: 60000013 sp : c3823f08 ip : 00000000 fp : 00000001 r10: 00000000 r9 : 00000000 r8 : 00000000 r7 : c03cf388 r6 : 00000000 r5 : c39b68c0 r4 : c3895800 r3 : 00000001 r2 : c3895988 r1 : c4c00000 r0 : 00000002 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: c000717f Table: 30004000 DAC: 00000017 Process swapper (pid: 1, stack limit = 0xc3822270) Stack: (0xc3823f08 to 0xc3824000)
上面第二行的内容说明我们更改的nand驱动参数根本就没有生效,分析Linux内核中的nand flash驱动drivers/mtd/nand/s3c2410.c文件中的相应函数,
其中的static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)函数发现:
struct s3c2410_platform_nand *plat = info->platform; int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; ………… info->clk_rate = clkrate; clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max); twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8); twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8); } else { /* default timings */ tacls = tacls_max; twrph0 = 8; twrph1 = 8; } if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { dev_err(info->device, "cannot get suitable timings\n"); return -EINVAL; } dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
由以上内容可以看出,你的内核并没有使用你的mini2440_nand_info结构体中的配置,而是使用了它的默认配给,即
} else { /* default timings */ tacls = tacls_max; twrph0 = 8; twrph1 = 8; }
中的配置信息。这点和你的内核输出s3c24xx-nand s3c2440-nand: Tacls=4, 39ns Twrph0=8 79ns, Twrph1=8 79ns完全符合。
解决方法:
只需在mach-mini2440.c的初始化函数mini2440_machine_init(void)里加入
s3c_device_nand.dev.platform_data=&mini2440_nand_info;
static void __init mini2440_machine_init(void) { s3c24xx_fb_set_platdata(&mini2440_fb_info); s3c_i2c0_set_platdata(NULL); platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); s3c_device_nand.dev.platform_data = &mini2440_nand_info; //smdk_machine_init(); }
即可。
重新编译、下载运行,可以看到nand分区信息:
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: 0xf1 (Samsung NAND 128MiB 3,3V 8-bit) Scanning device for bad blocks Creating 5 MTD partitions on "NAND 128MiB 3,3V 8-bit": 0x000000000000-0x000000040000 : "supervivi" uncorrectable error : 0x000000040000-0x000000060000 : "param" uncorrectable error : 0x000000060000-0x000000560000 : "Kernel" uncorrectable error : 0x000000560000-0x000008000000 : "root" ftl_cs: FTL header not found. 0x000000000000-0x000008000000 : "nand"
至此,就完成了 nand flash 驱动的移植
4. 移植 yaffs2
A、下载yaffs2源代码
我是直接进入http://www.yaffs.net下载
下载地址:
http://www.aleph1.co.uk/gitweb?p=yaffs2.git;a=summary
选择最新版本,点击snapshot下载。
进入解压后源代码目录yaffs2-d43e901:
cd yaffs2-d43e901
4.2为内核打上 yaffs2 补丁
./patch-ker.sh c m ../../kernel/linux-2.6.32
报以下信息
Updating ../../kernel/linux-2.6.32/fs/Kconfig Updating ../../kernel/linux-2.6.32/fs/Makefile
此时,inux-2.6.32/fs 目录,可以看到已经多了一个 yaffs2 目录
4.3配置和编译带 YAFFS2 支持的内核
在 Linux 内核源代码根目录运行:make menuconfig
选中
Kernel Features ---> [*] Use the ARM EABI to compile the kernel [*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL) (NEW)
File systems ---> [*] Miscellaneous filesystems ---> <*> yaffs2 file system support -*- 512 byte / page devices
保存并退出。
然后重新编译内核
make zImage
并把zImage烧写至板子
同时也把FriendlyARM随机带的root_qtopia-128M.img烧写至root分区,然后测试,串口log如下:
注:此处本人是自己制作的yaffs2文件系统image
以下为原文作者,遇到的问题:
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 256 mtdblock0 (driver?) 1f01 128 mtdblock1 (driver?) 1f02 5120 mtdblock2 (driver?) 1f03 125568 mtdblock3 (driver?) 1f04 131072 mtdblock4 (driver?) Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,2) [<c00319f8>] (unwind_backtrace+0x0/0xdc) from [<c02d9044>] (panic+0x40/0x118) [<c02d9044>] (panic+0x40/0x118) from [<c0009000>] (mount_block_root+0x1d0/0x210) [<c0009000>] (mount_block_root+0x1d0/0x210) from [<c0009298>] (prepare_namespace+0x164/0x1bc) [<c0009298>] (prepare_namespace+0x164/0x1bc) from [<c00085bc>] (kernel_init+0xd8/0x10c) [<c00085bc>] (kernel_init+0xd8/0x10c) from [<c002ce14>] (kernel_thread_exit+0x0/0x8)
重点看第二行内容,这个说明根据bootloader传过来的linux_cmd_line,不能找到真正的root分区。由于上文对nand flash分区如下:
0x000000000000-0x000000040000 : "supervivi" 0x000000040000-0x000000060000 : "param" 0x000000060000-0x000000560000 : "Kernel" 0x000000560000-0x000040560000 : "root" 0x000000000000-0x000040000000 : "nand"
说明root内容存放在/dev/mtdblock3上,因此,先检查bootloader设置。
按q进入vivi command line
Supervivi> param show Number of parameters: 9 name : hex integer ------------------------------------------------------------------------------------------------------------- mach_type : 000007cf 1999 media_type : 00000003 3 boot_mem_base : 30000000 805306368 baudrate : 0001c200 115200 xmodem : 00000001 1 xmodem_one_nak : 00000000 0 xmodem_initial_timeout : 000493e0 300000 xmodem_timeout : 000f4240 1000000 boot_delay : 01000000 16777216 Linux command line: noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0
linux_cmd_line设置不对,修改之
Supervivi> param set linux_cmd_line "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0" Change linux command line to "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0" Supervivi> param save Found block size = 0x00020000 Erasing... ... done Writing... ... done Written 49152 bytes Saved vivi private data Supervivi> menu
重新启动,输出log如下:
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 S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled Advanced Linux Sound Architecture Driver Version 1.0.21. No device for DAI UDA134X No device for DAI s3c24xx-i2s ALSA device list: No soundcards found. TCP cubic registered NET: Registered protocol family 17 s3c2410-rtc s3c2410-rtc: hctosys: invalid date/time yaffs: dev is 32505859 name is "mtdblock3" rw yaffs: passed flags "" VFS: Mounted root (yaffs filesystem) on device 31:3. Freeing init memory: 140K hwclock: settimeofday() failed: Invalid argument [01/Jan/1970:00:00:12 +0000] boa: server version Boa/0.94.13 [01/Jan/1970:00:00:12 +0000] boa: server built Mar 26 2009 at 15:28:42. [01/Jan/1970:00:00:12 +0000] boa: starting server pid=933, port 80 open device leds: No such file or directory Try to bring eth0 interface up......ifconfig: SIOCGIFFLAGS: No such device ifconfig: SIOCSIFHWADDR: No such device ifconfig: SIOCSIFADDR: No such device route: SIOCADDRT: Network is unreachable Done Please press Enter to activate this console.
至此说明kernel已经可以成功mount rootfs,linux kernel移植成功!
注:本人用的交叉编译器是:arm-linux-gcc 4.3.2