摘要:本文旨在将 arm-linux 在 skyeye 上搭建起来,并在 arm-linux 上能成功 mount NFS 为目标, 最终我们能在 arm-linux 里运行我们自己的应用程序. 其实在 skyeye 上移植 arm-linux 并非难事,网上也有不少资料, 只是大都遗漏细节, 以致细微之处卡壳,所以本文力求详实清析, 希望能对大家有点用处。<br />一 前言<br />本文旨在将 arm-linux 在 skyeye 上搭建起来,并在 arm-linux 上能成功 mount NFS 为目标, 最终我们能在 arm-linux 里运行我们自己的应用程序. 其实在 skyeye 上移植 arm-linux 并非难事,网上也有不少资料, 只是大都遗漏细节, 以致细微之处卡壳,所以本文力求详实清析, 希望能对大家有点用处。<br />二 安装 Skyeye<br />我们选定 skyeye 的 1.2.4 这个版本, 为了能让它上面运行的 arm-linx 能挂接 NFS,我们需要修改 device/net/dev_net_cs8900a.c (修改后的文件在附件里), 再编译 skyeye。操作如下, 先解压源码包:<br />#tar xzf skyeye-1.2.4_Rel.tar.gz<br />#cd skyeye-1.2.4<br />请用附件里的 dev_net_cs8900a.c 替换 device/net/dev_net_cs8900a.c 后执行编译:<br />#make NO_DBCT=1 NO_BFD=1<br />编译完后生成的 skyeye 在 binary 下,将其拷贝至 /usr/local/bin/ 下:<br />#cp binary/skyeye /usr/local/bin<br />三 编译内核<br />我们选定 linux-2.6.14.tar.bz2 这个版本, 交叉编译器用 arm-linux-gcc 3.4.1 (对2.6 内核用 3.4 以下的版本编译经常会出现问题)。操作步骤如下:<br />1.假定内核源码包在 /root 下, 首先解压源码:<br />#cd /root<br />#tar xjf linux-2.6.14.tar.bz2<br />2.进入内核目录:<br />#cd linux-2.6.14<br />修改此目录下的 Makefile, 将<br />ARCH ?= $(SUBARCH)<br />CROSS_COMPILE ?=<br />改为<br />ARCH ?= arm<br />CROSS_COMPILE ?= /usr/local/arm/3.4.1/bin/arm-linux-<br />3.生成默认的内核配置文件(for s3c2410):<br />#make smdk2410_defconfig<br />4.为内核添加 cs8900(见附件) 网卡驱动,以支持 NFS 挂接:<br />(1)复制 cs8900 驱动到 drivers/net/arm 目录<br />#cp cs8900.c drivers/net/arm<br />#cp cs8900.h drivers/net/arm<br />(2)修改 drivers/net/arm 目录下的 Kconfig 文件, 在最后添加:<br />config arm_CS8900<br />tristate "CS8900 support"<br />depends on NET_ETHERNET && arm && ARCH_SMDK2410<br />help<br />Support for CS8900A chipset based Ethernet cards. If you have a network<br />(Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available<br />from as well as .To compile this driver as a module, choose M here and read.<br />The module will be called cs8900.o.<br />注:在运行 make menuconfig 命令时就会出现: [ ] CS8900 support 这一选项<br />(3)修改 drivers/net/arm 目录下的Makefile文件,在最后添加如下内容:<br />obj-$(CONFIG_arm_CS8900) += cs8900.o<br />注:2.6 版本内核的 Makefile 也与 2.4 的有所不同, 添加以上语句, 就会使内核在编译的时候根据配置将cs8900A的驱动程序以模块或静态的方式编译到内核当中。<br />(4)修改 arch/arm/mach-s3c2410/mach-smdk2410.c 在此文件中找到 smdk2410_iodesc[] 结构数组,添加如下如下内容:<br />{vSMDK2410_ETH_IO,pSMDK2410_ETH_IO, SZ_1M, MT_DEVICE}<br />修改之后变成:<br />static struct map_desc smdk2410_iodesc[] __initdata = {<br /><br />{vSMDK2410_ETH_IO,pSMDK2410_ETH_IO, SZ_1M, MT_DEVICE}<br />};<br />并且添加一个头文件引用:<br />#include <br />(5)在 include/asm-arm/arch-s3c2410 目录下创建文件 smdk2410.h<br />#ifndef _INCLUDE_SMDK2410_H_<br />#define _INCLUDE_SMDK2410_H_<br />#include <br />#define pSMDK2410_ETH_IO 0x19000000<br />#define vSMDK2410_ETH_IO 0xE0000000<br />#define SMDK2410_ETH_IRQ IRQ_EINT9<br />#endif<br />5.参照 http://skyeye.wiki.sourceforge.net/Linux 修改内核文件<br />修改 include/asm-arm/arch-s3c2410/map.h<br />#define S3C2410_CS6 (0x30000000UL)<br />to<br />#define S3C2410_CS6 (0xC0000000UL)<br />修改 include/asm-arm/arch-s3c2410/memory.h<br />#define PHYS_OFFSET (0x30000000UL)<br />to<br />#define PHYS_OFFSET (0xC0000000UL)<br /><br />6.裁剪/定制内核<br />(1)#make menuconfig<br />(2)设置内核启动参数<br />Boot options ---> Default kernel command string:<br />mem=32M console=ttySAC0 root=/dev/ram initrd=0xc0800000,0x00800000 ramdisk_size=8192 rw<br />(3)设置 CS8900 的支持<br />Device Drivers ---><br />Network device support ---><br />Ethernet (10 or 100Mbit) ---> [] CS8900 support<br />选中 CS8900 support<br />(4)设置 initrd 的支持<br />Device Drivers ---> Block devices ---> [ ] RAM disk support<br />下面三项必须设置:<br />1.确保 RAM disk support 被选中<br />2.相应的将默认的 (4096) Default RAM disk size (kbytes) 改成 8192;<br />3.Initial RAM disk (initrd) support 一定要选中, 切记!<br />(5)设置 NFS 的支持<br />File systems ---> Network File Systems ---><br />至少确保下面两项被选中:<br /> NFS file system support<br /> Provide NFSv3 client support<br />(6)设置 ROM file system 的支持<br />File systems ---> ROM file system support<br />确保 ROM file system support 被选中<br />(7)设置 ext2 的支持<br />File systems ---> Second extended fs support<br />确保 Second extended fs support 被选中<br />7.编译<br />#make<br />编译完成后会有个 vmlinux 在当前目录下, 这就是我们要的 arm-linux 内核了<br /><br />#P# 四 制作根文件系统 initrd.img(Initial RAM disk)<br />我们选定 busybox-1.9.2.tar.bz2 这个版本, 以静态方式编译, 即生成的 busybox 不需要共享库的支持就能运行。这样做我们就不需要布署程序库了。缺点是自己写的 arm-linux 程序在这个根文件系统中是不能运行的,因为缺少共享程序库的支持。不过别担心,我们会解决这个问题的,稍后你将看到,通过在 arm-linux 里以挂接 NFS 的方式, 将宿主机的 arm-linux-gcc 编译器的库文件挂到 arm-linux 的 /lib 下, 就可完美的运行我们自己的程序了。好,一步步来,先来看看根文件系统的制作:<br />1.解压源码包<br />#tar xjf busybox-1.9.2.tar.bz2<br />#cd busybox-1.9.2<br />2.修改 Makefile, 将<br />ARCH ?= $(SUBARCH)<br />CROSS_COMPILE ?=<br />改为<br />ARCH ?= arm<br />CROSS_COMPILE ?= /usr/local/arm/3.3.2/bin/arm-linux-<br />注:这个版本的 busybox 用 3.4.1 的 arm-linux-gcc 编译有些问题, 用 3.3.2 版则可顺利编译。<br />3.定制 busybox<br />#make menuconfig<br />设置静态编译方式<br />Busybox Settings ---> Build Options ---> Build BusyBox as a static binary (no shared libs)<br />确保 Build BusyBox as a static binary (no shared libs) 被选中<br />4.执行 make 编译<br />#make<br />编译出错, 信息如下:<br />applets/applets.c:15:2: warning: #warning Static linking against glibc produces buggy executables<br />applets/applets.c:16:2: warning: #warning (glibc does not cope well with ld --gc-sections).<br />applets/applets.c:17:2: warning: #warning See sources.redhat.com/bugzilla/show_bug.cgi?id=3400<br />applets/applets.c:18:2: warning: #warning Note that glibc is unsuitable for static linking anyway.<br />applets/applets.c:19:2: warning: #warning If you still want to do it, remove -Wl,--gc-sections<br />applets/applets.c:20:2: warning: #warning from scripts/trylink and remove this warning.<br />applets/applets.c:21:2: error: #error Aborting compilation.<br />make[1]: *** [applets/applets.o] Error 1<br />按照提示,修改 scripts/trylink, 将此文件里面有 -Wl,--gc-sections 的行都删除掉,<br />然后重新 make<br />#make<br />还是出错, 信息如下:<br />root@hukq-desktop:~/busybox/busybox-1.9.2# make<br />CC applets/applets.o<br />applets/applets.c:15:2: warning: #warning Static linking against glibc produces buggy executables<br />applets/applets.c:16:2: warning: #warning (glibc does not cope well with ld --gc-sections).<br />applets/applets.c:17:2: warning: #warning See sources.redhat.com/bugzilla/show_bug.cgi?id=3400<br />applets/applets.c:18:2: warning: #warning Note that glibc is unsuitable for static linking anyway.<br />applets/applets.c:19:2: warning: #warning If you still want to do it, remove -Wl,--gc-sections<br />applets/applets.c:20:2: warning: #warning from scripts/trylink and remove this warning.<br />applets/applets.c:21:2: error: #error Aborting compilation.<br />make[1]: *** [applets/applets.o] Error 1<br />make: *** [applets] Error 2<br />修改文件 applets/applets.c 第 21 行, 将<br />#error Aborting compilation.<br />注释掉:<br />执行 make 重新编译<br />#make<br />编译通过, busybox 被生成了, 然后执行<br />#make install<br />busybox 就被安装到默认的临时目录 _install 下了<br />5.制作 initrd.img<br />有了 busybox 后制作 initrd.img 就容易多了,只是说起来比较烦琐。以命令演示如下:<br />创建映像文件并挂到 initrd 目录<br />#mkdir initrd<br />#dd if=/dev/zero of=initrd.img bs=1k count=4096<br />#mke2fs -F -v initrd.img<br />#mount -o loop initrd.img initrd<br />将添加 busybox 到此映像文件<br />#cd initrd<br />#cp -r ../_install/* .<br />#创建必要的目录<br />#mkdir proc lib etc dev root home var tmp<br />#chmod 777 tmp<br />建立设备文件<br />#cd dev<br />#mknod -m 644 console c 5 1<br />#mknod -m 644 null c 1 3<br />#mknod -m 640 ram b 1 1<br />#mknod -m 644 mem c 1 1<br />#cd ..<br />创建脚本文件 etc/inittab, 内容如下:<br />::sysinit:/etc/init.d/rcS<br />::askfirst:-/bin/sh<br />::restart:/sbin/init<br />::ctrlaltdel:/sbin/reboot<br />::shutdown:/bin/umount -a -r<br />::shutdown:/sbin/swapoff -a<br />设置此脚本执行权限<br />#chmod 644 etc/inittab<br />创建脚本文件 etc/init.d/rcS, 内容如下:<br />#!/bin/sh<br />/bin/mount -t proc none /proc<br />/sbin/ifconfig lo 127.0.0.1 up<br />/sbin/ifconfig eth0 10.0.0.2 netmask 255.0.0.0 up<br />hostname skyeye<br />mkdir /var/tmp<br />mkdir /var/log<br />mkdir /var/run<br />mkdir /var/lock<br />/bin/ash<br />设置此脚本执行权限<br />#chmod 755 etc/init.d/rcS<br />最后一步,执行实际的写入操作,生成 initrd.img<br />cd ..<br />umount initrd<br />五 运行 arm-linux<br />现在我们有了内核 vmlinux, 映像文件 initrd.img, 模拟程序 skyeye, 我们还需要一个<br />配置文件 skyeye.conf 进行 arm-linux 的仿真运行。<br />#mkdir /root/test<br />#cd /root/test<br />将 vmlinux, initrd.img 都拷贝到此目录, 在此目录下建立一个 skyeye 的配制文件<br />skyeye.conf, 文件内容如下:<br />cpu: arm920t<br />mach: s3c2410x<br /># physical memory<br />mem_bank: map=M, type=RW, addr=0xc0000000, size=0x00800000<br />mem_bank: map=M, type=RW, addr=0xc0800000, size=0x00800000, file=./initrd.img<br />mem_bank: map=M, type=RW, addr=0xc1000000, size=0x01000000<br /># all peripherals I/O mapping area<br />mem_bank: map=I, type=RW, addr=0x48000000, size=0x20000000<br />mem_bank: map=I, type=RW, addr=0x19000300, size=0x00000020<br />net: type=cs8900a, base=0x19000300, size=0x20,int=9, mac=0:4:3:2:1:f, ethmod=tuntap, hostip=10.0.0.1<br />lcd: type=s3c2410x, mod=gtk<br />#dbct:state=on<br /><br />好了,试运行吧:<br />skyeye -e vmlinux<br />看到你的 arm-linux 运行了吗 :-)<br /><br />#P# 六 在 arm-linux 里运行我们自己的程序<br />现在 arm-linux 在 skyeye 上跑起来了, 我们能运行里面的命令, 但这些都是 busybox的,是系统程序。怎样才能在 arm-linux 里运行我们自己的程序呢? 有两种方案,我们不妨讨论一下,择优而录之:<br />1.在制作根文件系统 initrd.img 的时候把我们自己的程序加进去,比如放在 /usr/bin 里目录下,然后重新生成 initrd.img,并用这个新的根文件系统来运行 arm-linux。其实这是我们的产品在 arm-linux 上发布的最终方式,但这有个缺点: 在产品开发/调试阶段这么做比较麻烦,每修改一次代码就得 build 一次根文件系统。<br />2.利用挂接 NFS(Network file system) 的方式,我们访问/执行一个网络文件系统上的文件就像它在本地一样,显然这么做能避免第一种方案的弊端! 如何实现呢? 随我来:<br />(1)在 arm-linux 的宿主机里配置 NFS Server (我用是 Ubuntu,而且是在 vmware 里)<br />#apt-get install nfs-kernel-server<br />#apt-get install nfs-common<br />(2)编辑文件 /etc/exports, 内容如下(具体需求由你而定):<br />/test *(rw,sync,no_root_squash)<br />/usr/local/arm/3.3.2/lib *(ro,sync,no_root_squash)<br />(3)配置宿主机的 ip<br />#ifconfig eth1 down<br />#ifconfig eth1 10.0.0.1 netmask 255.0.0.0 up<br />注:你的可能是 eth0, 另外 ip 地址你也可自己定义,只要能和 arm-liux 通信<br />(4)重启 nfs server<br />#/usr/sbin/exportfs<br />#/etc/init.d/nfs-kernel-server restart<br />#/etc/init.d/portmap restart<br />(5)在 skyeye 运行 arm-linux,为其配置 ip<br />#ifconfig lo down<br />#ifconfig eth0 down<br />#ifconfig lo 127.0.0.1 up<br />#ifconfig eth0 10.0.0.2 netmask 255.0.0.0 up<br />注:可将这几个命令加到 rcS 脚本里,让 arm-linux 启动时帮你做<br />(6)在 skyeye 上运行 arm-linux,演示 nfs 挂接<br />#mount -o nolock 10.0.0.1:/usr/local/arm/3.3.2/lib /lib<br />#export LD_LIBRARY_PATH=/lib<br />#mount -o nolock 10.0.0.1:/test /tmp<br />在宿主机的 /test 下建立文件 hello.c,用 arm-linux-gcc 3.3.2 编译<br />#cd /test<br />#arm-linux-gcc -o hello hello.c<br />在 arm-linux 的 /tmp 下看看,是不是有 hello.c 和 hello 这两个文件了? 试着运行看看:<br />#cd /tmp<br />#./hello<br />注:为了确认 arm-linux 能和宿主机通信, 可尝试以下手段:<br />(1)在宿主机上 ping 你的 arm-linux<br />#ping 10.0.0.2 -c 2<br />(2)在 arm-linux 里 ping 你的宿主机<br />#ping 10.0.0.1 -c 2<br />(3)如果相互都 ping 不通过,可这样做:<br />重新设置一下 arm-linux 的网络:<br />#ifconfig eth0 down<br />#ifconfig eth0 up<br />再重新设置一下宿主机的网络:<br />#ifconfig eth1 down<br />#ifconfig eth1 up<br />然后再像上一步那样,相互 ping 对方,直至 ping 通为止。 |
|