Linux SkyEye安装交叉编译器

ARM 30浏览

Linux SkyEye对于电脑使用的玩家的常用软件,然后我就学习及深入的研究Linux SkyEye,在这里和大家一起探讨Linux
SkyEye的使用方法,希望对大家有用。Linux
SkyEye是一个可以运行嵌入式操作系统的硬件仿真工具,这样就可以在没有硬件条件下来进行嵌入式系统的开发。

以下操作均在Fedora Core 1.0里通过。Linux SkyEye项目资源列表http://gro.clinux.org/projects/Linux SkyEye/

1、什么是Linux SkyEye?

Linux SkyEye是开源软件的一个项目,Linux
SkyEye的目标是在Linux和Windows操作系统里提供一个完全的仿真环境。Linux
SkyEye仿真环境相当于一个嵌入式计算机系统,你可以在Linux
SkyEye里运行一些嵌入式Linux操作系统,如ARMLinux,uClinux,uc/OS-II(ucos-ii)等,并能分析和调试它们的源
代码。

如果你想知道关于Linux SkyEye和嵌入式系统更详细的信息,请访问下面的站点:www.Linux SkyEye.org
http://www.Linux SkyEye.org/index_cn.html通过Linux
SkyEye能仿真下面的硬件:CPU核心:ARM7TDMI, ARM720T, ARM9, StrongARM, XScaleCPU:
Atmel AT91/X40, Cirrus CIRRUS LOGIC EP7312, Intel SA1100/SA1110, Intel
XScale PXA 250/255, CS89712, samsung 4510B,


  1. samsung 44B0(还不全)内存: RAM, ROM, Flash周边设备:   
  2. Timer, UART, ne2k网络芯片, LCD, 触摸屏等目前能在Linux SkyEye上运行下面的操作系统和系统软件:  
  3. uC/OSII-2.5.x(支持网络)  
  4. uClinux(基于Linux2.4.x内核, 支持网络)  
  5. ARM Linux 2.4.x/2.6.x  
  6. lwIP on uC/OSII  
  7. 基于uC/OSII, uClinux, ARM Linux的应用程序 

2.Linux SkyEye可以做什么事情?
1. 通过Linux SkyEye可以帮助促进嵌入式系统的学习,在不需要额外硬件的情况下学习和分析uclinux操作系统和其它嵌入式操作系统,如ucosII等。
2. Linux SkyEye可用于嵌入式系统的教学。
3. 希望通过Linux SkyEye促进操作系统的研究,如ucosII,uclinux+RTAI,uclinux2.5.x等。
4. 可以基于Linux SkyEye进行仿真特定硬件模块的研究。
5. Linux SkyEye可以作为嵌入式集成开发环境开发嵌入式系统(当然需要对Linux SkyEye做大量的工作)。
注:引自陈渝《Linux SkyEye Project FAQ》

3、安装Linux SkyEye

到http://gro.clinux.org/projects/Linux SkyEye/下载Linux
SkyEye-0.7.0.tar.bz2包:tar jxvf Linux SkyEye-v0.7.0.tar.bz2进入解压后的Linux
SkyEye目录,如果Linux SkyEye的版本低于0.6.0,则运行下面的命令:/configure --target=arm-elf
--prefix=/usr/local --without-gtk-prefix --without-gtk-exec-prefix
--disable-gtktest如果Linux SkyEye的版本高于0.6.0,则运行下面的命令:/configure
--target=arm-elf --prefix=/usr/local

接下来执行:


  1. make  
  2. make install安装完成后执行Linux SkyEye 

注意:


  1. a.如果你使用的是Mandrake Linux发行版,那么你在编译Linux SkyEye时遇到错误,并且错误与readline, ncurse, termcap等有关,你可以试试下面的方法:ln -s /usr/include/ncurses/termcap.h /usr/local/include/termcap.h接着再make和make install看能否成功!  
  2. b.如果你的Linux发行版是Debian Linux,那么不要使用gcc 2.95或是gcc 3.0,请使用gcc 3.2+  
  3. c.gcc的版本要在2.96或以上  
  4. d.如果Linux SkyEye的版本大于0.6.0,那么使用LCD仿真需要在Linux系统里安装GTK软件。 

