Linux 3.4.2内核移植
作者:互联网
实验平台:Jz2440开发板
一、linux 3.4.2内核移植之简单修改
1. 从官网下载3.4.2内核,拿到linux服务器解压内核:
tar xjf linux-3.4.2.tar.bz2
2. 进入linux-3.4.2目录,并修改Makefile指定CPU架构和交叉编译器:
cd linux-3.4.2/
vim Makefile
159行找到以下代码:
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
修改为:
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
注:这里使用的交叉编译器版本为4.3.2,低版本编译器有可能编译不通过
3. 配置linux内核、编译:
make s3c2410_defconfig
make uImage
编译出现如下错误:
解决办法:把kernel/timeconst.pl
文件的373行 if (!defined(@val)) {
改为 if (!(@val)) {
。
重新编译,编译成功:
4. 把编译好的uImage烧写到开发板:
在uboot中输入以下命令,把uImage
烧写到开发板:(注:需要把编译成功的uImage
拷贝到/home/book/works/first_fs/
目录下)
nfs 32000000 192.168.2.109:/home/book/works/first_fs/uImage
uImage
烧写成功:
注:如果出现错误:Loading: T *** ERROR: File lookup fail
,重复多烧两次就成功了,前提是开发能ping通Ubuntu服务器。
5. 启动linux内核:
在uboot中输入以下命令启动Linux内核:
bootm 32000000
打印信息如下:
由上图可知,串口输出的是乱码。很显然,虽然我们的内核已经启动,但是串口的设置,肯定没有设置好。
通过分析uboot源码知,获取及其ID的方法为从环境变量中获取,或者使用默认的ID,在uboot的默认MACH ID:
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; // MACH_TYPE_SMDK2410 = 193
如果s = getenv("machid");
成功,则使用它。
我们可以先自己在环境变量中设置:(在uboot输入以下命令)
set machid 16a // smdk2440 mach-smdk2440.c
或者
set machid 7CF // mini2440 mach-mini2440.c
注:这个设置只是用于测试,不设置machid,只修改晶振频率也可以正常启动内核。
Jz2440开发板使用的是12M的晶振,所以需要把arch/arm/mach-s3c24xx/mach-smdk2440.c
的165行:
s3c24xx_init_clocks(16934400);
改为:
s3c24xx_init_clocks(12000000);
同时修改一下uboot的环境变量:
set bootargs console=ttySAC0,115200 root=dev/mtdblock3
把重新编译好的uImage
通过nfs烧写到开发板,并启动linux
,打印信息如下:
从上图可知,终于可以正常打印字符了,但内核还没启动成功。
二、linux 3.4.2内核移植之修改系统分区
上一节可以启动linux时已经可以正常打印字符了,但是linux内核还没有启动成功,最后打印的信息如下:
从打印信息可以看出,我们的分区不对,在uboot移植中,我们已经对整个系统进行分区了,现在打印说我们的分区不对,一定是内核里也有分区的相关设置,我们需要去修改内核。
从如下打印的信息,
在linux顶层目录下搜索:grep -nR "Boot Agent"
,发现在common-smdk.c
中的113行有对应的分区的设置:
/* NAND parititon from 2.4.18-swl5 */
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "Boot Agent",
.size = SZ_16K,
.offset = 0,
},
[1] = {
.name = "S3C2410 flash partition 1",
.offset = 0,
.size = SZ_2M,
},
[2] = {
.name = "S3C2410 flash partition 2",
.offset = SZ_4M,
.size = SZ_4M,
},
[3] = {
.name = "S3C2410 flash partition 3",
.offset = SZ_8M,
.size = SZ_2M,
},
[4] = {
.name = "S3C2410 flash partition 4",
.offset = SZ_1M * 10,
.size = SZ_4M,
},
[5] = {
.name = "S3C2410 flash partition 5",
.offset = SZ_1M * 14,
.size = SZ_1M * 10,
},
[6] = {
.name = "S3C2410 flash partition 6",
.offset = SZ_1M * 24,
.size = SZ_1M * 24,
},
[7] = {
.name = "S3C2410 flash partition 7",
.offset = SZ_1M * 48,
.size = MTDPART_SIZ_FULL,
}
};
uboot的分区是这样的:
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
linux系统分区需要改为:
/* NAND parititon from 2.4.18-swl5 */
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "bootloader",
.size = SZ_256K,
.offset = 0,
},
[1] = {
.name = "params",
.offset = 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,//剩下的所有分区
},
};
重新编译,把uImage烧写到开发板,并启动,最后的打印信息如下:
由此可知,我们的分区已经正常了,只是还缺少文件系统没有烧写。
我们先烧写一个简单的文件系统看一下能否正常启动系统:
nfs 30000000 192.168.2.120:/home/book/works/first_fs/fs_mini_mdev.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 889bc0
注:192.168.2.120是Ubuntu服务器的IP地址,由于是动态分配IP,所以与前面的不一样。
烧写文件系统后下载内核启动:
nfs 32000000 192.168.2.120:/home/book/works/first_fs/uImage
bootm 32000000
发现还是启动不了,显示不支持yaffs2文件系统,那么再试一下jffs文件系统是否可以:
nfs 30000000 192.168.2.120:/home/book/works/first_fs/fs_mini_mdev.jffs2
nand erase.part rootfs
nand write.jffs2 30000000 260000 5b89a8
nfs 32000000 192.168.2.120:/home/book/works/first_fs/uImage
bootm 32000000
打印的信息如下:
从上面打印的信息可知,成功挂载了jffs2文件系统,但是内核没有启动成功。
对于ifconfig: SIOCSIFADDR: No such device
这个问题应该是网卡驱动没有移植好。解决办法有两个:① 移植linux DM9000网卡驱动;②去 etc/init.d/rcS中把ifconfig eth0 xxx.xxx.xxx.xxx注释掉(注:在别人的博客有人说,最终也卡在starting pid 933, tty '': '/etc/init.d/rcS'
,原因是文件系统与编译内核的工具链版本需要相同)
三、从0制作支持内核的文件系统
1.编译Busybox
获取busybox源码1.20.0版本的下载地址,把下载好的源码拿到Linux系统解压,进入到源码目录,然后直接:
make menuconfig
出现下面的界面:
设置交叉编译器:
选择:
Busybox Settings —>
Build Options —>
Cross Compiler prefix (NEW)
然后会出现可以输入的横条,在里面输入我们的编译器的前缀:
配置好后,退出保存保存配置。
然后直接编译:make
编译完成后,把它安装到fs_mini_mdev_new
,新建目录:
mkdir fs_mini_mdev_new
切换到busybox目录下进行安装:
make install CONFIG_PREFIX=../fs_mini_mdev_new
安装完成后,fs_mini_mdev_new
目录下的文件如下图所示:
第一步已经完成,busybox已经安装好,下一步是安装库。
2.安装库
查看工具链的路径:echo $PATH
可知工具链的路径是:/work/tools/arm-linux-gcc-4.3.2/bin
进入/work/tools/arm-linux-gcc-4.3.2/
目录:cd /work/tools/arm-linux-gcc-4.3.2/
输入:find -name lib
找到很多库如下:
用到的库只有这两个:
./arm-none-linux-gnueabi/libc/armv4t/usr/lib
./arm-none-linux-gnueabi/libc/armv4t/lib
我们只需要把这两个库拷贝过来就行:
先在fs_mini_mdev_new目录下建立以lib目录,然后把/work/tools/arm-linux-gcc-4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
目录下的所有.so
文件拷贝到fs_mini_mdev_new
的lib
目录下:
cp /work/tools/arm-linux-gcc-4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/*so* /home/book/works/busybox/fs_mini_mdev_new/lib -d (-d代表原来是链接文件,拷贝过来之后还是链接文件)
还有一个库需要添加:
在/home/book/works/busybox/fs_mini_mdev_new/usr
目录下新建lib目录,然后把/work/tools/arm-linux-gcc-4.3.2//arm-none-linux-gnueabi/libc/armv4t/usr/lib目录所有.so
文件拷贝到/home/book/works/busybox/fs_mini_mdev_new/usr/lib
目录下:
cp /work/tools/arm-linux-gcc-4.3.2/arm-none-linux-gnueabi/libc/armv4t/usr/lib/*so* /home/book/works/busybox/fs_mini_mdev_new/usr/lib -d
库已经添加完了,接下来是构造一些其他目录(etc,dev目录等)
3. 构造etc目录:
3.1 创建etc/inittab文件
在fs_mini_mdev_new
目录下创建etc
目录,在etc目录下创建inittab
文件,内容如下:
# /etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
3.2 创建etc/init.d/rcS文件
这是一个脚本,可以在里面添加想自动执行的命令。以下命令配置IP地址、挂接/etc/fstab指定的文件系统。
#!/bin/sh
ifconfig eth0 192.168.2.200
mount -a
其中:
第一行表示这是一个脚本文件,运行时使用/bin/sh解析。
第三行挂接/etc/fstab文件指定的所有文件系统。
最后还要更改它的属性,使它能够执行:
chmod +x etc/init.d/rcS
3.3 创建etc/fstab文件
内容如下,表示执行“mount -a”命令后将挂接proc、tmpfs文件系统
# device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
注:/etc/fstab 文件被用来定义文件系统的“静态信息”,这些信息被用来控制mount命令的行为。
4.构建dev目录
该目录下存放的是设备文件。设备文件是Linux系统中特有的文件类型,在Linux系统下,以文件的方式访问各种外设,即通过读写某个设备文件来操作某个具体硬件。比如通过“/dev/ttySAC0”文件可以操作串口0,通过/dev/mtdblock1”可以访问MTD设备(NAND Flash、NOR Flash等)的第二个分区。
/dev
的创建有3种方法:
① 手动创建:在制作根文件系统的时候,就在/dev目录下创建需要操作的设备文件比如ttySAC0等。系统挂接根文件系统后,就可以使用/dev目录下的设备文件了。
② 使用devfs文件系统:这种方法已经过时
③ 使用udev:udev是一个用户程序,它能够根据系统中硬件设别的状态更新设备文件,包括设备文件的创建、删除等。使用udev机制也不需要在/dev目录下创建设备节点,它需要一些用户程序的支持,并且内核要支持sysfs文件系统。它的操作比较复杂,但是灵活性比较高。在busybox中,有一个mdev命令,它是udev命令的简化版。
那么我们就使用mdev来创建设备文件:要在内核启动时自动运行mdev,需要修改etc/fstab文件来自动挂载文件系统、修改etc/init.d/rcS文件加入要自动运行的命令。
etc/fstab
的修改:
# device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
etc/init.d/rcS
的修改:
#!/bin/sh
ifconfig eth0 192.168.1.104
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
另外,mdev是通过init进程来启动的,在使用mdev构造/dev目录之前,init进程至少要用到的设备文件为/dev/console和/dev/null,所以要建立这两个文件:
mkdir dev
cd dev
sudo mknod console c 5 1
sudo mknod null c 1 3
5.构建其他目录
mkdir proc mnt sys root tmp
现在我们的/work/nfs_root/fs_mini_mdev_new目录下就是一个非常小的根文件系统。开发板可以将它作为网络根文件系统直接启动。如果要烧写进开发板,还要将它制作为一个文件,称为映像文件。
6. 制作文件系统映像文件
6.1首先需要编译制作jffs2映像文件的工具
工具:mtd-utils-05.07.23.tar.bz2 是MTD设备的工具包,编译它生成mkfs.jffs2工具,用它来将一个目录制作成jffs2文件系统映像文件。这个工具包需要zlib压缩包,先安装zlib。(mtd-utils-05.07.23.tar.bz2、zlib-1.2.3.tar.gz这两个文件在Jz2440开发板的资料光盘可以找到)
① 先安装zlib:
tar xzf zlib-1.2.3.tar.gz
cd zlib-1.2.3
./configure --shared --prefix=/usr
make
sudo make install
② 然后编译mkfs.jffs2
tar xjf mtd-utils-05.07.23.tar.bz2
cd mtd-utils-05.07.23/util
make
sudo make install
6.2 制作jffs2映像文件
进入fs_mini_mdev_new
所在的目录,输入以下命令:
mkfs.jffs2 -n -s 2048 -e 128KiB -d fs_mini_mdev_new -o fs_mini_mdev_new.jffs2
上面-n 表示不要在每个擦除块上都加上清除标志,-s 2018 表示我们的NAND Flash的一页的大小为2048字节,-e 128KiB 表示一个擦除快大小为128KiB ,-d 表示根文件系统的目录,-o表示输出的文件。
nfs 30000000 192.168.2.120:/home/book/works/busybox/fs_mini_mdev_new.jffs2
nand erase.part rootfs
nand write.jffs2 30000000 260000 $filesize
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
nfs 32000000 192.168.2.120:/home/book/works/first_fs/uImage
bootm 32000000
串口输出正常,linux也正常启动,整个系统也跑起来了。
注:在视频教程中,出现了错误:Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200。
分析这个错误:在内核中搜索字符串:exitcode,通过函数层层调用的分析,最终找到:do_exit(SIGKILL);执行了这个调用,才出现错误代码4,原因是编译内核用的编译工具是eabi接口的,我们需要重新配置内核使用EABI接口:
编译内核前需要配置linux:make menuconfig
然后依次选择:
Kernel Features —>
[*] Use the ARM EABI to compile the kernel
四、修改内核代码支持YAFFS文件系统
上一节从0制作jffs2文件系统,因为linux3.4.2内核本身就支持jffs2文件系统,但是它不支持yaffs文件系统,所以现在通过修改linux内核源码来支持yaffs文件系统。
1. 获取yaffs源码
获取源码yaffs源码的方式有很多种,这里我是直接从Jz2440开发板光盘资料中获取的yaffs源码。把它拷贝到Ubuntu服务器下并解压。
2. 给linux内核打补丁
进入到yaffs2源码目录,使用下面的命令进行打补丁:
./patch-ker.sh c m /home/book/works/linux-3.4.2 //后面这个是我的linux内核源码目录
打完补丁后,就会在内核的fs/yaffs2目录下加入了yaffs的源码
3. 配置内核支持YAFFS
在linux源码顶层目录下输入:
make menuconfig
依次选择:
File systems --->
Miscellaneous filesystems --->
<*> yaffs2 file system support
然后保存配置。重新编译内核:
make uImage
编译成功。
4. 制作yaffs2文件系统系统映像
上一节我们已经制作好了文件系统,接下来就是制作yaffs2映像。在fs_mini_mdev_new
所在的目录,输入以下命令:
mkyaffs2image fs_mini_mdev_new fs_mini_mdev_new.yaffs2
就可知制作出yaffs2文件系统映像。
5. 烧写YAFFS文件系统映像
在uboot中输入以下命令:
nfs 30000000 192.168.2.120:/home/book/works/busybox/fs_mini_mdev_new.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 $filesize
6. 烧写新内核启动
烧写内核前,在uboot设置启动参数:
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3
save
烧写内核:
nfs 32000000 192.168.2.120:/home/book/works/first_fs/uImage
bootm 32000000
如下图所示,yaffs文件系统成功挂载,linux启动成功,整个系统运行正常。
7. 制作内核补丁
最后我们将移植好的内核,生成补丁,方便以后的使用:
cp .config config_ok
make distclean
mv linux-3.4.2 linux-3.4.2_100ask
tar xjf linux-3.4.2.tar.bz2
diff -urN linux-3.4.2 linux-3.4.2_100ask > linux-3.4.2_100ask.patch
8. 如何打补丁:
patch -p1 < ../linux-3.4.2_100ask.patch
cp config_ok .config
make uImage
9. 把之前修改好的uImage 烧写到开发板(注:是烧写到Nand flash,之前的是烧写到SDRAM的一个地址里,然后从这个地址启动内核)
nfs 32000000 192.168.2.120:/home/book/works/first_fs/uImage
nand erase.part kernel
nand write 32000000 kernel
重新启动开发板,打印信息如下,linux启动失败。
上图显示checksum 错误,Data Size是2.4M,前面我们只为kernel分区分配了2M的存储空间,这肯定是不够了,所以需要改大kernel分区,这里我们把它改为4M。
① 修改uboot源码:
对uboot进行重新分区如下:(把kernel分区改为4M)
0x00000000-0x00040000 : “bootloader” (0~256k)
0x00040000-0x00060000 : “params”
0x00060000-0x00460000 : “kernel”
0x00460000-0x10000000 : “root”
修改uboot的配置文件include/configs/smdk2440.h
:
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define MTDIDS_DEFAULT "nand0=jz2440-0" /* 表示哪一个设备 */
#define MTDPARTS_DEFAULT "mtdparts=jz2440-0:256k(u-boot)," \
"128k(params)," \
"2m(kernel)," \
"-(rootfs)" \
改为:
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define MTDIDS_DEFAULT "nand0=jz2440-0" /* 表示哪一个设备 */
#define MTDPARTS_DEFAULT "mtdparts=jz2440-0:256k(u-boot)," \
"128k(params)," \
"4m(kernel)," \
"-(rootfs)" \
重编译,重新烧写uboot,在uboot输入命令:mtdparts
,从下图可知,kernel分区已经修改为4MB。
② 修改linux系统分区:
把common-smdk.c
中的113行有对应的分区的设置:
/* NAND parititon from 2.4.18-swl5 */
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "bootloader",
.size = SZ_256K,
.offset = 0,
},
[1] = {
.name = "params",
.offset = MTDPART_OFS_APPEND, //紧接着上一个分区
.size = SZ_128k,
},
[2] = {
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = SZ_4M,
},
[3] = {
.name = "rootfs",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,//剩下的所有分区
},
};
③ 重新编译uImage,并烧写内核。
nfs 32000000 192.168.2.120:/home/book/works/first_fs/uImage
nand erase.part kernel
nand write 32000000 60000 $filesize
从0x32000000启动内核,打印信息如下,说明linux系统分区修改成功。
④ 重新烧写yaffs2文件系统:
nfs 30000000 192.168.2.120:/home/book/works/busybox/fs_mini_mdev_new.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 460000 $filesize
⑤ 重新设置uboot启动命令:
set bootcmd "nand read 30000000 kernel 0x400000;bootm 30000000"
save
然后输入命名:reset
,重启开发板,linux启动成功。
然后重复步骤"7. 制作内核补丁",重新制作补丁文件。
标签:fs,Linux,文件系统,3.4,内核,mdev,linux,目录 来源: https://blog.csdn.net/qq_35031421/article/details/104086584