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

2019-07-13 00:35发布

                                   嵌入式系统开发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 #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的过程就相当于是对已经掌握的知识做了一个补足,提升。使我对很多东西的了解更加深入了。