到内核官网下载最新版本的内核
https://www.kernel.org/
目前,下载的内核版本是 linux-3.4.2
交叉编译版本:arm-linux-4.3.2
PC机系统:ubuntu 12.04 LTS
开发板:TQ2440
1.下载完内核后,进行解压
tar xvfj linux-3.4.2.tar.bz2 -C ./
进入内核目录:cd linux-3.4.2
查找内核的默认配置文件:find -iname "*defconfig"
内核的默认配置文件,都是在某个架构的目录下
./arch/arm/configs/s3c2410_defconfig
跟 2440 有关的两个配置文件:mini2440_defconfig 和 s3c2410_defconfig
因为之前的 u-boot 移植是使用 2410 作为模板,因此,内核配置选用 s3c2410_defconfig
如果使用 mini2440_defconfig ,则需要重新在 u-boot 里设置机器 ID
修改内核顶层目录的 Makefile ,把编译器改为 arm-linux-gcc
在内核目录下,执行 make s3c2410_defconfig,执行完后,会生成 .config
执行内核顶层目录下,执行 make uImage 编译内核
编译成功后,在 arch/arm/boot/目录下会生成 uImage 镜像,
复制到 /opt/work/other_board/kernel_projects/images 并重新命名为 uImage_new
使用以下命令下载和启动内核:
nfs 32000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/uImage_new && bootm 32000000
内核启动后,出现乱码,寻找乱码原因(此时内核已经成功运行起来)
通过查看 u-boot 源码,得知 u-boot 传入的 machine-id 是 #define MACH_TYPE_SMDK2410 193
另外,我们可以从 u-boot 设置启动参数,传入 machine-id 给内核 :set machid 193
随便设置一个 machid ,重新启动,会提示 machid 不匹配的错误,并且列出内核支持的 mach-id
查看内核源码,在 mach-smdk2440.h文件的最后几行,有这样一个宏:
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <[email protected]> */
.atag_offset = 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
.restart = s3c244x_restart,
MACHINE_END
这个宏展开后,会有 MACH_TYPE_S3C2440 这样一个宏,这个宏在 arch\arm\tools\mach-types 中定义
这个宏会被转换为一个头文件 include/asm-arm/mach-types.h(此文件自动生成) 供其他文件包含,
在内核里面,查找 mach-types.h ,发现这个文件里,又包含了 #include <generated/mach-types.h>
打开 ./include/generated/mach-types.h 文件,里面包含了该内核支持的单板id
在 u-boot 里,分别设置机器 ID 为 16A(SMDK2440) 和 7CF(MINI2440)
启动内核,均不能正确输出信息,出现乱码。
查看源码,在 mach-s3c24xx文件里,时钟初始化为 s3c24xx_init_clocks(16934400);
在 mach-mini2440文件里,时钟初始化为 s3c24xx_init_clocks(12000000);
因此,我们选择 machid 为 7CF ,因为 mini2440的时钟设置为 12MHz ,跟开发板一样
在 u-boot 命令行中 ,执行 print 打印出参数,发现没有设置波特率
设置波特率:set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 ,并保存
重新启动内核,信息已经正确输出。
查看信息,发现内核无法挂载根文件系统。内核打印信息,其中有一段内容:
0x000000000000-0x000000004000 : "Boot Agent"
mtd: partition "Boot Agent" doesn't end on an erase block -- force read-only
0x000000000000-0x000000200000 : "S3C2410 flash partition 1"
0x000000400000-0x000000800000 : "S3C2410 flash partition 2"
0x000000800000-0x000000a00000 : "S3C2410 flash partition 3"
0x000000a00000-0x000000e00000 : "S3C2410 flash partition 4"
0x000000e00000-0x000001800000 : "S3C2410 flash partition 5"
0x000001800000-0x000003000000 : "S3C2410 flash partition 6"
0x000003000000-0x000010000000 : "S3C2410 flash partition 7"
修改内核分区信息,使其与u-boot分区一致(可以不一致,u-boot分区跟内核分区无关联)
在内核里,搜索 "Boot Agent" , 执行 grep "\"Boot\ Agent\"" * -nR ( 反斜杠表示转义的意思 )
发现分区信息在 arch/arm/mach-s3c24xx/common-smdk.c 文件里
在 u-boot 里执行 mtdparts 查看 u-boot 的分区信息:
#: name size offset mask_flags
0: u-boot 0x00040000 0x00000000 0
1: params 0x00020000 0x00040000 0
2: kernel 0x00200000 0x00060000 0
3: rootfs 0x0fda0000 0x00260000 0
修改 arch/arm/mach-s3c24xx/common-smdk.c 文件,mtd_partition 改为以下内容 :
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "bootloader", //分区名字
.size = SZ_256K, //分区大小
.offset = 0, //偏移起始地址
},
[1] = {
.name = "params",
.offset = MTDPART_OFS_APPEND, //MTDPART_OFS_APPEND 表示紧接着上一个分区
.size = SZ_128K,
},
[2] = {
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = SZ_2M,
},
[3] = {
.name = "rootfs",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL, //MTDPART_SIZ_FULL 表示剩余的所有空间
},
};
分区信息修改完成后,烧写一个文件系统进去,看内核能不能正确挂载文件系统
执行以下命令:
nfs 30000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/first_fs.yaffs2
nand erase.part rootfs
nand write 30000000 260000 862080 (30000000-内存地址,260000-rootfs分区起始地址,862080-文件大小16进制)
重新烧写内核,并启动,发现内核还不支持 yaffs2 文件系统
查看 .config ,发现内核可以支持 jffs2 文件系统
执行以下命令,烧写 jffs2 文件系统
nfs 30000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/fs_mini_mdev.jffs2
nand erase.part rootfs
nand write 30000000 260000 $filesize
设置启动参数:set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
重新烧写内核,并启动,内核打印信息:VFS: Mounted root (jffs2 filesystem) on device 31:3.
说明文件系统已经被成功挂载,但是还不能用,因为 init 进程出现了问题,需要制作新的文件系统
使用 busybox 制作新的根文件系统
到 busybox 官网下载 busybox 源码 :https://busybox.net/
使用的版本是 busybox 1.20.0
解压busybox: tar xvfj busybox 1.20.0.tar.bz2 -C ./
解压完成后,在 busybox 根目录下,执行 make menuconfig,进入配置界面
选择Busybox Settings ---> Busybox Library Tuning ---> [*] Tab completion ,增加 Tab 补全功能
不使用静态链接,Build Options ---> []Build BusyBox as a static binary(no share libs)
修改交叉编译前缀,Build Options ---> (arm-linux-) Cross Compiler prefix
其他选项保持默认配置,然后直接 make 编译
编译完成后,把 busybox 安装在 /opt/work/other_board/kernel_projects/root_fs 目录,执行以下指令:
make CONFIG_PREFIX=/opt/work/other_board/kernel_projects/root_fs install
安装完成后,会在 /opt/work/other_board/kernel_projects/root_fs 目录下,生成以下文件和目录:
bin目录、linuxrc链接、sbin目录、usr目录
安装 glibc 库,交叉编译器目录下,一般都有 glibc 库 :
进入交叉编译器目录,执行 find -iname "lib" 查找库文件,查找结果如下:
./lib
./arm-none-linux-gnueabi/lib
./arm-none-linux-gnueabi/libc/armv4t/lib
./arm-none-linux-gnueabi/libc/armv4t/usr/lib
./arm-none-linux-gnueabi/libc/lib
./arm-none-linux-gnueabi/libc/thumb2/lib
./arm-none-linux-gnueabi/libc/thumb2/usr/lib
./arm-none-linux-gnueabi/libc/usr/lib
使用的库文件是
./arm-none-linux-gnueabi/libc/armv4t/lib
./arm-none-linux-gnueabi/libc/armv4t/usr/lib
建立两个目录:
mkdir /opt/work/other_board/kernel_projects/root_fs/lib
mkdir -p /opt/work/other_board/kernel_projects/root_fs/usr/lib
执行以下命令,复制 glibc 库到根文件系统的 lib 目录:
cp ./arm-none-linux-gnueabi/libc/armv4t/lib/*so* /opt/work/other_board/kernel_projects/root_fs/lib -d
cp ./arm-none-linux-gnueabi/libc/armv4t/usr/lib/*so* /opt/work/other_board/kernel_projects/root_fs/usr/lib -d
-d 参数表示,保持库文件的链接属性,不加 -d 的话,会导致复制的库文件很庞大
构建 etc 目录,etc 目录包含 :
fstab文件 ,该文件列出了需要挂载的文件系统
init.d目录,里面有 rcS脚本 ,该脚本的 mount -a 会执行 fstab 文件
inittab 文件,该文件是 init 进程执行的第一个文件,第一句话是执行 init.d/rcS 脚本
构建 dev 目录,执行 mkdir dev
在 dev 目录下,构建两个设备节点:
mknod console c 5 1
mknod null c 1 3
构建其他空目录:mkdir proc tmp sys mnt root
到此,最小根文件系统制作完成
使用工具制作 .jffs2 文件系统,执行以下命令:
mkfs.jffs2 -n -s 2048 -e 128KiB -d /opt/work/other_board/kernel_projects/root_fs -o root_fs.jffs2
-n 表示不需要 cleanmaker 节点,-s 表示一个扇区大小,-e 表示一个擦除块的大小,-d 表示制作的目录 -o 表示输出的镜像名
制作完成后,烧写 内核 和 文件系统 到开发板
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
nfs 30000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/root_fs.jffs2
nand erase.part rootfs
nand write 30000000 260000 $filesize
nfs 32000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/uImage_new && bootm 32000000
启动内核后,发现 jffs2 文件系统已经挂载成功,但提示不能加载 init 进程,
内核打印信息提示:Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
在内核源码中搜索 “Attempted to kill init”,跟踪源码,
发现exitcode为 #define SIGILL
4
上网搜索内核打印信息“Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004”
发现需要配置内核支持 EABI (嵌入式应用二进制接口),重新配置内核支持 EABI 并编译
Kernel Features --> Use the ARM EABI to compile the kernel
重新下载 内核 和 文件系统 到开发板,并启动:
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
nfs 30000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/root_fs.jffs2
nand erase.part rootfs
nand write 30000000 260000 $filesize
nfs 32000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/uImage_eabi && bootm 32000000
至此,内核启动成功,文件系统挂载成功
添加yaffs2文件系统
linux-3.4.2里,没有添加对yaffs2的支持,需要移植yaffs2到内核
yaffs2源码从以下网址获得:http://www.yaffs.net/download-yaffs-using-git
使用 git 工具获得yaffs2源码:git clone git://www.aleph1.co.uk/yaffs2 (如PC没有 git 工具,则需要安装)
下载完成后,进入 yaffs2 目录,查看 README-linux ,里面有 yaffs2 的安装方法:
Integrating YAFFS2 into a Linux 2.6.x kernel
--------------------------------------------
We'll start by assuming you have a building linux 2.6.x source tree called
linux-dir and have the
yaffs2 source code in a directory calls yaffs-dir.
yaffs-dir has a handy shell script called patch-ker.sh will painlessly do all the patching
for you.
patch-ker.sh takes three parameters:
c/l
copy or link: c will copy yaffs files into the kernel tree, l will
create symbolic links.
m/s
multi-version or single version vfs glue layer. Suggest you use m.
linux-tree
eg.
cd yaffs-dir
./patch-ker.sh c m linux-tree
执行以下指令给内核打上 yaffs2 的补丁
cd yaffs2
./patch-ker.sh c m /opt/work/other_board/kernel_projects/linux-3.4.2
补丁打完后,在 fs/yaffs2/ 目录下会有 yaffs2 源码
执行 make menuconfig 重新配置内核使其支持 yaffs2
-> File systems │
-> Miscellaneous filesystems (MISC_FILESYSTEMS [=y]) │
-> yaffs2 file system support (YAFFS_FS [=n])
制作 yaffs2 文件系统映像:mkyaffs2image /opt/work/other_board/kernel_projects/root_fs root_fs.yaffs2
重新编译内核,编译成功后,重新烧写到开发板
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3
nfs 30000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/root_fs.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 $filesize
nfs 32000000 192.168.1.61:/opt/work/other_board/kernel_projects/images/uImage_yaffs2 && bootm 32000000
烧写完成,启动,发现 yaffs2 文件系统挂载成功,但不能启动,使用替代法解决
发现问题出现在 u-boot 源码里,对yaffs烧写的那部分:
在 cmd_nand.c --> do_nand() --> nand_write_skip_bad() 函数里,
need_skip = check_skip_len(nand, offset, *length); //检查nandflash 里有多少坏块
......
......
if (!need_skip && !(flags & WITH_DROP_FFS)) { //如果没有坏块(need_skip == 0)&& (flags != WITH_DROP_FFS)
rval = nand_write (nand, offset, length, buffer); //就会执行以下的烧写
if (rval == 0)
return 0;
*length = 0;
printf ("NAND write to offset %llx failed %d\n",offset, rval);
return rval;
}
但对于 yaffs2 ,真正的烧写是在:
if (flags & WITH_YAFFS_OOB) {
int page, pages;
size_t pagesize = nand->writesize;
size_t pagesize_oob = pagesize + nand->oobsize;
struct mtd_oob_ops ops;
ops.len = pagesize;
ops.ooblen = nand->oobsize;
ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
pages = write_size / pagesize_oob;
for (page = 0; page < pages; page++) {
WATCHDOG_RESET();
ops.datbuf = p_buffer;
ops.oobbuf = ops.datbuf + pagesize;
rval = nand->write_oob(nand, offset, &ops);
if (rval)break;
offset += pagesize;
p_buffer += pagesize_oob;
}
}
因此,需要修改以上的代码,修改后为:
if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags & WITH_YAFFS_OOB)) {
rval = nand_write (nand, offset, length, buffer);
if (rval == 0)
return 0;
*length = 0;
printf ("NAND write to offset %llx failed %d\n",offset, rval);
return rval;
}
修改完成后,重新烧写 u-boot ,执行以下指令:
usb 1 30000000
nand erase 0 80000
nand write 30000000 0 80000
重新烧写内核和文件系统,成功挂载并运行 yaffs 文件系统
裁剪内核并制作补丁
进入 make menuconfig 去掉一些不需要用到的配置项,比如:
去掉一些无关的单板:
-> System Type │
-> SAMSUNG S3C24XX SoCs Support
去掉一些无关的文件系统:如 ext2、ext3、ext4 等。。。
重新编译内核,执行 make uImage
制作内核补丁:
cp .config config_ok
make distclean
mv -f linux-3.4.2 linux3.4.2_ok
tar xvfj linux-3.4.2.tar.bz2
diff -urN linux-3.4.2 linux-3.4.2_ok > linux-3.4.2_ok.patch
至此,内核移植完成。