1. 程式人生 > >ARM模擬器-skyeye(天目)的安裝和使用!

ARM模擬器-skyeye(天目)的安裝和使用!

                  ARM模擬器-skyeye(天目)的安裝和使用

SkyEye是一個可以執行嵌入式作業系統的硬體模擬工具,這樣就可以在沒有硬體條件下來進行嵌入式系統的開發。

以下操作均在Fedora Core 1.0裡通過。


文件摘要:
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能模擬下面的硬體:
(1)CPU核心:ARM7TDMI, ARM720T, ARM9, StrongARM, XScale

(2)CPU: Atmel AT91/X40, Cirrus CIRRUS LOGIC EP7312, Intel SA1100/SA1110, Intel XScale PXA 250/255, CS89712,                           samsung 4510B,samsung 44B0(還不全)
(3)記憶體: RAM, ROM, Flash
(4)周邊裝置: Timer, UART, ne2k網路晶片, LCD, 觸控式螢幕等

目前能在SkyEye上執行下面的作業系統和系統軟體:
(1)uC/OSII-2.5.x(支援網路)
(2)uClinux(基於Linux2.4.x核心, 支援網路)
(3)ARM Linux 2.4.x/2.6.x
(4)lwIP on uC/OSII
(5)基於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

(1)到http://gro.clinux.org/projects/skyeye/下載skyeye-0.7.0.tar.bz2包並減壓:

tar jxvf skyeye-v0.7.0.tar.bz2

(2)進入解壓後的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

(3)接下來執行:

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交叉編譯器

(1)下載arm-elf-tools-20030314.sh

ftp://166.111.68.183/pub/embed/uclinux/soft/tools/arm
或到
ftp://166.111.8.229/OS/Embeded

(2)執行:

chmod a+x arm-elf-tools-20030314.sh


(3)然後:

./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/skyey...-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

10、安裝完成SkyEye後,下一步將做什麼?

1、對於嵌入式作業系統的初學者和入門者和入門的學生而言,他們可以先看一些有關作業系統和嵌入式作業系統方面的教材和書籍,如與uC/OS、Minix、uClinux、Linux相關的書籍等。然後可以在Skyeye上開發一些簡單的應用程式例子(如程序間通訊、程序優先順序、死鎖情況、網路應用等),對某些作業系統功能(如程序排程、記憶體管理、網路子系統、檔案子系統等)進行簡單的修改和擴充套件,並通過Skyeye進行執行和除錯,看看會發生什麼情況。

2、對於有一定經驗的軟體工程師而言,在SkyEye上完成一定的應用系統原型開發是值得一做的事情。比如移植或開發一個檔案子系統或網路子系統到一個特定的作業系統中,相信比在一個真實的開發板上開發要容易一些。在Skyeye上進行一些作業系統的移植和開發(如移植RTLinux、RTAI等其它作業系統到Skyeye上)也是很有挑戰性的工作。

3、對於硬體工程師而言,對Skyeye進行擴充,設計新的硬體模擬(如USB、IDE硬碟等)使得Skyeye的硬體模擬功能更加強大,支援更多功能的軟體,是很有意義的事情。

參考:
SkyEye專案站點裡的一篇中文文件;
陳渝《SkyEye Project FAQ》;
skyeye-0.7.0中的README文件。