SkyEye是一个可以运行嵌入式操作系统的硬件仿真工具,这样就可以在没有硬件条件下来进行嵌入式系统的开发。
以下操作均在Fedora
Core 1.0里通过。
Skyeye项目资源列表
http://gro.clinux.org/projects/skyeye/
文档摘要:
1、什么是SkyEye?
2、SkyEye可以做什么事情?
3、安装SkyEye
4、安装arm-elf交叉编译器
5、测试你的arm-elf-gcc编译器
6、执行你的hello程序
7、一个应用程序的开发实例
8、编译并运行uClinux-dist-20030909.tar.gz
9、加入网络功能
10、安装完成SkyEye后,下一步将做什么?
1、什么是SkyEye?
SkyEye是开源软件的一个项目,SkyEye的目标是在Linux和Windows操作系统里提供一个完全的仿真环境。SkyEye仿真环境相当于一个嵌入式计
算机系统,你可以在SkyEye里运行一些嵌入式Linux操作系统,如ARMLinux,uClinux,uc/OS-II(ucos-ii)等,并能分析和调试它们的源代码。
如果你想知道关于SkyEye和嵌入式系统更详细的信息,请访问下面的站点:
http://www.skyeye.org/
http://www.skyeye.org/index_cn.html
通过SkyEye能仿真下面的硬件:
CPU核心:ARM7TDMI,
ARM720T, ARM9, StrongARM, XScale
CPU: Atmel AT91/X40, Cirrus
CIRRUS LOGIC EP7312, Intel SA1100/SA1110, Intel XScale PXA 250/255,
CS89712, samsung 4510B,
samsung 44B0(还不全)
内存: RAM, ROM,
Flash
周边设备: Timer, UART, ne2k网络芯片, LCD,
触摸屏等
目前能在SkyEye上运行下面的操作系统和系统软件:
uC/OSII-2.5.x(支持网络)
uClinux(基于Linux2.4.x内核,
支持网络)
ARM Linux 2.4.x/2.6.x
lwIP on uC/OSII
基于uC/OSII,
uClinux, ARM Linux的应用程序
2.SkyEye可以做什么事情?
1.
通过SkyEye可以帮助促进嵌入式系统的学习,在不需要额外硬件的情况下学习和分析uclinux操作系统和其它嵌入式操作系统,如ucosII等
。
2.
SkyEye可用于嵌入式系统的教学。
3.
希望通过skyeye促进操作系统的研究,如ucosII,uclinux+RTAI,uclinux2.5.x等。
4.
可以基于SkyEye进行仿真特定硬件模块的研究。
5.
SkyEye可以作为嵌入式集成开发环境开发嵌入式系统(当然需要对SkyEye做大量的工作)。
注:引自陈渝《SkyEye
Project FAQ》
3、安装SkyEye
到
http://gro.clinux.org/projects/skyeye/下载skyeye-0.7.0.tar.bz2包:
tar
jxvf
skyeye-v0.7.0.tar.bz2
进入解压后的skyeye目录,如果SkyEye的版本低于0.6.0,则运行下面的命令:
./configure
--target=arm-elf --prefix=/usr/local --without-gtk-prefix
--without-gtk-exec-prefix
--disable-gtktest
如果SkyEye的版本高于0.6.0,则运行下面的命令:
./configure
--target=arm-elf
--prefix=/usr/local
接下来执行:
make
make
install
安装完成后执行skyeye
注意:
a.如果你使用的是Mandrake
Linux发行版,那么你在编译SkyEye时遇到错误,并且错误与readline, ncurse,
termcap等有关,你可以试试下面
的方法:
ln -s
/usr/include/ncurses/termcap.h
/usr/local/include/termcap.h
接着再make和make
install看能否成功!
b.如果你的Linux发行版是Debian Linux,那么不要使用gcc 2.95或是gcc
3.0,请使用gcc
3.2+
c.gcc的版本要在2.96或以上
d.如果SkyEye的版本大于0.6.0,那么使用LCD仿真需要在Linux系统里安装GTK软件。
4、安装arm-elf交叉编译器
下载arm-elf-tools-20030314.sh
ftp://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.c
PHP 代码:
#include <stdio.h>
int main(void)
{
int
i;
for(i
= 0; i < 6; i++){
printf("i = %d ",i);
printf("Hello, embedded linux!\n");
}
return 0;
}
然后执行:
arm-elf-gcc
-Wl,-elf2flt -o hello
hello.c
-elf2flt参数是将elf文件格式转为flat文件格式,这个工具是在你安装交叉编译器产生的。
或者你可以写个Makefile文件,执行:
make
这里是我的Makefile文件,仅供参考:
PHP 代码:
# begin
CC =
arm-elf-gcc
CFLAGS
= -D__PIC__
-fpic
-msingle-pic-base -O2 -pipe -Wall -g
LDFLAGS =
-Wl,-elf2flt
LIBS
=
OBJS
= hello.o
all: hello
hello: $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o hello $(OBJS) $(LIBS)
clean:
rm -rf *.o *.elf *.gdb hello
# end
如果编译通过,就会产生hello可执行文件。用下面的命令:
file
hello
你会发现,它是BFLT(binary
FLAT),你目标平台所支持的文件格式。
6、执行你的hello程序
这里,我们将借助genromfs这个小工具来完成测试,这个工具就是你在安装交叉编译器时产生的,你可以直接使用它。
到
http://gro.clinux.org/projects/skyeye/下载skyeye-binary-testutils-1.0.4.tar.bz2包:
tar
jxvf skyeye-binary-testutils-1.0.4.tar.bz2
cd
testsuits/at91/uclinux2(当然你还可以用别的)
mkdir
romfs(建一个目录,后面用)
mount -o loop boot.rom /mnt/xxx
cp -r
/mnt/xxx/*
romfs
另外,把你编译好的可执行程序拷贝到/romfs/bin目录里,这里就是hello了!
genromfs
-f boot.rom -d romfs/
注:可以用genromfs
-h来获得帮助!
OK!执行下面的命令:
skyeye
linux
(skyeye)target
sim
(skyeye)load
(skyeye)run
kernel
start.....
很熟悉了吧。。。
cd
/bin
hello
可以看到结果了吗?
其实到了这一步,你就可以开发自己的程序了!
7、一个应用程序的开发实例
下面介绍的程序主要是完成一个网络应用,网络应用的标准模型是客户机-服务器模型,它的主要执行过程如下:
(1)系统启动服务器执行。服务器完成一些初始化操作,然后进入睡眠状态,等待客户机请求;
(2)在网络的某台机器上,用户执行客户机程序;
(3)客户机进程与服务器进程建立一条连接;
(4)连接建立之后,客户机通过网络向服务器发出请求,请求某种服务;
(5)服务器接收到客户机请求后,根据客户机请求的内容进行相应的处理,然后将处理结果返回;
(6)服务器断开与客户机的连接,继续睡眠,等待其他客户机的请求;
Linux系统中的很多服务器是在系统初启时启动的,如时间服务器、打印服务器、文件传输服务器和电子邮件服务器等。大多数时间这些服务器
进程处于睡眠状态,等待客户机的请求。
下面这两个客户机-服务器程序比较简单,主要是对网络客户机-服务器模型的实际运行有大致印象。这个客户机-服务器的操作过程非常简单:
客户机与服务器建立连接之后,服务器向客户机返回一条消息。
服务器程序的源代码如下:
PHP 代码:
/*
tcpserver.c */
#include <stdlib.h>
#include
<stdio.h>
#include <errno.h>
#include
<string.h>
#include <netdb.h>
#include
<sys/types.h>
#include <netinet/in.h>
#include
<sys/socket.h>
#define WAITBUF 10
int main(int argc, char *argv[])
{
int
sockfd, new_fd;
struct
sockaddr_in server_addr;
struct
sockaddr_in client_addr;
unsigned int
sin_size, portnumber;
char
hello[]="Hello! Socket communication world!\n";
if(argc != 2)
{
fprintf(stderr, "Usage:%s portnumber\a\n",
argv[0]);
exit(1);
}
if((portnumber = atoi(argv[1])) < 0)
{
fprintf(stderr, "Usage: %s portnumber error\a\n", argv[0]);
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socket error:%s\n\a",
strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = portnumber;
if(bind(sockfd,(struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) ==
-1)
{
fprintf(stderr, "Bind error:%s\n\a",
strerror(errno));
exit(1);
}
if(listen(sockfd, WAITBUF) == -1)
{
fprintf(stderr, "Listen error:%s\n\a",
strerror(errno));
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd, (struct sockaddr *)(&client_addr),
&sin_size)) == -1)
{
fprintf( stderr, "Accept error:%s\n\a",
strerror(errno));
exit(1);
}
fprintf(stderr, "Server get connection from %s\n", inet_ntoa(client_addr.sin_addr));
if(send(new_fd, hello, strlen(hello), 0) == -1)
{
fprintf(stderr, "Write Error:%s\n",
strerror(errno));
exit(1);
}
close(new_fd);
}
close(sockfd);
exit(0);
}
给服务器程序写一个Makefile文件,如下:
PHP 代码:
# start
CC =
arm-elf-gcc
CFLAGS
= -D__PIC__
-fpic
-msingle-pic-base -O2 -pipe -Wall -g
LDFLAGS =
-Wl,-elf2flt
LIBS
=
OBJS
= tcpserver.o
all: tcpserver
tcpser: $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o tcpserver $(OBJS) $(LIBS)
clean:
rm
-rf
*.o
*.elf
*.gdb hello
# end
客户机程序的源代码如下:
PHP 代码:
/*
tcpclient.c */
#include <stdlib.h>
#include
<stdio.h>
#include <errno.h>
#include
<string.h>
#include <netdb.h>
#include
<sys/types.h>
#include <netinet/in.h>
#include
<sys/socket.h>
#define RECVBUFSIZE 1024
int main(int argc, char *argv[])
{
int sockfd;
char
buffer[RECVBUFSIZE];
struct
sockaddr_in server_addr;
int
portnumber, nbytes;
if(argc
!= 3)
{
fprintf(stderr, "Usage:%s hostname portnumber\a\n", argv[0]);
exit(1);
}
if((portnumber=atoi(argv[2])) < 0)
{
fprintf(stderr,"Usage:%s hostname portnumber\a\n", argv[0]);
exit(1);
}
if((sockfd
= socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socket Error:%s\a\n",
strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = portnumber;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) ==
-1)
{
fprintf(stderr, "Connect Error:%s\a\n",
strerror(errno));
exit(1);
}
if((nbytes
= recv(sockfd, buffer, RECVBUFSIZE, 0)) == -1)
{
fprintf(stderr, "Read Error:%s\n",
strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("I have received:%s\n",
buffer );
close(sockfd);
exit(0);
}
最后,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.gz
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的skyeye配置文件skyeye.conf,内容如下:
cpu:
arm7tdmi
mach: at91
mem_bank: map=M, type=RW, addr=0x00000000,
size=0x00004000
mem_bank: map=M, type=RW, addr=0x01000000,
size=0x00400000
mem_bank: map=M, type=R, addr=0x01400000,
size=0x00400000, file=images/romfs.img
mem_bank: map=M, type=RW,
addr=0x02000000, size=0x00400000
mem_bank: map=M, type=RW,
addr=0x02400000, size=0x00008000
mem_bank: map=M, type=RW,
addr=0x04000000, size=0x00400000
mem_bank: map=I, type=RW,
addr=0xf0000000,
size=0x10000000
这个时候就可以用skyeye来调试运行kernel了,在/usr/src/uClinux-dist执行如下命令:
skyeye
linux-2.4.x/linux
(skyeye)target
sim
(skyeye)load
(skyeye)run
kernel
start.....
注意:
要在skyeye.conf所在目录下执行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设备模块:
#insmod
/lib/modules/'uname
-r'/kernel/drivers/net/tun.o
如果你没有该设备,那你就要用下面的命令来创建它:
#mkdir
/dev/net
#mknod /dev/net/tun c 10
200
(2)运行vnet(虚拟集线器)设备模块(这一步不是必需的):
获取vnet的源码,然后创建设备:
#mknod
/dev/net/vnet c 10 201
#chmod 666
/dev/net/vnet
创建vnet.o
#make
vnet.o
插入模块vnet.o
#insmod
vnet.o
进入test目录,用test来测度vnet.o
#cd
test
#make
#./testvnet1
d.配置skyeye.conf文件
cpu:
arm7tdmi
mach: at91
mem_bank: map=M, type=RW, addr=0x00000000,
size=0x00004000
mem_bank: map=M, type=RW, addr=0x01000000,
size=0x00400000
mem_bank: map=M, type=R, addr=0x01400000,
size=0x00400000, file=images/romfs.img
mem_bank: map=M, type=RW,
addr=0x02000000, size=0x00400000
mem_bank: map=M, type=RW,
addr=0x02400000, size=0x00008000
mem_bank: map=M, type=RW,
addr=0x04000000, size=0x00400000
mem_bank: map=I, type=RW,
addr=0xf0000000, size=0x10000000
# format: state=on/off
mac=xx:xx:xx:xx:xx:xx ethmod=tuntap/vnet hostip=dd.dd.dd.dd
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
For example:
#set nic info state=on/off
mac=xx:xx:xx:xx:xx:xx ethmod=tuntap/vnet hostip=dd.dd.dd.dd
net:
state=on, mac=0:4:3:2:1:f, ethmod=tun, hostip=10.0.0.1
或
net:
state=on, mac=0:4:3:2:1:f, ethmod=vnet,
hostip=10.0.0.1
注意:
如果你想在同一时刻运行两个或更多的skyeye,那么请为每一个skyeye使用不同的skyeye.conf
e.运行skyeye
linux-2.4.x/linux