第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

时间:2021-01-10 09:05:26

三、内核的移植

说明:针对的是百问网的jz2440   

gcc:4.9.1


1、移植内核

首先,下载源码包:https://www.kernel.org/

现在时间为2014年12月20日其主界面截图为:

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

在此,就在下较新的稳定的版本作为尝试。在这里有个命名问题需要说明一下,最前面的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)

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

上面的集中SoCs可根据需要进行选择。(假如内核编译完毕,下载后无法启动,可以尝试去掉SAMSUNG S3C2410这个选项)

然后在system type—选着串口打印信息这里选择串口0

(0)   S3C UART to use for low-level messages

然后在kernel hacking—

也要选择串口0

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

然后再Boot option ----->

noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200这里根据实际情况设置假如此时不设置的话在uboot设置也可以。

在devicedriversà

<*>                     Memorytechnology device(MTD) support里面

这里要选择MTD partitioning support(mtd分区支持)可是这个选择没有出现。如图:

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

因此需要手动的去添加。

此时可以打开一个2.6内核的在内核目录下drivers/mtd/kconfig找到,因此我们修改本内核的文件使之支持:

vi drivers/mtd/Kconfig

赋值下面的语句到linux-3.14.28/drivers/mtd/kconfig(注意第一个字母大写)的第25行左右就可以。

 

config MTD_PARTITIONS

      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会打印出一些环境变量的信息:

 第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

其中倒数第九行没改正之前为:

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 得到:

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

然后重新执行:

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,   //新加

};

整体效果如下图:

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

然后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

  (根据后缀名选取不同的解压参数)

解压后放置效果如图:

第二部分 s3c2440 移植linux内核 添加网卡支持 yaffs2文件系统支持

进入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