s3c2440嵌入式linux操作系统移植(lab1)

时间:2022-05-02 12:43:07

                                   嵌入式系统开发lab1试验小结

1.VIVI移植
在移植VIVI之前,必须先保证交叉编译器的正确性。因为张老师已经给了一个标准的基于gcc的交叉编译器,在此就不重复crosstool的生成过程。在VIVI和kernel的Makefile中需要指定交叉编译器的位置,所以在正式移植以前先把交叉编译器copy到指定的位置

/usr/local/arm/…

1.1      修改Makefile文件
Makefile中主要修要修改三处:

1.       LINUX_INCLUDE_DIR

设置为LINUX_INCLUDE_DIR = /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

2.       CROSS_COMPILE

设置为CROSS_COMPILE   = /usr/local/arm/4.3.2/bin/arm-linux-

3.       ARM_GCC_LIBS

设置为ARM_GCC_LIBS    = /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

 

其实在张老师给的VIVI版本中Makefile 的修改已经完成了,如果是用这个版本的VIVI,那么不用做任何的修改就可以直接移植了,如果是自己下载的,也只需要更改这三个地方。

1.2 修改arch/s3c2440/smdk.c
Smdk.c是VIVI移植中最重要的一个文件,主要是分区表的建立和启动参数的设置

1.       分区表的建立

将s3c2440_NAND_BOOT时对应的分区数据结构修改为如下结构

 

#ifdef CONFIG_S3C2440_NAND_BOOT

mtd_partition_t default_mtd_partitions[] = {  

                    {

        /*

          add by xwc

          2010-04-15

         */

        name:       "supervivi",

        offset:     0,

        size:       0x00030000,

        flag:       0

    }, {

        name:       "kernel",

        offset:     0x00050000,

        size:       0x00200000,

        flag:       0

    }, {

        name:       "root",

        offset:     0x00250000,

        size:       0x03Dac000,

        flag:       0

    }

};

#endif

 

在这里,我并没有采取张老师上课上提倡的5个分区的方法,甚至这里根本就没有param分区,不过需要注意的是supervivi 分区的结束点是0x00030000,kernel分区的开始点事0x00050000,这中间差的size大小是0x00020000,所以param其实还是可以利用这一段空间。

 

2.       启动参数的设置

启动参数主要是指这一行

char linux_cmd[] = "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0";

在我最开始做实验的时候,因为不知道param save 无法保存的bug是怎么回事(详见下文),所以选择在代码里修改,之后解决了那个问题,就选择用默认的参数,在启动的时候可以手动设置。

1.3 配置选项
         主要是用 make menuconfig的方式对VIV进行配置,不过一般在make menuconfig之前最好先执行make distclean 确保系统处于clean的状态,不然有时候会无法生成config界面

 

 

各个部分大致做的工作如下

System Type ---> [系统配置:主要设置芯片、平台类型 底层启动选项等]                

General setup---> [通用设置:vivi基地址、系统缓存、电源管理等 ]                   

Private Data ---> [私有数据设置:vivi的私有数据 启动的一些用户私有数据]           

Serial Port --->   [串口:是否支持串口(vivi只支持串口,怎么敢不选),串口传输协议]

Memory Technology Devices(MTD)--> [存储设备相关选项]                          

Add Built-in Commands ---->        [vivi支持命令]                            

System hacking ---->         [系统调试相关选项]                                

Debugging messages   --->    [调试信息相关]                                    

----                                                                           

Load and Alternate Configuration File [载入配置文件,vivi自带一个sdmk的配置文件]

Save Configuration to an Alternate File [保存自己的配置信息]

 

 

有如下几个地方需要注意:

System type 要选对,而且要保证支持NAND启动方式

I-cache D-cache 要选中,要不然启动很慢

要启动串口支持

 

1.4 做实验过程中遇到的问题
VIVI的移植相对而言很简单,最开始在make menuconfig的时候没有编辑界面跳出来,不过我平时弄linux-kernel比较多,linux kernel menuconfig的时候有时也会报错,主要是因为以前编辑过,有些残留的文件,要清除掉才可以,于是打开Makefile文件,查找果然有distclean:

 

