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
原java
export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= $(SUBARCH) CROSS_COMPILE ?=
改成:
linux
export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= arm CROSS_COMPILE ?= /usr/local/arm/4.3.2/bin/arm-linux-
其中,ARCH 是指定目標平臺爲 arm,CROSS_COMPILE 是指定交叉編譯器
接下來,要測試一下 linux 的編譯是否能正常經過。
執行:git
$ make s3c2410_defconfig
使用缺省內核配置文件,s3c2410_defconfig 是 SMDK2440 的
缺省配置文件web
$ make
編譯時間較長
編譯經過,在此咱們先沒必要燒寫到開發板驗證它的正確性。app
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")
注:此處第二個參數,寫什麼都不重要,重要的是第一個參數,它決定的了內核使用的機器碼ui
請參考本人的另外一篇文章,且對應機器碼必定要和bootloader中傳遞給內核的機器碼是一致的this
http://my.oschina.net/hanshubo/blog/538823 spa
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, };
注:
一、此處代碼放在
static void __init mini2440_map_io(void)
函數定義的下面
二、分區部分代碼每一個人的狀況都不同,要根據本身的實際狀況進行編寫,原則:NAND FLASH裏寫了什麼內容,
三、且此處分區的定義還和後面提到的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