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_newlib目录下:

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 2048 表示我们的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. 制作内核补丁",重新制作补丁文件。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

[email protected].

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值