clean:

    find . /( -name '*.o' -o -name core -o -name ".*.flags" /) -type f -print /

    | grep -v lxdialog/ | xargs rm -f

    rm -f $(CLEAN_FILES)

 

distclean: clean

 

于是我就知道肯定是要先make distclean一下。

 

 

还有一个问题就是mach_type, 这里经过我的研究,发现只要linux kernel和vivi中对应就可以了,不修改也是没有问题的,所以我选择了不修改。

2. linux 内核移植
内核的移植其实本质上跟VIVI差不多,主要是做一些配置,一是使用gcc-arm交叉编译器,二是与vivi上的分区表保持一致。

2.1修改Makefile
主要是修改成使用arm-gcc交叉编译器进行编译,下面是我makefile中修改的地方

第一处:

#========================================================================

#SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ /

#                 -e s/arm.*/arm/ -e s/sa110/arm/ /

#                 -e s/s390x/s390/ -e s/parisc64/parisc/ /

#                 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ /

#                 -e s/sh.*/sh/ )

#========================================================================

# add by xwc

# 2010-4-15

SUBARCH := arm

#========================================================================

第二处:

#===============================

#CROSS_COMPILE  ?=

 

#==============================

# add by xwc

# 2010-4-15

CROSS_COMPILE   ?= arm-linux-

#==============================

2.2 ~/.bashrc 修改
为了能够更方便的使用arm-gcc交叉编译器,将其加入到Path中,可以利用修改.bashrc的方式:

export PATH=$PATH:/usr/local/arm/4.3.2/bin

然后source .bashrc 一下,或者重新登录就可以了。这样就没有必要再Makefile中指定全局的路径。

2.3 时钟配置
对应于arch/arm/mach-s3c2440/mach-smdk2440.c

S3c24xx_init_clocks(16934400);

改为:

S3c24xx_init_clocks(12000000);

这没什么说的,直接按照张老师的ppt改一下就可以了,要不然,时钟频率设置不对,超级终端中会出现乱码

2.4 分区信息修改
分区的信息要保持跟VIVI中一致,其实理论上说,不保持一致也是OK的,不过为了防止意外,最好还是copy一下。

修改 arch/arm/plat-s3c24xx/common-smdk.c 文件

 

 

 

 

static struct mtd_partition smdk_default_nand_part[] = {

 

        /*

          add by xwc

          2010-04-15

         */

 

    [0] = {

        .name   = "supervivi",

        .size   = 0x00030000,

        .offset = 0,

    },

    [1] = {

        .name   = "kernel",

        .offset = 0x00050000,

        .size   = 0x00200000,

    },

    [2] = {

        .name   = "root",

        .offset = 0x00250000,

        .size   = 0x03dac000,

    }

 

};

 

 

2.5 禁用software ECC 校验
修改 drivers/mtd/nand/s3c2410.c

 

    else {

        //chip->ecc.mode        = NAND_ECC_SOFT;

        /*

         * add by xwc

         * 2010-4-15

         */

        chip->ecc.mode      = NAND_ECC_NONE;

}

 

2.6      配置内核选项
这里也是make menuconfig 和vivi的menuconfig差不多,当然这样说可能不太对,我记得好像meke menuconfig这种模式最早就是用在linux kernel中的。这里配置的选项比较多,我是依据自己的经验勾选了一些,除了跟s3c2440非常相关的一些选项之外,其余的选项我做了最精简的配置,主要是为了减少编译的时间,和减小编译后kernel的大小。

2.7      做实验过程中遇到的问题
主要有2个方面:

一个是mach_type的修改,可以不用改成782,而是使用默认的与vivi一致的就OK,不过这样的话有一个问题,就是在vivi中选择boot the kernel的时候启动不起来,如果直接启动的话,应该是没有任何问题。

另一个是我最开始kernel的选项选的比较多,最后编出来的zImage 大于2M,烧不上去,就把kernel精简了一下,后来想了一下,可以增大kernel分区。

3. DM9000网卡驱动移植
3.1 修改DM9000使用的资源列表
这部分主要集中在arch/arm/plat-s3c24x/comman-smdk.c中

修改方式如下,

1.       头文件,加上

#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)

#include <linux/dm9000.h>

#endif

 

2.       然后修改s3c_dm9k_resource

static struct resource s3c_dm9k_resource[] = {

 [0] = {

     .start = S3C2410_CS4,           //0x20000000, base address(band)

     .end   = S3C2410_CS4+3,

     .flags = IORESOURCE_MEM,

 },

 [1] = {

     .start = S3C2410_CS4 + 4,    //0x20000004

     .end   = S3C2410_CS4 + 4 + 3,

     .flags = IORESOURCE_MEM,

 },

 [2] = {

     .start = IRQ_EINT7,//EINT7 pin

     .end   = IRQ_EINT7,

     .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,

 }

 

};

主要应该注意的是BANK4基地址为0x20000000,也就是S3C2410_CS4

3.       修改DM9000与开发板相关的数据,指定访问DM9000时,数据位宽为16

 

static struct dm9000_plat_data s3c_dm9k_platdata = {

 .flags  = DM9000_PLATF_16BITONLY,

};

 

static struct platform_device s3c_device_dm9k = {

 .name  = "dm9000",

 .id  = 0,

 .num_resources = ARRAY_SIZE(s3c_dm9k_resource),

 .resource = s3c_dm9k_resource,

 .dev  = {

  .platform_data = &s3c_dm9k_platdata,

 }

};

4. 在smdk_devs结构体中添加以下代码:

#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
 &s3c_device_dm9k,
#endif

 

3.2设置dm9000的mac地址
主要是修改 drivers/net/dm9000.c这个文件

 

在dm9000_probe函数中的变量声明之后添加以下代码:

#if defined(CONFIG_ARCH_S3C2410)

 unsigned int oldval_bwscon;

 unsigned int oldval_bankcon4;

#endif

在dev_dbg(&pdev->dev, "dm9000_probe()/n");语句之后添加以下代码:

#if defined(CONFIG_ARCH_S3C2410)

 oldval_bwscon=*((volatile unsigned int *)S3C2410_BWSCON);

 *((volatile unsigned int *)S3C2410_BWSCON)=(oldval_bwscon & ~(3<<16))| S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;

oldval_bankcon4=*((volatile unsigned int *)S3C2410_BANKCON4);

*((volatile unsigned int *)S3C2410_BANKCON4)=0x1f7c;

#endif

将platform_set_drvdata(pdev, ndev);之前的if判断语句改为:

if (!is_valid_ether_addr(ndev->dev_addr))

 {

  dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "

"set using ifconfig/n", ndev->name);

  #if defined(CONFIG_ARCH_S3C2410)

  printk("Now use the default MAC address: 08:90:90:90:90:90/n");

  ndev->dev_addr[0]=0x08;

  ndev->dev_addr[1]=0x90;

  ndev->dev_addr[2]=0x90;

  ndev->dev_addr[3]=0x90;

  ndev->dev_addr[4]=0x90;

  ndev->dev_addr[5]=0x90;

  #endif

 }

在dev_err(db->dev, "not found (%d)./n", ret);之后添加以下代码:

#if defined(CONFIG_ARCH_S3C2410)

 *((volatile unsigned int *)S3C2410_BWSCON)=oldval_bwscon;

 *((volatile unsigned int *)S3C2410_BWSCON)=oldval_bankcon4;

#endif

这里主要参考了网上的设置,选择指定mac地址,应该是用默认的也是没有问题的。(猜测,个人没有验证)

3.3配置内核
启动kernel对于DM9000的支持

Device Drivers --->

  Network device support --->

    [*] Network device support --->

      Ethernet (10 or 100Mbit) --->

        <*> DM9000 support

3.4设置ip,netmast,gateway,ping测试
配置的命令比较简单,如下:

/ $ cd sbin

/sbin $ ifconfig lo up

/sbin $ ifconfig eth0 10.131.250.65 netmask 255.255.255.0 up

/sbin $ route add default gw 10.131.250.1

/sbin $ inetd

 

然后ping一下,ping通就OK

3.5      做实验过程中遇到的问题
1.       最开始的时候gw没有设置好,所以ping外网ping不通

2.       我有一个同学没有设置gw就可以直接ping通外网,后来查了一下,发现时netmask设置成了 255.0.0.0,这样,很显然,只要是10网段都没有问题

3.       网线问题,由于我自己使用的网线不是太好,所以明明所有的东西都配好了,就是ping 不通


第一个包返回时间很长就是因为网线不好,后面的我自己拿手按住就正常了

4. Yaff2文件系统移植
4.1 内核增加yaffs2支持
         下载最新的yaffs2源代码,张老师给的源代码与2.6.29不匹配

         执行 ./patch-ker.sh c /2440/linux-2.6.29

 

上面命令完成下面三件事情

(1)修改内核fs/Kconfig   增加一行:source "fs/yaffs2/Kconfig"

(2)修改内核fs/Kconfig

   增加一行:ojb-$(CONFIG_YAFFS_FS) +=yaffs2/

(3)在内核fs/目录下创建yaffs2目录

   将yaffs2源码目录下面的Makefile.kernel文件复制为内核fs/yaffs2/Makefie;

   将yaffs2 源码目录的Kconfig文件复制到内核fs/yaffs2目录下;

   将yaffs2源码目录下的*.c *.h文件复制到内核fs/yaffs2目录下.

 

然后make menuconfig 添加支持

File systems   --->

         Miscellaneous filesystems --->  

                    <*>YAFFS2 file system support

 

4.2 创建yaffs文件系统
这部分主要参考了张老师给的材料,做的过程比较顺利,大概过程如下

1.  创建必须的文件夹及设备文件

# mkdir rootfs

# cd rootfs

# mkdir bin dev etc lib mnt proc sbin sys root

# mkdir  /etc/var

# mkdir  /etc/tmp

 

2. 创建设备文件系统

# mknod -m 660 dev/console c 5 1

# mknod -m 660 dev/null        c 1 3

 

3. 建立动态运行库

由于linux只安装上了arm-linux-gcc 4.3.2没有glibc的库文件,只好把友善之臂提供的
yaffs2文件系统下的lib文件拷贝过来。

 

4. 交叉编译busybox

解压缩tar -zxf busybox1.13.3.tar
解压后修改Makefile,指明交叉编译器:

ARCH             ?= arm

    CROSS_COMPILE    ?= arm-linux-

5.执行make CONFIG_PREFIX=/2440/rootfs install

在/2440/rootfs目录下生成sbin,usr目录和linuxrc文件

6.创建etc目录下文件

在rootfs/etc目录下创建一个inittab文件

内容如下:

# /etc/inittab

::sysinit:/etc/init.d/rcS

s3c2410_serial0::askfirst:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a -r

创建etc/init.d/rcS文件

#!/bin/sh

ifconfig eth0 192.168.1.17

mount –a

mkdir /dev/pts

mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev –s

最后还要改变它的属性使它能够执行。

chmod +x etc/init.d/rcS

创建etc/fstab文件

#device        mount-point        type        options        dump        fack 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

7.构建其他目录

mkdir proc mnt tmp sys root

8.使用mkyaffsimgae命令生成yaffs映像文件

mkyaffsimage rootfs rootfs.yaffs

9.通过supervivi将内核映像zImage和rootfs.yaffs下载到开发板上

 

4.3 遇到的问题
因为资料上很详细,所以做这部分移植很顺利,并没有出现什么问题,唯一的一个问题就是用yaffs2给kernel打patch之后,kernel一直编不过,当时查代码查了好长时间,发现确实存在数据结构没有定义的情况,于是到网上下载了一个最新的版本,然后就没有问题了。

5. NFS 文件系统server端架设
5.1 server 设置方法
         我把nfsserver搭建在arch-linux上,这是我自己实验室的机器,因为nfs我自己在实验室一直在用,所以,这部分问题不大,主要是修改/etc/exports这个文件,添加诸如

/nfs *(rw,sync)的语句。注意一下路径和权限设置对就可以了。这里需要注意的就是要起相关的服务,像RPC service,nfs service,portmap等,这个在不同系统的linux版本上稍微有些不同,需要注意。


