您的位置:首页 > 运维架构 > Linux

Linux kernel移植笔记

2016-06-13 11:45 489 查看
到内核官网下载最新版本的内核
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 <ben-linux@fluff.org> */
.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

至此,内核移植完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: