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 menuconfig命令进入内核配置界面,进入到“System Type”选项配置菜单,将S3C2440 Machines选项下做如下选择:只选择SMDK2440和SMDK2440 withS3C2440 CPU module两个选项。
Device Drivers --->
<*> I2C support --->
I2C Hardware Bus support --->
选择好“<*> S3C2410 I2C Driver”
此处选择是为支持 I2C 总线
Device Drivers --->
Character devices--->【选择用户自己开的驱动模块】
$ 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
来源:oschina
链接:https://my.oschina.net/u/1028474/blog/539272