三、内核的移植
说明:针对的是百问网的jz2440
gcc:4.9.1
1、移植内核
首先,下载源码包:https://www.kernel.org/
现在时间为2014年12月20日其主界面截图为:
在此,就在下较新的稳定的版本作为尝试。在这里有个命名问题需要说明一下,最前面的2.6或者3.18是主版本号码,后面的次版本号是比如2.6.32.65中的32,再后面的比如2.6.32.65中的65是升级版本号,主版本号为奇数的是开发本比如3.17,主版本号为偶数的为稳定版比如3.18,一般情况下名字后面是-rc1的是测试版。然后紧接着下载其对应版本的补丁文件(假如存在补丁文件)这里下载的源码包的名字为linux-3.14.27.tar.xz。补丁文件是patch-3.14.27.xz
使用git下载的话可执行获取linux3.14.x的源码:
git clonegit://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
gitcheckout remotes/origin/linux-3.14.y
然后解压linux内核,进入其目录假如需要打补丁的话进行打补丁
cd linux-3.14.27/
接下来修改交叉编译
在顶层Makefile中的198行和199行
vi Makefile
ARCH ?=$(SUBARCH)
CROSS_COMPILE ?=$(CONFIG_CROSS_COMPILE:"%"=%)
修改为:
ARCH ?=arm
CROSS_COMPILE ?= arm-linux-
在这里简单的说明一下?=与:=与=与+=的区别
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
具体的可以参考博客http://www.cnblogs.com/wanqieddy/archive/2011/09/21/2184257.html
这里很显然在linux-3.14.28/arch/arm/configs/下只有s3c2410_defconfig配置文件没有2440的的配置文件因此因此需要开发版的配置与内核的配置一致,其实这里要说明的是,s3c2410与s3c2440的cpu是一样的,至于原因可以通过cpu的ID看得出。由于内核代码没有针对2440的配置,在linux-3.14.28/arch/arm/configs/可以知道 s3c2410_defconfig所以用配置2410的文件来配置内核。使之生成.config配置文件
接下来进行预配置
在linux-3.14.28/目录下执行
make s3c2410_defconfig
很快生成了配置文件,假如此时执行make 或者make uImage会生成uImage,但是这适用于2410下载到2440上面会出现乱码。
这里简短的说明一下内核的命令
make mrproper--- 清理全部文件,包括.config和一些备份文件
make clean --- 清理生成文件,但会保留.config和一些模块文件。
make defconfig--- 生成包含全部默认选项的.config文件。这里用make s3c2410_defconfig替代
make oldconfig--- 在旧的.config基础上生成新的.config。如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦
make config --- 基于文本的最为传统的配置界面,不推荐使用
make menuconfig--- 基于文本选单的配置界面,字符终端下推荐使用
make xconfig ---基于图形窗口模式的配置界面,Xwindow下推荐使用
目的都是生成一个.config文件,这三个命令中,makexconfig的界面最为友好,如果你可以使用Xwindow,你就用这个好了,这个比较方便,也好设置。如果你不能使用Xwindow,那么就使用 make menuconfig好了。界面虽然比上面一个差点,总比make config的要好多了。
make --- 默认编译。
make bzImage --- 编译生成压缩的内核二进制文件,也会用make zImage替代
所以接下来make menuconfig
首先在system type---SANSUNG s3c244xxSoCs Support—
选中s3c2410 MDA support 表示支持dma
当然在开头的部分列举出了好几种型号的片上系统(SoCs)
上面的集中SoCs可根据需要进行选择。(假如内核编译完毕,下载后无法启动,可以尝试去掉SAMSUNG S3C2410这个选项)
然后在system type—选着串口打印信息这里选择串口0
(0) S3C UART to use for low-level messages
然后在kernel hacking—
也要选择串口0
然后再Boot option ----->
noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200这里根据实际情况设置假如此时不设置的话在uboot设置也可以。
在devicedriversà
<*> Memorytechnology device(MTD) support里面
这里要选择MTD partitioning support(mtd分区支持)可是这个选择没有出现。如图:
因此需要手动的去添加。
此时可以打开一个2.6内核的在内核目录下drivers/mtd/kconfig找到,因此我们修改本内核的文件使之支持:
vi drivers/mtd/Kconfig
赋值下面的语句到linux-3.14.28/drivers/mtd/kconfig(注意第一个字母大写)的第25行左右就可以。
bool "MTD partitioning support"
help
Ifyou have a device which needs to divide its flash chip(s) up
into multiple 'partitions', each of which appears to the user as
aseparate MTD device, you require this option to be enabled. If
unsure, say 'Y'.
Note, however, that you don't need this option for the DiskOnChip
devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device.
修改完毕后,继续执行make menuconfig
然后在devicedrivers ---memory technology device(mtd) support中选着
<*>MTDpartitioning support
然后
Kernel Features ->
[*]Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel
接下来修改mtd分区
vi ./arch/arm/mach-s3c24xx/common-smdk.c
112行static struct mtd_partitionsmdk_default_nand_part的函数
把整个函数替换为下面的函数。
这里分为四个部分,本人板子nand是256m
修改为:
static struct mtd_partitionsmdk_default_nand_part[] = {
[0]= {
.name = "bootloader",
.size = 0x00040000, //256k
.offset =0,
},
[1]= {
.name = "params",
.offset= 0x00040000,
.size = 0x00020000, //128k
},
[2]= {
.name = "kernel",
.offset= 0x00060000,
.size = 0x00400000, //4m
},
[3]= {
.name = "root",
.offset = 0x00460000,
.size = 0x0fba0000, //251m
}
};
然后修改晶振频率:
vi arch/arm/mach-s3c24xx/mach-smdk2440.c
将s3c24xx_init_clocks(16934400);
改为
s3c24xx_init_clocks(12000000);//12m晶振
修改机器码:这个跟uboot的需要一致,具体的可以查看在uboot下使用bdinfo查看。
机器码显示为0x0000016A
在arch/arm/tools/mach-types
s3c2440 ARCH_S3C2440 S3C2440 362(因为0x16a=362无需改动)
最后执行make uImage
接下来提示了个错误:
"mkimage"command not found - U-Boot images will not be built
make[1]: ***[arch/arm/boot/uImage] 错误 1
make: ***[uImage] 错误 2
这里是提示缺少mkimage工具,安装此工具:
sudo apt-get install u-boot-tools
然后继续
make uImage
这里说明下make uImage 与make zImage的区别:
zImage是ARM Linux常用的一种压缩映像文件,uImage是U-boot专用的映像文件,它是在zImage之前加上一个长度为0×40的“头”,说明这个映像文件的类型、加载位置、生成时间、大小等信息。换句话说,如果直接从uImage的0×40位置开始执行,zImage和uImage没有任何区别。另外,Linux2.4内核不支持uImage,Linux2.6内核加入了很多对嵌入式系统的支持,但是uImage的生成也需要设置。此外uImage要比zImage同样的内核要大好多。可参考:http://bbs.21ic.com/icview-374802-1-1.html。
最后会在linux-3.14.28/arch/arm/boot/目录下生成uImage
接下来将生成的uImage下载到开发板:
对于基本的内核uImage。可直接在uboot下载,执行:
tftp 0x30000000 uImage
或者 nfs 0x30000000 192.168.1.110:/work/nfs-root/tmp/uImage
(ip为linux ip 前提内核镜像文件拷问到相应目录下 )
nand erase kernel
nand write 0x30000000 kernel
其中uboot的分区如下:
device nand0<nandflash0>, # parts = 4
#: name size offset mask_flags
0: bootloader 0x00040000 0x00000000 0
1: params 0x00020000 0x00040000 0
2: kernel 0x00200000 0x00060000 0
3: root 0x0fda0000 0x00260000 0
activepartition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000
defaults:
mtdids : nand0=nandflash0
mtdparts:mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)
然后启动后出现:
Reading datafrom 0x25f800 -- 100% complete.
2097152 bytes read: OK
## Booting imageat 30007fc0 ...
Image Name: Linux-3.14.26
Created: 2015-01-05 2:46:41 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2741160 Bytes = 2.6 MB
Load Address: 30108000
Entry Point: 30108000
Verifying Checksum ... Bad Data CRC
这里,发现生成的uImage是2.61M然后Uboot对nand flash的kernel是2m,太小了
收到该博客启发:http://blog.chinaunix.net/uid-14114479-id-3148959.html
于是修改uboot对于nand flash的分区(或者直接写起始地址与分区大小),这里通过环境变量修改分区大小,在uboot输入print会打印出一些环境变量的信息:
其中倒数第九行没改正之前为:
mtdparts=mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)
因此只需设置一下环境变量就可以:
set mtdpartsmtdparts=nandflash0:256k@0(bootloader),128k(params),4m(kernel),-(root)
然后执行: save //保存修改
然后重新查看mtd分区:输入uboot命令 mtd 得到:
然后重新执行:
tftp 0x30000000 uImage或者 nfs 0x30000000192.168.1.110:/work/nfs-root/kernel/uImage
(使用nfs下载时,需将内核镜像靠备考相应目录)
nand erase kernel
nand write 0x30000000 kernel
这里假如串口打印的是乱码有两种原因:其一,内核中arch\arm\mach-s3c24xx\mach-smdk2440.c没有设置正确的晶振 s3c24xx_init_clocks(12000000);//12m晶振根据实际修改;其二。Uboot传入参数设置的波特率波有问题。
2、添加网卡驱动
因为裸机的时候没有涉及网卡代码的编写,这里涉及到网络驱动,这里先不分析原理,这是移植成功就可以了。
为此阅读linux-3.14.27\Documentation\networking/下的dm9000.txt,根据上面的代码尝试修改如下:
(部分参考http://blog.csdn.net/zjhsucceed_329)
修改arch/arm/mach-s3c24xx/mach-smdk2440.c ,在该源码文件新加入:
#include<linux/dm9000.h>
#include"bast.h" //这里包含了对BAST_PA_DM9000宏定义(PA物理地址)
static struct resourcesmdk2440_dm9k_resource[] = {
[0] = {
.start = S3C2410_CS4 +BAST_PA_DM9000, //文档里给的是S3C2410_CS5这是因
为问档的地址/数据线(共用)连接到back5,实际开发板连接的banck4所以要把S3C2410_CS5改为S3C2410_CS4
.end = S3C2410_CS4 + BAST_PA_DM9000 + 3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start =S3C2410_CS4 + BAST_PA_DM9000 + 4,// 0x40, //文档里给的偏移地址为0x40这里改成4
.end = S3C2410_CS4 + BAST_PA_DM9000 + 7,//0x40 +0x3f,
//文档里给的偏移地址为0x7f这里改成7
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT7, //中断引脚
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ |IORESOURCE_IRQ_HIGHLEVEL,
}
};
static struct dm9000_plat_datasmdk2440_dm9k_platdata = {
.flags =DM9000_PLATF_16BITONLY, //DM9000_PLATF_16BITONLY
};
static struct platform_devicesmdk2440_device_dm9k = {
.name ="dm9000",
.id = 0,
.num_resources =ARRAY_SIZE(smdk2440_dm9k_resource),
.resource =smdk2440_dm9k_resource,
.dev = {
.platform_data= &smdk2440_dm9k_platdata,
},
};
然后找到*smdk2440_devices[]数组,在该数组里面添加&smdk2440_device_dm9k,添加后数组如下所示:
static struct platform_device*smdk2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&smdk2440_device_dm9k, //新加
};
整体效果如下图:
然后make uImage
下载内核后提示:
dm9000 dm9000.0 eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
表明正确。
3、添加内核支持YAFFS2文件系统(可选)
假如需要支持yaffs文件系统的话需要配置一下,进入yaffs源码文件(可以在下面网址下载源码包http://www.yaffs.net/download-yaffs-using-git)。
下载后,将下载的源码包拷贝到linux系统中。(这里我把yaffs2的源码包和linux的源码包放到了同一个文件夹下面:)
拷贝后解压:
tar -xvf yaffs2-7e5cf0f.tar.gz
或者tar -xJvf yaffs2-7e5cf0f.tar.xz
(根据后缀名选取不同的解压参数)
解压后放置效果如图:
进入yaffs2目录: cdyaffs2-HEAD-7e5cf0f/
里面有个README-linux-patch详细的介绍使用过程。
在yaffs2源码包下运行 ./patch-ker.sh c m ../linux-3.14.27 //其中的c代表复制,m代表复合类型
运行完毕后,进入到linux-3.14.28目录中:
进入配置菜单 make menuconfig
运行后在Filesystem –-- > Miscellaneous filesystems(其他文件系统)—选择
Yaffs2 file sysytom support
其余的暂且使用默认配置,如有其他需要回来再选。
将其加入内核后就可以编译内核:
make uImage
此时会提示错误:
fs/yaffs2/yaffs_vfs.c:In function 'yaffs_file_flush':
fs/yaffs2/yaffs_vfs.c:741:2:error: too few arguments to function 'yaffs_flush_file'
yaffs_flush_file(obj, 1, 0);
^
In file includedfrom fs/yaffs2/yaffs_vfs.c:173:0:
fs/yaffs2/yaffs_guts.h:879:5:note: declared here
int yaffs_flush_file(struct yaffs_obj *in,
^
fs/yaffs2/yaffs_vfs.c:In function 'yaffs_sync_object':
fs/yaffs2/yaffs_vfs.c:771:2:error: too few arguments to function 'yaffs_flush_file'
yaffs_flush_file(obj, 1, datasync);
^
In file includedfrom fs/yaffs2/yaffs_vfs.c:173:0:
fs/yaffs2/yaffs_guts.h:879:5:note: declared here
int yaffs_flush_file(struct yaffs_obj *in,
^
fs/yaffs2/yaffs_vfs.c:In function 'yaffs_flush_inodes':
fs/yaffs2/yaffs_vfs.c:2190:4:error: too few arguments to function 'yaffs_flush_file'
yaffs_flush_file(obj, 1, 0);
^
In file includedfrom fs/yaffs2/yaffs_vfs.c:173:0:
fs/yaffs2/yaffs_guts.h:879:5:note: declared here
int yaffs_flush_file(struct yaffs_obj *in,
^
fs/yaffs2/yaffs_vfs.c:In function 'yaffs_flush_super':
fs/yaffs2/yaffs_vfs.c:2203:2:error: too few arguments to function 'yaffs_flush_whole_cache'
yaffs_flush_whole_cache(dev);
^
In file includedfrom fs/yaffs2/yaffs_vfs.c:173:0:
fs/yaffs2/yaffs_guts.h:885:6:note: declared here
void yaffs_flush_whole_cache(struct yaffs_dev*dev, int discard);
^
fs/yaffs2/yaffs_vfs.c:In function 'yaffs_proc_read':
fs/yaffs2/yaffs_vfs.c:3214:37:error: macro "__DATE__" might prevent reproducible builds[-Werror=date-time]
"Multi-version YAFFS built:"__DATE__ " " __TIME__
^
fs/yaffs2/yaffs_vfs.c:3214:50:error: macro "__TIME__" might prevent reproducible builds[-Werror=date-time]
"Multi-version YAFFS built:"__DATE__ " " __TIME__
^
fs/yaffs2/yaffs_vfs.c:In function 'init_yaffs_fs':
fs/yaffs2/yaffs_vfs.c:3565:54:error: macro "__DATE__" might prevent reproducible builds[-Werror=date-time]
"yaffs built " __DATE__ "" __TIME__ " Installing.");
^
fs/yaffs2/yaffs_vfs.c:3565:1:error: macro "__TIME__" might prevent reproducible builds[-Werror=date-time]
"yaffs built " __DATE__ "" __TIME__ " Installing.");
^
fs/yaffs2/yaffs_vfs.c:In function 'exit_yaffs_fs':
fs/yaffs2/yaffs_vfs.c:3606:52:error: macro "__DATE__" might prevent reproducible builds[-Werror=date-time]
"yaffs built " __DATE__ "" __TIME__ " removing.");
^
fs/yaffs2/yaffs_vfs.c:3606:1:error: macro "__TIME__" might prevent reproducible builds[-Werror=date-time]
"yaffs built " __DATE__ "" __TIME__ " removing.");
^
cc1: somewarnings being treated as errors
make[2]: ***[fs/yaffs2/yaffs_vfs.o] 错误 1
make[1]: ***[fs/yaffs2] 错误 2
make: *** [fs] 错误 2
看到错误可以知道。这是两个错误,其中的一个错误是因为某个函数缺少一个参数,另一个错误是吧某些警告信息当成错误去处理,先看第一个错误:
这里的问题看着确实是少一个参数在yaffs2_vfs.c 741
#if(LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static intyaffs_file_flush(struct file *file, fl_owner_t id)
#else
static intyaffs_file_flush(struct file *file)
#endif
{
struct yaffs_obj *obj =yaffs_dentry_to_obj(file->f_dentry);
struct yaffs_dev *dev = obj->my_dev;
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_file_flush object %d(%s)",
obj->obj_id,
obj->dirty ? "dirty" :"clean");
affs_gross_lock(dev);
yaffs_flush_file(obj,1, 0); //三个形参
yaffs_groyaffs_gross_lockss_unlock(dev);
return 0;
}
而杂yaffs_gust.c定义的时候却有四个参数。
intyaffs_flush_file(struct yaffs_obj *in,
int update_time,
int data_sync,
int discard_cache)
{
if (!in->dirty)
return YAFFS_OK;
yaffs_flush_file_cache(in, discard_cache);
if (data_sync)
return YAFFS_OK;
if (update_time)
yaffs_load_current_time(in, 0, 0);
return (yaffs_update_oh(in, NULL, 0, 0, 0,NULL) >= 0) ?
YAFFS_OK :YAFFS_FAIL;
}
这里在缺少参数的地方补个0,调用的时候变成yaffs_flush_file(obj, 1, 0, 0); yaffs_flush_whole_cache(dev, 0);实际上最后一个参数在yaffs_gust.c的1471行实用的:
static voidyaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
{
if (!cache || cache->locked)
return;
/* Write it out and free it up if need be.*/
if (cache->dirty) {
yaffs_wr_data_obj(cache->object,
cache->chunk_id,
cache->data,
cache->n_bytes,
1);
cache->dirty = 0;
}
if(discard)
cache->object= NULL;
}
至于最后是否对整个yaffs文件系统的挂载有影响,先这样设定,后面继续观察。
于是进入在linux的源码包中修改源码文件:
vi fs/yaffs2/yaffs_vfs.c
将该文件的741行
yaffs_flush_file(obj, 1, 0); 修改为yaffs_flush_file(obj,1, 0, 0);
771行
yaffs_flush_file(obj, 1, datasync);修改为yaffs_flush_file(obj, 1, datasync, 0);
2190行
yaffs_flush_file(obj, 1, 0); 修改为yaffs_flush_file(obj,1, 0, 0);
2203行
yaffs_flush_whole_cache(dev,); 修改为: yaffs_flush_whole_cache(dev, 0);
对于第二个错误:
解释这个错误之前需要了解" __DATE__ " " __TIME__ " 等宏定义,具体可以参考:
http://www.360doc.com/content/12/0314/13/1317564_194254979.shtml
http://biancheng.dnbcw.info/c/277439.html
ANSIC标准定义了以下6种可供C语言使用的预定义宏:
__LINE__ 在源代码中插入当前源代码行号
__FILE__ 在源代码中插入当前源代码文件名
__DATE__ 在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕
__TIME__ 在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕
__STDC__ 当要求程序严格遵循ANSIC标准时该标识符被赋值为1。
__cplusplus
再来解释一下这个错误:
error: macro"__DATE__" might prevent reproducible builds [-Werror=date-time]
"Multi-version YAFFS built:"__DATE__ " " __TIME__
这是说宏"__DATE__"有可能会阻止可再生(二次)的构造,【这属于警告性错误】
这样可以先把这种错误不在以错误的形似存在。以警告的形式存在。
于是想办法去掉[-Werror=date-time]不让报错就可以
受http://lkml.iu.edu/hypermail/linux/kernel/1312.2/05011.html启发(声明:我的gcc是4.9.1)与在修改顶层目录下的makefile文件(vi linux-3.14.27/Makefile)的第696行,
在linux的源码包下,执行:
vi Makefile
KBUILD_CFLAGS +=$(call cc-option,-Werror=date-time) 注释掉就可以:
#KBUILD_CFLAGS +=$(call cc-option,-Werror=date-time)
然后继续make uImage