4、安装arm-elf交叉编译器

下载arm-elf-tools-20030314.shftp://166.111.68.183/pub/embed/uclinux
/soft/tools/arm或到ftp://166.111.8.229/OS/Embeded执行:chmod a+x
arm-elf-tools-20030314.sh然后:./arm-elf-tools-20030314.sh ls
/usr/local/bin/你应能看到以arm-elf开头的可执行文件,其中arm-elf-gcc就是用来编译你目标平台的编译器的,当然还有一
些小工具,后面将一一讲来。

5、测试你的arm-elf-gcc编译器

先写一个小程序hello.cPHP 代码:#include <stdio.h>


  1. int main(void)  
  2. {  
  3. int i;  
  4. for(
    i

     = 
    0

    ; i 
    <


     
    6


    ; i++){  
  5. printf("
    i

     = %d  ",i);  
  6. printf("Hello, embedded linux!"n");  
  7. return 0;  
  8. }  

然后执行:arm-elf-gcc -Wl,-elf2flt -o hello
hello.c-elf2flt参数是将elf文件格式转为flat文件格式,这个工具是在你安装交叉编译器产生的。或者你可以写个Makefile文
件,执行:make这里是我的Makefile文件,仅供参考:PHP 代码:# begin


  1. CC

     = 
    arm

    -elf-gcc  
  2. CFLAGS

     = -D__PIC__ -fpic -msingle-pic-base -O2 -pipe -Wall -g  
  3. LDFLAGS

     = -Wl,-elf2flt  
  4. LIBS

     =  
  5. OBJS

     = hello.o  
  6. all:hello  
  7. hello:  $(OBJS)  
  8. $(CC) $(CFLAGS) $(LDFLAGS) -o hello $(OBJS) $(LIBS)  
  9. clean:  
  10. rm -rf *.o *.elf *.gdb hello  
  11. # end  

如果编译通过,就会产生hello可执行文件。用下面的命令:file hello你会发现,它是BFLT(binary FLAT),你目标平台所支持的文件格式。

6、执行你的hello程序

这里,我们将借助genromfs这个小工具来完成测试,这个工具就是你在安装交叉编译器时产生的,你可以直接使用它。到http://gro.clinux.org/projects/skyey...-1.0.4.tar.bz2包:


  1. tar jxvf Linux SkyEye-binary-testutils-1.0.4.tar.bz2  
  2. cd testsuits/at91/uclinux2(当然你还可以用别的)  
  3. mkdir romfs(建一个目录,后面用)  
  4. mount -o loop boot.rom /mnt/xxx  
  5. cp -r /mnt/xxx/* romfs 

另外,把你编译好的可执行程序拷贝到/romfs/bin目录里,这里就是hello了!genromfs -f boot.rom -d romfs/注:可以用genromfs -h来获得帮助!

OK!执行下面的命令:


  1. Linux SkyEye linux  
  2. (Linux SkyEye)target sim  
  3. (Linux SkyEye)load  
  4. (Linux SkyEye)run  
  5. kernel start..... 

很熟悉了吧。。。cd /binhello可以看到结果了吗?其实到了这一步,你就可以开发自己的程序了!

7、一个应用程序的开发实例

下面介绍的程序主要是完成一个网络应用,网络应用的标准模型是客户机-服务器模型,它的主要执行过程如下:
(1)系统启动服务器执行。服务器完成一些初始化操作,然后进入睡眠状态,等待客户机请求;
(2)在网络的某台机器上,用户执行客户机程序;
(3)客户机进程与服务器进程建立一条连接;
(4)连接建立之后,客户机通过网络向服务器发出请求,请求某种服务;
(5)服务器接收到客户机请求后,根据客户机请求的内容进行相应的处理,然后将处理结果返回;
(6)服务器断开与客户机的连接,继续睡眠,等待其他客户机的请求;

Linux系统中的很多服务器是在系统初启时启动的,如时间服务器、打印服务器、文件传输服务器和电子邮件服务器等。大多数时间这些服务器进程处于睡眠状态,等待客户机的请求。

下面这两个客户机-服务器程序比较简单,主要是对网络客户机-服务器模型的实际运行有大致印象。这个客户机-服务器的操作过程非常简单:客户机与服务器建立连接之后,服务器向客户机返回一条消息。

服务器程序的源代码如下:
PHP 代码:


  1. /* tcpserver.c */  
  2. #include 
    <
    stdlib.h
    >


     
  3. #include 
    <
    stdio.h
    >


     
  4. #include 
    <
    errno.h
    >


     
  5. #include 
    <
    string.h
    >


     
  6. #include 
    <
    netdb.h
    >


     
  7. #include 
    <
    sys


    /types.h
    >


     
  8. #include 
    <
    netinet


    /in.h
    >


     
  9. #include 
    <
    sys


    /socket.h
    >


     
  10. #define WAITBUF 10  
  11.  
  12. int main(int argc, char *argv[])  
  13. {  
  14. int sockfd, new_fd;  
  15. struct sockaddr_in server_addr;  
  16. struct sockaddr_in client_addr;  
  17. unsigned int sin_size, portnumber;  
  18. char hello[]="Hello! Socket communication world!"n";  
  19.  
  20. if(argc != 2)  
  21. {  
  22. fprintf(stderr, "Usage:%s portnumber"a"n", argv[0]);  
  23. exit(1);  
  24. }  
  25.  
  26. if((
    portnumber

     = 
    atoi

    (argv[1])) 
    <


     
    0


    )  
  27. {  
  28. fprintf(stderr, "Usage: %s portnumber error"a"n", argv[0]);  
  29. }  
  30.  
  31. if((
    sockfd

     = 
    socket

    (AF_INET, SOCK_STREAM, 0)) == -1)  
  32. {  
  33. fprintf(stderr, "Socket error:%s"n"a", strerror(errno));  
  34. exit(1);  
  35. }  
  36.  
  37. bzero(&server_addr, sizeof(struct sockaddr_in));  
  38. server_addr.sin_family

     = 
    AF_INET

    ;  
  39.  
  40. server_addr.sin_addr.s_addr

     = 
    htonl

    (INADDR_ANY);  
  41. server_addr.sin_port

     = 
    portnumber

    ;  
  42.  
  43. if(bind(sockfd,(struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)  
  44. {  
  45. fprintf(stderr, "Bind error:%s"n"a", strerror(errno));  
  46. exit(1);  
  47. }  
  48.  
  49. if(listen(sockfd, WAITBUF) == -1)  
  50. {  
  51. fprintf(stderr, "Listen error:%s"n"a", strerror(errno));  
  52. exit(1);  
  53. }  
  54.  
  55. while(1)  
  56. {  
  57. sin_size

     = 
    sizeof

    (struct sockaddr_in);  
  58. if((
    new_fd

     = 
    accept

    (sockfd, (struct sockaddr *)(&client_addr), &sin_size)) == -1)  
  59. {  
  60. fprintf( stderr, "Accept error:%s"n"a", strerror(errno));  
  61. exit(1);  
  62. }  
  63. fprintf(stderr, "Server get connection from %s"n", inet_ntoa(client_addr.sin_addr));  
  64. if(send(new_fd, hello, strlen(hello), 0) == -1)  
  65. {  
  66. fprintf(stderr, "Write Error:%s"n", strerror(errno));  
  67. exit(1);  
  68. }  
  69.  
  70. close(new_fd);  
  71. }  
  72. close(sockfd);  
  73. exit(0);  
  74. }   

给服务器程序写一个Makefile文件,如下:
PHP 代码:


  1. # start  
  2.  
  3. CC

     = 
    arm

    -elf-gcc  
  4.  
  5. CFLAGS

     = -D__PIC__ -fpic -msingle-pic-base -O2 -pipe -Wall -g  
  6. LDFLAGS

     = -Wl,-elf2flt  
  7.  
  8. LIBS

     =  
  9. OBJS

     = tcpserver.o  
  10.  
  11. all:tcpserver  
  12.  
  13. tcpser:  $(OBJS)  
  14. $(CC) $(CFLAGS) $(LDFLAGS) -o tcpserver $(OBJS) $(LIBS)  
  15.  
  16. clean:  
  17. rm -rf *.o *.elf *.gdb hello  
  18.  
  19. # end   
  20.  

客户机程序的源代码如下:
PHP 代码:


  1. /* tcpclient.c */  
  2. #include 
    <
    stdlib.h
    >


     
  3. #include 
    <
    stdio.h
    >


     
  4. #include 
    <
    errno.h
    >


     
  5. #include 
    <
    string.h
    >


     
  6. #include 
    <
    netdb.h
    >


     
  7. #include 
    <
    sys


    /types.h
    >


     
  8. #include 
    <
    netinet


    /in.h
    >


     
  9. #include 
    <
    sys


    /socket.h
    >


     
  10.  
  11. #define RECVBUFSIZE 1024  
  12. int main(int argc, char *argv[])  
  13. {  
  14. int sockfd;  
  15. char buffer[RECVBUFSIZE];  
  16. struct sockaddr_in server_addr;  
  17. int portnumber, nbytes;  
  18. if(argc != 3)  
  19. {  
  20. fprintf(stderr, "Usage:%s hostname portnumber"a"n", argv[0]);  
  21. exit(1);  
  22. }  
  23. if((
    portnumber

    =
    atoi

    (argv[2])) 
    <


     
    0


    )  
  24. {  
  25. fprintf(stderr,"Usage:%s hostname portnumber"a"n", argv[0]);  
  26. exit(1);  
  27. }  
  28. if((
    sockfd

     = 
    socket

    (AF_INET, SOCK_STREAM, 0)) == -1)  
  29. {  
  30. fprintf(stderr, "Socket Error:%s"a"n", strerror(errno));  
  31. exit(1);  
  32. }  
  33. bzero(&server_addr, sizeof(server_addr));  
  34. server_addr.sin_family

     = 
    AF_INET

    ;  
  35. server_addr.sin_port

     = 
    portnumber

    ;  
  36. server_addr.sin_addr.s_addr

     = 
    inet_addr

    (argv[1]);  
  37. if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)  
  38. {  
  39. fprintf(stderr, "Connect Error:%s"a"n", strerror(errno));  
  40. exit(1);  
  41. }  
  42.  
  43. if((
    nbytes

     = 
    recv

    (sockfd, buffer, RECVBUFSIZE, 0)) == -1)  
  44. {  
  45. fprintf(stderr, "Read Error:%s"n", strerror(errno));  
  46. exit(1);  
  47. }  
  48. buffer[nbytes]='"0';  
  49. printf("I have received:%s"n", buffer );  
  50. close(sockfd);  
  51. exit(0);  
  52. }   
  53.  

最后,Linux
SkyEye-binary-testutils-1.1.0.tar.bz2/at91x40/uclinux1包里提取boot.rom,用步聚6中
的方法,把tcpserver程序放在boot.rom的bin目录中在目标板上运行tcpserver 2000在主机上运行./tcpclient
10.0.0.2
2000看看结果!程序的源码的注释因篇幅不在这给出,大家可以参考一些Linux网络编程的书籍,我也会在我的主页上更新一些资料,有需要的朋友可以去
下载!

8、编译并运行uClinux-dist-20030909.tar.gz

到ftp://166.111.68.183/pub/embed/uclinux/soft/或到ftp://166.111.8.229/OS
/Embeded/uclinux/pub/uClinux/dist下载uClinux-dist-20030909.tar.gz假设把它下载到
/usr/src/目录下.

然后依次执行下面的命令:tar zxvf uClinux-dist-20030909.tar.gzv cd
uClinux-dist/在图形方式下可用命令make xconfig或在命令行方式下用命令make menuconfig
vendor/product中选择GDB/ARMulator kernel版本选择2.4然后save and exit

运行下面这两条命:
make dep
make

此时在/usr/src/uClinux-dist/linux-2.4.x目录下会生成可执行文件linux在/usr/src
/uClinux-dist/images/会生成romfs.img等文件在uClinux-dist目录下建立仿真AT91的Linux
SkyEye配置文件Linux SkyEye.conf,内容如下:


  1. cpu: arm7tdmi  
  2. mach: at91  
  3. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x00000000


    size

    =
    0x00004000

     
  4. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x01000000


    size

    =
    0x00400000

     
  5. mem_bank: 
    map

    =
    M


    type

    =
    R


    addr

    =
    0x01400000


    size

    =
    0x00400000


    file

    =
    images

    /romfs.img  
  6. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x02000000


    size

    =
    0x00400000

     
  7. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x02400000


    size

    =
    0x00008000

     
  8. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x04000000


    size

    =
    0x00400000

     
  9. mem_bank: 
    map

    =
    I


    type

    =
    RW


    addr

    =
    0xf0000000


    size

    =
    0x10000000

     

这个时候就可以用Linux SkyEye来调试运行kernel了,在/usr/src/uClinux-dist执行如下命令:


  1. Linux SkyEye linux-2.4.x/linux  
  2. (Linux SkyEye)target sim  
  3. (Linux SkyEye)load  
  4. (Linux SkyEye)run  
  5. kernel start..... 

注意:要在Linux SkyEye.conf所在目录下执行Linux SkyEye linux-2.4.x/linux

9、加入网络功能
a.用root用户进行操作。
b.你要看你的/lib/modules/'uname -r'/kernel/drivers/net/目录里有没有tun.o如果没有的话你就需要编译你的linux内核来获得tun.o了。
c.(1)运行tun设备模块:


  1. #insmod /lib/modules/'uname -r'/kernel/drivers/net/tun.o如果你没有该设备,那你就要用下面的命令来创建它:  
  2. #mkdir /dev/net  
  3. #mknod /dev/net/tun c 10 200 

(2)运行vnet(虚拟集线器)设备模块(这一步不是必需的):获取vnet的源码,然后创建设备:


  1. #mknod /dev/net/vnet c 10 201  
  2. #chmod 666 /dev/net/vnet  
  3.  
  4. 创建vnet.o#make vnet.o插入模块vnet.o#insmod vnet.o进入test目录,用test来测度vnet.o  
  5. #cd test  
  6. #make  
  7. #./testvnet1  

d.配置Linux SkyEye.conf文件


  1. cpu: arm7tdmi  
  2. mach: at91  
  3. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x00000000


    size

    =
    0x00004000

     
  4. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x01000000


    size

    =
    0x00400000

     
  5. mem_bank: 
    map

    =
    M


    type

    =
    R


    addr

    =
    0x01400000


    size

    =
    0x00400000


    file

    =
    images

    /romfs.img  
  6. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x02000000


    size

    =
    0x00400000

     
  7. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x02400000


    size

    =
    0x00008000

     
  8. mem_bank: 
    map

    =
    M


    type

    =
    RW


    addr

    =
    0x04000000


    size

    =
    0x00400000

     
  9. mem_bank: 
    map

    =
    I


    type

    =
    RW


    addr

    =
    0xf0000000


    size

    =
    0x10000000

     
  10. # format: 
    state

    =
    on

    /off 
    mac

    =
    xx

    :xx:xx:xx:xx:xx 
    ethmod

    =
    tuntap

    /vnet 
    hostip

    =
    dd

    .dd.dd.dd  
  11. net: 
    state

    =
    on


    mac

    =
    0

    :4:3:2:1:f, 
    ethmod

    =
    tun


    hostip

    =
    10

    .0.0.1 

下面将对上面的一些参数作下说明:state=on/off意思是仿真的NIC(网络接口板)是有线的还是无线的;mac=仿真适配器的
MAC地址;ethmod=tuntap/vnet在主机环境里使用的虚拟设备;hostip=意思是主机环境与keyeye交互用的IP格式:
state=on/off mac=xx:xx:xx:xx:xx:xx ethmod=tuntap/vnet hostip=dd.dd.dd.dd


  1. For example:  
  2. #set nic info 
    state

    =
    on

    /off 
    mac

    =
    xx

    :xx:xx:xx:xx:xx 
    ethmod

    =
    tuntap

    /vnet 
    hostip

    =
    dd

    .dd.dd.dd  
  3. net: 
    state

    =
    on


    mac

    =
    0

    :4:3:2:1:f, 
    ethmod

    =
    tun


    hostip

    =
    10

    .0.0.1  
  4. 或  
  5. net: 
    state

    =
    on


    mac

    =
    0

    :4:3:2:1:f, 
    ethmod

    =
    vnet


    hostip

    =
    10

    .0.0.1 

注意:
如果你想在同一时刻运行两个或更多的Linux SkyEye,那么请为每一个Linux SkyEye使用不同的Linux SkyEye.conf e.运行Linux SkyEye linux-2.4.x/linux

10、安装完成Linux SkyEye后,下一步将做什么?

1、对于嵌入式操作系统的初学者和入门者和入门的学生而言,他们可以先看一些有关操作系统和嵌入式操作系统方面的教材和书籍,如与uC/OS、
Minix、uClinux、Linux相关的书籍等。然后可以在Linux
SkyEye上开发一些简单的应用程序例子(如进程间通信、进程优先级、死锁情况、网络应用等),对某些操作系统功能(如进程调度、内存管理、网络子系
统、文件子系统等)进行简单的修改和扩展,并通过Linux SkyEye进行运行和调试,看看会发生什么情况。

2、对于有一定经验的软件工程师而言,在Linux
SkyEye上完成一定的应用系统原型开发是值得一做的事情。比如移植或开发一个文件子系统或网络子系统到一个特定的操作系统中,相信比在一个真实的开发
板上开发要容易一些。在Linux SkyEye上进行一些操作系统的移植和开发(如移植RTLinux、RTAI等其它操作系统到Linux
SkyEye上)也是很有挑战性的工作。

3、对于硬件工程师而言,对Linux SkyEye进行扩充,设计新的硬件仿真(如USB、IDE硬盘等)使得Linux SkyEye的硬件仿真功能更加强大,支持更多功能的软件,是很有意义的事情。

参考:Linux SkyEye项目站点里的一篇中文文档;陈渝《Linux SkyEye Project FAQ》;Linux SkyEye-0.7.0中的README文档。

后记:为了让大家能快速上手,进行实际的开发工作,我赶凑了一篇文档,很粗糙。但我坚信随着更多的有经验的人的加入;随着我们自己水平的提高,一定会出现更多、更好的文章来。就让我们快点行动起来吧!

最后,我再次建议大家看一下《嵌入式Linux技术与应用》这本书。可以到http://www.Linux
SkyEye.org/document.htm或是ftp://166.111.68.183/pub/embed/Linux
SkyEye/document/或是http://www.huihoo.org/mirrors/Linux
SkyEye/下载文档,可以获得更多有关Linux SkyEye和嵌入式Linux开发的知识和经验.