这里需要注意,(rw,sync)中间一定不能有空格,否则会报格式不正确。

5.2遇到的问题
         这部分没遇到什么问题,因为自己的机器上本来就有nfs server,各项服务也有起着,所以比较顺利。

6. NFS文件系统 client 端设置
6.1 client 端设置方法
         首先肯定要启动kernel对nfs的支持,通过make menuconfig,配置,上文已经多次提到,具体的方法在此就不赘余,具体的配置脚本是 mount –o nolock 10.131.251.151:/nfs

6.2遇到的问题
         遇到的问题主要是脚本的参数上,我以前在自己机器上mount的时候都没有用过nolock这个参数,所以最开始的时候一直挂不上,后来查了下资料,加上去就OK了。

7. 从NFS 启动
7.1 设置方法
         其实nfs系统挂载成功之后,如果要从nfs启动,那就只是启动参数上设置的问题了,只要设置对了,就OK,在实验室做项目的时候,由于要进行kernel的更改,开发,经常要重启机器,于是我们也采用netboot的方法,不过我们是把kernel放在远端,然后启动的时候下载到本地。

         具体的启动参数设置如下:

linux_cmd_line

"console=ttySAC0 root=nfs nfsroot=10.131.251.151:/nfs

ip=10.131.250.65:10.131.251.151:10.131.250.1:255.255.255.0:ppi-151:eth0:off init=/linuxrc"

其中 设置根文件系统启动方式为NFS方式,10.131.251.151为主机地址,/nfs为根文件系统路径 , 10.131.250.65是开发板ip地址,10.131.250.1是主机网关地址,255.255.255.0是子网掩码,ppi-151是主机名称,eth0是网卡, init=

设置为文件系统启动执行根目录下的初始化文件。

7.2 遇到的问题
         主要是启动的参数,参数设置对了问题就不大。

8. 修改VIVI param save 无法保存参数bug
         这个bug其实修改起来比较简单,我修改这个bug的过程也比较简单,因为,我发现vivi make menuconfig的时候的参数很少,于是我就一个一个看下来,后来发现有private data,于是打开,发现有支持use user-define parameter block 这个选项,选上,果然就可以保存了。

 


9. 感想,收获以及对课程的建议
在做lab1的过程中,收获颇多,

         首先,就是对嵌入式系统有了一个大致的了解,以前一直听说烧板子,烧板子,但是就是不明白具体是怎么烧的,现在自己做了一把,豁然开朗。而且对加深PC机的了解也有很大的帮助,因为我以前也没有重新烧制BIOS,装完系统后也没有更改过bootloader,对磁盘进行分区也都是在装系统的时候一并完成,并不了解具体的过程。现在做完lab1,对很多事情都有了清晰的了解,包括bootloader是怎么烧制的,系统启动的时候bootloader是如何工作的,bootloader是如何把kernel加载进系统,并且把控制权转交给kernel。再有,就是对磁盘分区具体做了哪些工作,文件系统具体是怎么建立起来的,以及文件系统在kernel启动时的作用,等等。这些都对我有极大的帮助。

         做lab1的过程中,感触比较深的就是,要多做探索,因为本来嵌入式开发对我而言就是一个全新的领域,所以要多探索,才能多有收获。

         比如说mach_type, 张老师上课的时候说必须要改一下,那么我就自己试验了一下,发现如果不修改,只要kernel里面的设置和vivi里面的设置一样,就都可以启动起来。不过我又继续研究发现,如果不修改的话,用vivi 直接boot kernel会起不来,报mach_type不匹配的错误。

         第二点就是要细心,就比如说修复private param 不能保存的问题,因为我一开始就很自己的研究vivi的menuconfig设置,所以很快就发现了这个问题所在,从根本上解决了。

         再有,就是,做lab的过程是跟已经掌握的知识相互印证的过程。因为毕竟都是linux操作系统,很多东西都是相似的,做lab的过程就相当于是对已经掌握的知识做了一个补足,提升。使我对很多东西的了解更加深入了。