﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-1，2，3。。。 大道以多岐路亡羊，学者以多方丧生。-随笔分类-arm嵌入式学习</title><link>http://www.cnitblog.com/schkui/category/2843.html</link><description>政府为什么敢控制物价，不敢控制房价，---- 因为为房，是(多或少)数官员和大商人的一起的利益。。。怕影响自己的政绩...    </description><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 14:22:13 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 14:22:13 GMT</pubDate><ttl>60</ttl><item><title>转载  学习使用SkyEye仿真</title><link>http://www.cnitblog.com/schkui/archive/2006/11/10/19044.html</link><dc:creator>爱易</dc:creator><author>爱易</author><pubDate>Fri, 10 Nov 2006 05:38:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/11/10/19044.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/19044.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2006/11/10/19044.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/19044.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/19044.html</trackback:ping><description><![CDATA[SkyEye是一个可以运行嵌入式操作系统的硬件仿真工具，这样就可以在没有硬件条件下来进行嵌入式系统的开发。<br /><br />
以下操作均在Fedora Core 1.0里通过。<br /><br /><font color="red"><font size="3"><b>Skyeye项目资源列表</b></font></font><br /><a href="http://gro.clinux.org/projects/skyeye/" target="_blank">http://gro.clinux.org/projects/skyeye/</a><br /><br /><br /><font color="blue"><b>文档摘要：</b></font><br />
1、什么是SkyEye？<br />
2、SkyEye可以做什么事情？<br />
3、安装SkyEye<br />
4、安装arm-elf交叉编译器<br />
5、测试你的arm-elf-gcc编译器<br />
6、执行你的hello程序<br />
7、一个应用程序的开发实例<br />
8、编译并运行uClinux-dist-20030909.tar.gz<br />
9、加入网络功能<br />
10、安装完成SkyEye后，下一步将做什么？<br /><br /><br /><font color="blue"><b>1、什么是SkyEye？</b></font><br /><br />
SkyEye是开源软件的一个项目，SkyEye的目标是在Linux和Windows操作系统里提供一个完全的仿真环境。SkyEye仿真环境相当于一个嵌入式计<br /><br />
算机系统，你可以在SkyEye里运行一些嵌入式Linux操作系统，如ARMLinux，uClinux，uc/OS-II(ucos-ii)等，并能分析和调试它们的源代码。<br /><br />
如果你想知道关于SkyEye和嵌入式系统更详细的信息，请访问下面的站点：<br /><a href="http://www.skyeye.org/" target="_blank">www.SkyEye.org</a><br /><a href="http://www.skyeye.org/index_cn.html" target="_blank">http://www.skyeye.org/index_cn.html</a><br /><br />
通过SkyEye能仿真下面的硬件：<br />
CPU核心：ARM7TDMI, ARM720T, ARM9, StrongARM, XScale<br />
CPU: Atmel AT91/X40, Cirrus CIRRUS LOGIC EP7312, Intel SA1100/SA1110, Intel XScale PXA 250/255, CS89712, samsung 4510B, <br /><br />
samsung 44B0(还不全)<br />
内存: RAM, ROM, Flash<br />
周边设备: Timer, UART, ne2k网络芯片, LCD, 触摸屏等<br /><br />
目前能在SkyEye上运行下面的操作系统和系统软件：<br />
uC/OSII-2.5.x(支持网络)<br />
uClinux(基于Linux2.4.x内核, 支持网络)<br />
ARM Linux 2.4.x/2.6.x<br />
lwIP on uC/OSII<br />
基于uC/OSII, uClinux, ARM Linux的应用程序<br /><br /><br /><font color="blue"><b>2.SkyEye可以做什么事情？</b></font><br />
1. 通过SkyEye可以帮助促进嵌入式系统的学习，在不需要额外硬件的情况下学习和分析uclinux操作系统和其它嵌入式操作系统，如ucosII等<br /><br />
。<br />
2. SkyEye可用于嵌入式系统的教学。<br />
3. 希望通过skyeye促进操作系统的研究，如ucosII，uclinux+RTAI，uclinux2.5.x等。<br />
4. 可以基于SkyEye进行仿真特定硬件模块的研究。<br />
5. SkyEye可以作为嵌入式集成开发环境开发嵌入式系统（当然需要对SkyEye做大量的工作）。<br />
注：引自陈渝《SkyEye Project FAQ》<br /><br /><br /><font color="blue"><b>3、安装SkyEye</b></font><br /><br />
到<a href="http://gro.clinux.org/projects/skyeye/" target="_blank">http://gro.clinux.org/projects/skyeye/</a>下载skyeye-0.7.0.tar.bz2包：<br /><br />
tar jxvf skyeye-v0.7.0.tar.bz2<br /><br />
进入解压后的skyeye目录，如果SkyEye的版本低于0.6.0,则运行下面的命令：<br /><br />
./configure --target=arm-elf --prefix=/usr/local --without-gtk-prefix --without-gtk-exec-prefix --disable-gtktest<br /><br />
如果SkyEye的版本高于0.6.0,则运行下面的命令：<br /><br />
./configure --target=arm-elf --prefix=/usr/local<br /><br />
接下来执行：<br /><br />
make<br />
make install<br /><br />
安装完成后执行skyeye<br /><br />
注意：<br />
a.如果你使用的是Mandrake Linux发行版,那么你在编译SkyEye时遇到错误，并且错误与readline, ncurse, termcap等有关，你可以试试下面<br /><br />
的方法：<br /><br />
ln -s /usr/include/ncurses/termcap.h /usr/local/include/termcap.h<br /><br />
接着再make和make install看能否成功！<br />
b.如果你的Linux发行版是Debian Linux,那么不要使用gcc 2.95或是gcc 3.0，请使用gcc 3.2+<br />
c.gcc的版本要在2.96或以上<br />
d.如果SkyEye的版本大于0.6.0,那么使用LCD仿真需要在Linux系统里安装GTK软件。<br /><br /><br /><font color="blue"><b>4、安装arm-elf交叉编译器</b></font><br /><br />
下载arm-elf-tools-20030314.sh<br /><a href="ftp://166.111.68.183/pub/embed/uclinux/soft/tools/arm" target="_blank">ftp://166.111.68.183/pub/embed/uclinux/soft/tools/arm</a><br />
或到<br /><a href="ftp://166.111.8.229/OS/Embeded" target="_blank">ftp://166.111.8.229/OS/Embeded</a><br /><br />
执行：<br />
chmod a+x arm-elf-tools-20030314.sh<br />
然后：<br />
./arm-elf-tools-20030314.sh<br /><br />
ls /usr/local/bin/<br /><br />
你应能看到以arm-elf开头的可执行文件，其中arm-elf-gcc就是用来编译你目标平台的编译器的，当然还有一些小工具，后面将一一讲来。<br /><br /><br /><font color="blue"><b>5、测试你的arm-elf-gcc编译器</b></font><br /><br />
先写一个小程序hello.c<br /><div style="margin: 5px 20px 20px 0px;"><div class="smallfont" style="margin-bottom: 2px;">PHP 代码:</div><div class="alt2" style="border: 1px solid rgb(198, 198, 198); margin: 0px; padding: 4px; overflow: auto; width: 640px; height: 258px;"><code style="white-space: nowrap;"></code><div dir="ltr" style="text-align: left;"><!-- php buffer start --><code><font color="#000000"><font color="#ff8000">#include &lt;stdio.h&gt;
<br /><br /></font><font color="#0000bb">int main</font><font color="#007700">(</font><font color="#0000bb">void</font><font color="#007700">)
<br />{
<br />    </font><font color="#0000bb">int i</font><font color="#007700">;
<br /><br />    for(</font><font color="#0000bb">i </font><font color="#007700">= </font><font color="#0000bb">0</font><font color="#007700">; </font><font color="#0000bb">i </font><font color="#007700">&lt; </font><font color="#0000bb">6</font><font color="#007700">; </font><font color="#0000bb">i</font><font color="#007700">++){
<br /><br />        </font><font color="#0000bb">printf</font><font color="#007700">(</font><font color="#dd0000">"i = %d  "</font><font color="#007700">,</font><font color="#0000bb">i</font><font color="#007700">);
<br /><br />        </font><font color="#0000bb">printf</font><font color="#007700">(</font><font color="#dd0000">"Hello, embedded linux!\n"</font><font color="#007700">);
<br />    }
<br /><br />    return </font><font color="#0000bb">0</font><font color="#007700">;
<br />} 
<br /></font></font></code><!-- php buffer end --></div></div></div>
然后执行：<br /><br />
arm-elf-gcc -Wl,-elf2flt -o hello hello.c<br /><br />
-elf2flt参数是将elf文件格式转为flat文件格式，这个工具是在你安装交叉编译器产生的。<br /><br />
或者你可以写个Makefile文件，执行：<br /><br />
make<br /><br />
这里是我的Makefile文件，仅供参考：<br /><div style="margin: 5px 20px 20px 0px;"><div class="smallfont" style="margin-bottom: 2px;">PHP 代码:</div><div class="alt2" style="border: 1px solid rgb(198, 198, 198); margin: 0px; padding: 4px; overflow: auto; width: 640px; height: 322px;"><code style="white-space: nowrap;"></code><div dir="ltr" style="text-align: left;"><!-- php buffer start --><code><font color="#000000"><font color="#ff8000"># begin
<br /><br /></font><font color="#0000bb">CC </font><font color="#007700">= </font><font color="#0000bb">arm</font><font color="#007700">-</font><font color="#0000bb">elf</font><font color="#007700">-</font><font color="#0000bb">gcc
<br /><br />CFLAGS </font><font color="#007700">= -</font><font color="#0000bb">D__PIC__ </font><font color="#007700">-</font><font color="#0000bb">fpic </font><font color="#007700">-</font><font color="#0000bb">msingle</font><font color="#007700">-</font><font color="#0000bb">pic</font><font color="#007700">-</font><font color="#0000bb">base </font><font color="#007700">-</font><font color="#0000bb">O2 </font><font color="#007700">-</font><font color="#0000bb">pipe </font><font color="#007700">-</font><font color="#0000bb">Wall </font><font color="#007700">-</font><font color="#0000bb">g
<br />LDFLAGS </font><font color="#007700">= -</font><font color="#0000bb">Wl</font><font color="#007700">,-</font><font color="#0000bb">elf2flt
<br /><br />LIBS </font><font color="#007700">=
<br /></font><font color="#0000bb">OBJS </font><font color="#007700">= </font><font color="#0000bb">hello</font><font color="#007700">.</font><font color="#0000bb">o
<br /><br />all</font><font color="#007700">:    </font><font color="#0000bb">hello
<br /><br />hello</font><font color="#007700">:  $(</font><font color="#0000bb">OBJS</font><font color="#007700">)
<br />        $(</font><font color="#0000bb">CC</font><font color="#007700">) $(</font><font color="#0000bb">CFLAGS</font><font color="#007700">) $(</font><font color="#0000bb">LDFLAGS</font><font color="#007700">) -</font><font color="#0000bb">o hello </font><font color="#007700">$(</font><font color="#0000bb">OBJS</font><font color="#007700">) $(</font><font color="#0000bb">LIBS</font><font color="#007700">)
<br /><br /></font><font color="#0000bb">clean</font><font color="#007700">:
<br />        </font><font color="#0000bb">rm </font><font color="#007700">-</font><font color="#0000bb">rf </font><font color="#007700">*.</font><font color="#0000bb">o </font><font color="#007700">*.</font><font color="#0000bb">elf </font><font color="#007700">*.</font><font color="#0000bb">gdb hello
<br /><br /></font><font color="#ff8000"># end 
<br /></font></font></code><!-- php buffer end --></div></div></div>
如果编译通过，就会产生hello可执行文件。用下面的命令：<br /><br />
file hello<br /><br />
你会发现，它是BFLT(binary FLAT)，你目标平台所支持的文件格式。<br /><br /><br /><font color="blue"><b>6、执行你的hello程序</b></font><br /><br />
这里，我们将借助genromfs这个小工具来完成测试，这个工具就是你在安装交叉编译器时产生的，你可以直接使用它。<br /><br />
到<a href="http://gro.clinux.org/projects/skyeye/%E4%B8%8B%E8%BD%BDskyeye-binary-testutils-1.0.4.tar.bz2" target="_blank">http://gro.clinux.org/projects/skyey...-1.0.4.tar.bz2</a>包：<br /><br />
tar jxvf skyeye-binary-testutils-1.0.4.tar.bz2<br /><br />
cd testsuits/at91/uclinux2(当然你还可以用别的)<br /><br />
mkdir romfs(建一个目录，后面用)<br /><br />
mount -o loop boot.rom /mnt/xxx<br /><br />
cp -r /mnt/xxx/* romfs<br /><br />
另外，把你编译好的可执行程序拷贝到/romfs/bin目录里，这里就是hello了！<br /><br />
genromfs -f boot.rom -d romfs/<br /><br />
注：可以用genromfs -h来获得帮助！<br /><br />
OK！执行下面的命令：<br /><br />
skyeye linux<br /><br />
(skyeye)target sim<br /><br />
(skyeye)load<br /><br />
(skyeye)run<br /><br />
kernel start.....<br /><br />
很熟悉了吧。。。<br /><br />
cd /bin<br /><br />
hello<br /><br />
可以看到结果了吗？<br /><br />
其实到了这一步，你就可以开发自己的程序了！<br /><br /><br /><font color="blue"><b>7、一个应用程序的开发实例</b></font><br /><br />
下面介绍的程序主要是完成一个网络应用，网络应用的标准模型是客户机-服务器模型，它的主要执行过程如下:<br />
(1)系统启动服务器执行。服务器完成一些初始化操作，然后进入睡眠状态，等待客户机请求;<br />
(2)在网络的某台机器上，用户执行客户机程序;<br />
(3)客户机进程与服务器进程建立一条连接;<br />
(4)连接建立之后，客户机通过网络向服务器发出请求，请求某种服务;<br />
(5)服务器接收到客户机请求后，根据客户机请求的内容进行相应的处理，然后将处理结果返回;<br />
(6)服务器断开与客户机的连接，继续睡眠，等待其他客户机的请求;<br /><br />
Linux系统中的很多服务器是在系统初启时启动的，如时间服务器、打印服务器、文件传输服务器和电子邮件服务器等。大多数时间这些服务器<br /><br />
进程处于睡眠状态，等待客户机的请求。<br /><br />
下面这两个客户机-服务器程序比较简单，主要是对网络客户机-服务器模型的实际运行有大致印象。这个客户机-服务器的操作过程非常简单：<br /><br />
客户机与服务器建立连接之后，服务器向客户机返回一条消息。<br /><br />
服务器程序的源代码如下：<br /><div style="margin: 5px 20px 20px 0px;"><div class="smallfont" style="margin-bottom: 2px;">PHP 代码:</div><div class="alt2" style="border: 1px solid rgb(198, 198, 198); margin: 0px; padding: 4px; overflow: auto; width: 640px; height: 498px;"><code style="white-space: nowrap;"></code><div dir="ltr" style="text-align: left;"><!-- php buffer start --><code><font color="#000000"><font color="#ff8000">/* tcpserver.c */
<br />#include &lt;stdlib.h&gt;
<br />#include &lt;stdio.h&gt;
<br />#include &lt;errno.h&gt;
<br />#include &lt;string.h&gt;
<br />#include &lt;netdb.h&gt;
<br />#include &lt;sys/types.h&gt;
<br />#include &lt;netinet/in.h&gt;
<br />#include &lt;sys/socket.h&gt;
<br /><br />#define WAITBUF 10
<br /><br /></font><font color="#0000bb">int main</font><font color="#007700">(</font><font color="#0000bb">int argc</font><font color="#007700">, </font><font color="#0000bb">char </font><font color="#007700">*</font><font color="#0000bb">argv</font><font color="#007700">[])
<br />{
<br />    </font><font color="#0000bb">int sockfd</font><font color="#007700">, </font><font color="#0000bb">new_fd</font><font color="#007700">;
<br />    </font><font color="#0000bb">struct sockaddr_in server_addr</font><font color="#007700">;
<br />    </font><font color="#0000bb">struct sockaddr_in client_addr</font><font color="#007700">;
<br />    </font><font color="#0000bb">unsigned int sin_size</font><font color="#007700">, </font><font color="#0000bb">portnumber</font><font color="#007700">;
<br />    </font><font color="#0000bb">char hello</font><font color="#007700">[]=</font><font color="#dd0000">"Hello! Socket communication world!\n"</font><font color="#007700">;
<br /><br />    if(</font><font color="#0000bb">argc </font><font color="#007700">!= </font><font color="#0000bb">2</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Usage:%s portnumber\a\n"</font><font color="#007700">, </font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">0</font><font color="#007700">]);
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br /><br />    if((</font><font color="#0000bb">portnumber </font><font color="#007700">= </font><font color="#0000bb">atoi</font><font color="#007700">(</font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">1</font><font color="#007700">])) &lt; </font><font color="#0000bb">0</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Usage: %s portnumber error\a\n"</font><font color="#007700">, </font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">0</font><font color="#007700">]);
<br />    }
<br /><br />    if((</font><font color="#0000bb">sockfd </font><font color="#007700">= </font><font color="#0000bb">socket</font><font color="#007700">(</font><font color="#0000bb">AF_INET</font><font color="#007700">, </font><font color="#0000bb">SOCK_STREAM</font><font color="#007700">, </font><font color="#0000bb">0</font><font color="#007700">)) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Socket error:%s\n\a"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br /><br />    </font><font color="#0000bb">bzero</font><font color="#007700">(&amp;</font><font color="#0000bb">server_addr</font><font color="#007700">, </font><font color="#0000bb">sizeof</font><font color="#007700">(</font><font color="#0000bb">struct sockaddr_in</font><font color="#007700">));
<br />    </font><font color="#0000bb">server_addr</font><font color="#007700">.</font><font color="#0000bb">sin_family </font><font color="#007700">= </font><font color="#0000bb">AF_INET</font><font color="#007700">;
<br /><br />    </font><font color="#0000bb">server_addr</font><font color="#007700">.</font><font color="#0000bb">sin_addr</font><font color="#007700">.</font><font color="#0000bb">s_addr </font><font color="#007700">= </font><font color="#0000bb">htonl</font><font color="#007700">(</font><font color="#0000bb">INADDR_ANY</font><font color="#007700">);
<br />    </font><font color="#0000bb">server_addr</font><font color="#007700">.</font><font color="#0000bb">sin_port </font><font color="#007700">= </font><font color="#0000bb">portnumber</font><font color="#007700">;
<br /><br />    if(</font><font color="#0000bb">bind</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">,(</font><font color="#0000bb">struct sockaddr </font><font color="#007700">*)(&amp;</font><font color="#0000bb">server_addr</font><font color="#007700">), </font><font color="#0000bb">sizeof</font><font color="#007700">(</font><font color="#0000bb">struct sockaddr</font><font color="#007700">)) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Bind error:%s\n\a"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br /><br />    if(</font><font color="#0000bb">listen</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">, </font><font color="#0000bb">WAITBUF</font><font color="#007700">) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Listen error:%s\n\a"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br /><br />    while(</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">sin_size </font><font color="#007700">= </font><font color="#0000bb">sizeof</font><font color="#007700">(</font><font color="#0000bb">struct sockaddr_in</font><font color="#007700">);
<br />        if((</font><font color="#0000bb">new_fd </font><font color="#007700">= </font><font color="#0000bb">accept</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">, (</font><font color="#0000bb">struct sockaddr </font><font color="#007700">*)(&amp;</font><font color="#0000bb">client_addr</font><font color="#007700">), &amp;</font><font color="#0000bb">sin_size</font><font color="#007700">)) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />        {
<br />            </font><font color="#0000bb">fprintf</font><font color="#007700">( </font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Accept error:%s\n\a"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />            exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />        }
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Server get connection from %s\n"</font><font color="#007700">, </font><font color="#0000bb">inet_ntoa</font><font color="#007700">(</font><font color="#0000bb">client_addr</font><font color="#007700">.</font><font color="#0000bb">sin_addr</font><font color="#007700">));
<br />        if(</font><font color="#0000bb">send</font><font color="#007700">(</font><font color="#0000bb">new_fd</font><font color="#007700">, </font><font color="#0000bb">hello</font><font color="#007700">, </font><font color="#0000bb">strlen</font><font color="#007700">(</font><font color="#0000bb">hello</font><font color="#007700">), </font><font color="#0000bb">0</font><font color="#007700">) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />        {
<br />            </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Write Error:%s\n"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />            exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />        }
<br /><br />        </font><font color="#0000bb">close</font><font color="#007700">(</font><font color="#0000bb">new_fd</font><font color="#007700">);
<br />    }
<br />    </font><font color="#0000bb">close</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">);
<br />    exit(</font><font color="#0000bb">0</font><font color="#007700">);
<br />} 
<br /></font></font></code><!-- php buffer end --></div></div></div><br />
给服务器程序写一个Makefile文件，如下：<br /><div style="margin: 5px 20px 20px 0px;"><div class="smallfont" style="margin-bottom: 2px;">PHP 代码:</div><div class="alt2" style="border: 1px solid rgb(198, 198, 198); margin: 0px; padding: 4px; overflow: auto; width: 640px; height: 322px;"><code style="white-space: nowrap;"></code><div dir="ltr" style="text-align: left;"><!-- php buffer start --><code><font color="#000000"><font color="#ff8000"># start
<br /><br /></font><font color="#0000bb">CC </font><font color="#007700">= </font><font color="#0000bb">arm</font><font color="#007700">-</font><font color="#0000bb">elf</font><font color="#007700">-</font><font color="#0000bb">gcc
<br /><br />CFLAGS </font><font color="#007700">= -</font><font color="#0000bb">D__PIC__ </font><font color="#007700">-</font><font color="#0000bb">fpic </font><font color="#007700">-</font><font color="#0000bb">msingle</font><font color="#007700">-</font><font color="#0000bb">pic</font><font color="#007700">-</font><font color="#0000bb">base </font><font color="#007700">-</font><font color="#0000bb">O2 </font><font color="#007700">-</font><font color="#0000bb">pipe </font><font color="#007700">-</font><font color="#0000bb">Wall </font><font color="#007700">-</font><font color="#0000bb">g
<br />LDFLAGS </font><font color="#007700">= -</font><font color="#0000bb">Wl</font><font color="#007700">,-</font><font color="#0000bb">elf2flt
<br /><br />LIBS </font><font color="#007700">=
<br /></font><font color="#0000bb">OBJS </font><font color="#007700">= </font><font color="#0000bb">tcpserver</font><font color="#007700">.</font><font color="#0000bb">o
<br /><br />all</font><font color="#007700">:    </font><font color="#0000bb">tcpserver
<br /><br />tcpser</font><font color="#007700">:  $(</font><font color="#0000bb">OBJS</font><font color="#007700">)
<br />    $(</font><font color="#0000bb">CC</font><font color="#007700">) $(</font><font color="#0000bb">CFLAGS</font><font color="#007700">) $(</font><font color="#0000bb">LDFLAGS</font><font color="#007700">) -</font><font color="#0000bb">o tcpserver </font><font color="#007700">$(</font><font color="#0000bb">OBJS</font><font color="#007700">) $(</font><font color="#0000bb">LIBS</font><font color="#007700">)
<br /><br /></font><font color="#0000bb">clean</font><font color="#007700">:
<br />    </font><font color="#0000bb">rm </font><font color="#007700">-</font><font color="#0000bb">rf </font><font color="#007700">*.</font><font color="#0000bb">o </font><font color="#007700">*.</font><font color="#0000bb">elf </font><font color="#007700">*.</font><font color="#0000bb">gdb hello
<br /><br /></font><font color="#ff8000"># end 
<br /></font></font></code><!-- php buffer end --></div></div></div><br />
客户机程序的源代码如下：<br /><div style="margin: 5px 20px 20px 0px;"><div class="smallfont" style="margin-bottom: 2px;">PHP 代码:</div><div class="alt2" style="border: 1px solid rgb(198, 198, 198); margin: 0px; padding: 4px; overflow: auto; width: 640px; height: 498px;"><code style="white-space: nowrap;"></code><div dir="ltr" style="text-align: left;"><!-- php buffer start --><code><font color="#000000"><font color="#ff8000">/* tcpclient.c */
<br />#include &lt;stdlib.h&gt;
<br />#include &lt;stdio.h&gt;
<br />#include &lt;errno.h&gt;
<br />#include &lt;string.h&gt;
<br />#include &lt;netdb.h&gt;
<br />#include &lt;sys/types.h&gt;
<br />#include &lt;netinet/in.h&gt;
<br />#include &lt;sys/socket.h&gt;
<br /><br />#define RECVBUFSIZE 1024
<br /><br /></font><font color="#0000bb">int main</font><font color="#007700">(</font><font color="#0000bb">int argc</font><font color="#007700">, </font><font color="#0000bb">char </font><font color="#007700">*</font><font color="#0000bb">argv</font><font color="#007700">[])
<br />{
<br />    </font><font color="#0000bb">int sockfd</font><font color="#007700">;
<br />    </font><font color="#0000bb">char buffer</font><font color="#007700">[</font><font color="#0000bb">RECVBUFSIZE</font><font color="#007700">];
<br />    </font><font color="#0000bb">struct sockaddr_in server_addr</font><font color="#007700">;
<br />    </font><font color="#0000bb">int portnumber</font><font color="#007700">, </font><font color="#0000bb">nbytes</font><font color="#007700">;
<br />    
<br />    if(</font><font color="#0000bb">argc </font><font color="#007700">!= </font><font color="#0000bb">3</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Usage:%s hostname portnumber\a\n"</font><font color="#007700">, </font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">0</font><font color="#007700">]);
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br /><br />    if((</font><font color="#0000bb">portnumber</font><font color="#007700">=</font><font color="#0000bb">atoi</font><font color="#007700">(</font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">2</font><font color="#007700">])) &lt; </font><font color="#0000bb">0</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">,</font><font color="#dd0000">"Usage:%s hostname portnumber\a\n"</font><font color="#007700">, </font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">0</font><font color="#007700">]);
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br />    
<br />    if((</font><font color="#0000bb">sockfd </font><font color="#007700">= </font><font color="#0000bb">socket</font><font color="#007700">(</font><font color="#0000bb">AF_INET</font><font color="#007700">, </font><font color="#0000bb">SOCK_STREAM</font><font color="#007700">, </font><font color="#0000bb">0</font><font color="#007700">)) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Socket Error:%s\a\n"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br />    
<br />    </font><font color="#0000bb">bzero</font><font color="#007700">(&amp;</font><font color="#0000bb">server_addr</font><font color="#007700">, </font><font color="#0000bb">sizeof</font><font color="#007700">(</font><font color="#0000bb">server_addr</font><font color="#007700">));
<br />    </font><font color="#0000bb">server_addr</font><font color="#007700">.</font><font color="#0000bb">sin_family </font><font color="#007700">= </font><font color="#0000bb">AF_INET</font><font color="#007700">;
<br />    </font><font color="#0000bb">server_addr</font><font color="#007700">.</font><font color="#0000bb">sin_port </font><font color="#007700">= </font><font color="#0000bb">portnumber</font><font color="#007700">;
<br />    </font><font color="#0000bb">server_addr</font><font color="#007700">.</font><font color="#0000bb">sin_addr</font><font color="#007700">.</font><font color="#0000bb">s_addr </font><font color="#007700">= </font><font color="#0000bb">inet_addr</font><font color="#007700">(</font><font color="#0000bb">argv</font><font color="#007700">[</font><font color="#0000bb">1</font><font color="#007700">]);
<br />    
<br />    if(</font><font color="#0000bb">connect</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">, (</font><font color="#0000bb">struct sockaddr </font><font color="#007700">*)(&amp;</font><font color="#0000bb">server_addr</font><font color="#007700">), </font><font color="#0000bb">sizeof</font><font color="#007700">(</font><font color="#0000bb">struct sockaddr</font><font color="#007700">)) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Connect Error:%s\a\n"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br />    
<br />    if((</font><font color="#0000bb">nbytes </font><font color="#007700">= </font><font color="#0000bb">recv</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">, </font><font color="#0000bb">buffer</font><font color="#007700">, </font><font color="#0000bb">RECVBUFSIZE</font><font color="#007700">, </font><font color="#0000bb">0</font><font color="#007700">)) == -</font><font color="#0000bb">1</font><font color="#007700">)
<br />    {
<br />        </font><font color="#0000bb">fprintf</font><font color="#007700">(</font><font color="#0000bb">stderr</font><font color="#007700">, </font><font color="#dd0000">"Read Error:%s\n"</font><font color="#007700">, </font><font color="#0000bb">strerror</font><font color="#007700">(</font><font color="#0000bb">errno</font><font color="#007700">));
<br />        exit(</font><font color="#0000bb">1</font><font color="#007700">);
<br />    }
<br />    </font><font color="#0000bb">buffer</font><font color="#007700">[</font><font color="#0000bb">nbytes</font><font color="#007700">]=</font><font color="#dd0000">'\0'</font><font color="#007700">;
<br />    </font><font color="#0000bb">printf</font><font color="#007700">(</font><font color="#dd0000">"I have received:%s\n"</font><font color="#007700">, </font><font color="#0000bb">buffer </font><font color="#007700">);
<br />    </font><font color="#0000bb">close</font><font color="#007700">(</font><font color="#0000bb">sockfd</font><font color="#007700">);
<br />    exit(</font><font color="#0000bb">0</font><font color="#007700">);
<br />} 
<br /></font></font></code><!-- php buffer end --></div></div></div><br />
最后，skyeye-binary-testutils-1.1.0.tar.bz2/at91x40/uclinux1包里提取boot.rom，用步聚6中的方法，把tcpserver程序放在boot.rom的<br /><br />
bin目录中<br /><br />
在目标板上运行tcpserver 2000<br /><br />
在主机上运行./tcpclient 10.0.0.2 2000<br /><br />
看看结果! <br /><br />
程序的源码的注释因篇幅不在这给出，大家可以参考一些Linux网络编程的书籍，我也会在我的主页上更新一些资料，有需要的朋友可以去下载<br /><br />
！<br /><br /><br /><font color="blue"><b>8、编译并运行uClinux-dist-20030909.tar.gz</b></font><br /><br />
到<a href="ftp://166.111.68.183/pub/embed/uclinux/soft/" target="_blank">ftp://166.111.68.183/pub/embed/uclinux/soft/</a><br />
或到<a href="ftp://166.111.8.229/OS/Embeded/uclinux/pub/uClinux/dist" target="_blank">ftp://166.111.8.229/OS/Embeded/uclinux/pub/uClinux/dist</a>下载<br />
uClinux-dist-20030909.tar.gz<br /><br />
假设把它下载到/usr/src/目录下，然后依次执行下面的命令：<br /><br />
tar zxvf uClinux-dist-20030909.tar.gz<br />
cd uClinux-dist/<br /><br />
在图形方式下可用命令make xconfig<br />
或<br />
在命令行方式下用命令make menuconfig<br /><br />
vendor/product中选择GDB/ARMulator<br />
kernel版本选择2.4<br />
然后save and exit<br /><br />
运行下面这两条命：<br />
make dep<br />
make<br /><br />
此时在/usr/src/uClinux-dist/linux-2.4.x目录下会生成可执行文件linux<br />
在/usr/src/uClinux-dist/images/会生成romfs.img等文件<br /><br />
在uClinux-dist目录下建立仿真AT91的skyeye配置文件skyeye.conf,内容如下：<br />
cpu: arm7tdmi<br />
mach: at91<br />
mem_bank: map=M, type=RW, addr=0x00000000, size=0x00004000<br />
mem_bank: map=M, type=RW, addr=0x01000000, size=0x00400000<br />
mem_bank: map=M, type=R,  addr=0x01400000, size=0x00400000, file=images/romfs.img<br />
mem_bank: map=M, type=RW, addr=0x02000000, size=0x00400000<br />
mem_bank: map=M, type=RW, addr=0x02400000, size=0x00008000<br />
mem_bank: map=M, type=RW, addr=0x04000000, size=0x00400000<br />
mem_bank: map=I, type=RW, addr=0xf0000000, size=0x10000000<br /><br /><br />
这个时候就可以用skyeye来调试运行kernel了，在/usr/src/uClinux-dist执行如下命令：<br /><br />
skyeye linux-2.4.x/linux<br /><br />
(skyeye)target sim<br /><br />
(skyeye)load<br /><br />
(skyeye)run<br /><br />
kernel start.....<br /><br />
注意:<br />
要在skyeye.conf所在目录下执行skyeye linux-2.4.x/linux<br /><br /><br /><font color="blue"><b>9、加入网络功能</b></font><br />
a.用root用户进行操作。<br />
b.你要看你的/lib/modules/'uname -r'/kernel/drivers/net/目录里有没有tun.o<br />
  如果没有的话你就需要编译你的linux内核来获得tun.o了。<br />
c.(1)运行tun设备模块：<br /><br />
     #insmod /lib/modules/'uname -r'/kernel/drivers/net/tun.o<br /><br />
     如果你没有该设备，那你就要用下面的命令来创建它：<br /><br />
     #mkdir /dev/net<br />
     #mknod /dev/net/tun c 10 200<br /><br />
  (2)运行vnet(虚拟集线器)设备模块(这一步不是必需的)：<br />
     获取vnet的源码，然后创建设备：<br /><br />
     #mknod /dev/net/vnet c 10 201<br />
     #chmod 666 /dev/net/vnet<br /><br />
     创建vnet.o<br />
     #make vnet.o<br /><br />
     插入模块vnet.o<br />
     #insmod vnet.o<br /><br />
     进入test目录，用test来测度vnet.o<br />
     #cd test<br />
     #make<br />
     #./testvnet1<br /><br />
d.配置skyeye.conf文件<br /><br />
cpu: arm7tdmi<br />
mach: at91<br />
mem_bank: map=M, type=RW, addr=0x00000000, size=0x00004000<br />
mem_bank: map=M, type=RW, addr=0x01000000, size=0x00400000<br />
mem_bank: map=M, type=R,  addr=0x01400000, size=0x00400000, file=images/romfs.img<br />
mem_bank: map=M, type=RW, addr=0x02000000, size=0x00400000<br />
mem_bank: map=M, type=RW, addr=0x02400000, size=0x00008000<br />
mem_bank: map=M, type=RW, addr=0x04000000, size=0x00400000<br />
mem_bank: map=I, type=RW, addr=0xf0000000, size=0x10000000<br />
# format: state=on/off mac=xx:xx:xx:xx:xx:xx ethmod=tuntap/vnet hostip=dd.dd.dd.dd<br />
net: state=on, mac=0:4:3:2:1:f, ethmod=tun, hostip=10.0.0.1<br /><br /><br />
下面将对上面的一些参数作下说明：<br />
state=on/off意思是仿真的NIC(网络接口板)是有线的还是无线的；<br />
mac=仿真适配器的MAC地址；<br />
ethmod=tuntap/vnet在主机环境里使用的虚拟设备；<br />
hostip=意思是主机环境与keyeye交互用的IP<br />
格式: state=on/off mac=xx:xx:xx:xx:xx:xx ethmod=tuntap/vnet hostip=dd.dd.dd.dd<br /><br />
For example:<br />
#set nic info state=on/off  mac=xx:xx:xx:xx:xx:xx  ethmod=tuntap/vnet hostip=dd.dd.dd.dd<br />
net: state=on, mac=0:4:3:2:1:f, ethmod=tun, hostip=10.0.0.1<br />
或<br />
net: state=on, mac=0:4:3:2:1:f, ethmod=vnet, hostip=10.0.0.1<br /><br />
注意：<br />
如果你想在同一时刻运行两个或更多的skyeye,那么请为每一个skyeye使用不同的skyeye.conf<br /><br />
e.运行skyeye linux-2.4.x/linux<br /><br /><font color="red"><font size="5"><b>10、安装完成SkyEye后，下一步将做什么？</b></font></font><br /><br />
1、对于嵌入式操作系统的初学者和入门者和入门的学生而言，他们可以先看一些有关操作系统和嵌入式操作系统方面的教材和书籍，如与<br /><br />
uC/OS、Minix、uClinux、Linux相关的书籍等。然后可以在Skyeye上开发一些简单的应用程序例子(如进程间通信、进程优先级、死锁情况、网<br /><br />
络应用等)，对某些操作系统功能(如进程调度、内存管理、网络子系统、文件子系统等)进行简单的修改和扩展，并通过Skyeye进行运行和调试<br /><br />
，看看会发生什么情况。<br /><br />
2、对于有一定经验的软件工程师而言，在SkyEye上完成一定的应用系统原型开发是值得一做的事情。比如移植或开发一个文件子系统或网络子<br /><br />
系统到一个特定的操作系统中，相信比在一个真实的开发板上开发要容易一些。在Skyeye上进行一些操作系统的移植和开发(如移植RTLinux、<br /><br />
RTAI等其它操作系统到Skyeye上)也是很有挑战性的工作。<br /><br />
3、对于硬件工程师而言，对Skyeye进行扩充，设计新的硬件仿真(如USB、IDE硬盘等)使得Skyeye的硬件仿真功能更加强大，支持更多功能的软<br /><br />
件，是很有意义的事情。<br /><br />
参考：<br />
SkyEye项目站点里的一篇中文文档；<br />
陈渝《SkyEye Project FAQ》；<br />
skyeye-0.7.0中的README文档。<br /><br />
后记：<br />
为了让大家能快速上手，进行实际的开发工作，我赶凑了一篇文档，很粗糙。但我坚信随着更多的有经验的人的加入；随着我们自己水平的提<br /><br />
高，一定会出现更多、更好的文章来。就让我们快点行动起来吧！<br /><br />
最后，我再次建议大家看一下《嵌入式Linux技术与应用》这本书。<br /><br />
可以到<a href="http://www.skyeye.org/document.htm" target="_blank">http://www.skyeye.org/document.htm</a>或是<br /><a href="ftp://166.111.68.183/pub/embed/skyeye/document/" target="_blank">ftp://166.111.68.183/pub/embed/skyeye/document/</a>或是<br /><a href="http://www.huihoo.org/mirrors/skyeye/" target="_blank">http://www.huihoo.org/mirrors/skyeye/</a><br />
下载文档，可以获得更多有关skyeye和嵌入式Linux开发的知识和经验。<img src ="http://www.cnitblog.com/schkui/aggbug/19044.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">爱易</a> 2006-11-10 13:38 <a href="http://www.cnitblog.com/schkui/archive/2006/11/10/19044.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>嵌入式Linux的GDB远程调试的实现</title><link>http://www.cnitblog.com/schkui/archive/2006/11/10/19043.html</link><dc:creator>爱易</dc:creator><author>爱易</author><pubDate>Fri, 10 Nov 2006 05:23:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/11/10/19043.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/19043.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2006/11/10/19043.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/19043.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/19043.html</trackback:ping><description><![CDATA[远程调试环境由宿主机GDB和目标机调试stub共同构成，两者通过串口或TCP连接。使用GDB标准远程串行协议协同工作，实现对目标机上的系统内核和
上层应用的监控和调试功能。调试stub是嵌入式系统中的一段代码，作为宿主机GDB和目标机调试程序间的一个媒介而存在。<br />         
就目前而言，嵌入式Linux系统中，主要有三种远程调试方法，分别适用于不同场合的调试工作：用ROM
Monitor调试目标机程序、用KGDB调试系统内核和用gdbserver调试用户空间程序。这三种调试方法的区别主要在于，目标机远程调试stub
的存在形式的不同，而其设计思路和实现方法则是大致相同的。<br />而我们最常用的是调试应用程序。就是采用gdb+gdbserver的方式进行调试。
在很多情况下，用户需要对一个应用程序进行反复调试，特别是复杂的程序。采用GDB方法调试，由于嵌入式系统资源有限性，一般不能直接在目标系统上进行调
试，通常采用gdb+gdbserver的方式进行调试。Gdbserver在目标系统中运行，gdb则在宿主机上运行。<br />要进行GDB调试，目标
系统必须包括gdbserver程序，宿主机也必须安装gdb程序。一般linux发行版中都有一个可以运行的gdb，但开发人员不能直接使用该发行版中
的gdb来做远程调试，而要获取gdb的源代码包，针对arm平台作一个简单配置，重新编译得到相应gdb。gdb的源代码包可以从http:
//ftp.cs.pu.edu.tw/Linux/sourceware/gdb/releases/下载，最新版本为gdb-6.4。下载到某个目
录，笔者下载到自己的用户目录：/home/vicky。<br />下载完后，进入/home/vicky目录，配置编译步骤如下：<br />#tar jxvf gdb-6.4-tar-bz2<br />#cd gdb-6.4<br />#./configure --target=arm-linux --prefix=/usr/local/arm-gdb -v<br />#make<br />(这一步的时候可能会有问题，提示一个函数中（具体函数名不记得了）parse error，就是unsigned前边多了一个”}”,你用vi进入那一行把它删掉就行了。)<br />#make install<br />#export PATH=$PATH:/usr/local/arm-gdb<br />进入gdbserver目录：<br />#./configure --target=arm-linux –host=arm-linux<br />#make CC=/usr/local/arm/2.95.3/bin/arm-linux-gcc<br />(这一步要指定arm-linux-gcc的位置，可能跟你的不一样)<br />没有错误的话就在gdbserver目录下生成gdbserver可执行文件，把它烧写到flash的根文件系统分区，或通过nfs mount的方式都可以。只要保证gdbserver能在开发板上运行就行。<br />下
面就可以用gdb+gdbserver调试我们开发板上的程序了。在目标板上运行gdbserver，其实就是在宿主机的minicom下，我的red
hat linux装在vmware下的。我是在minicom下#mount 192.168.2.100:/ /tmp后做的(这里参数-o
nolock可以不加，不加这一步执行得反而更快些)，hello和gdbserver都是位于linux根目录下，把主机根目录挂在到开发板的/tmp
目录下。<br />要进行gdb调试，首先要在目标系统上启动gdbserver服务。在gdbserver所在目录下输入命令：<br />(minicom下)<br />#cd /tmp<br />#./gdbserver 192.168.2.100:2345 hello<br />192.168.2.100为宿主机IP，在目标系统的2345端口开启了一个调试进程，hello为要调试的程序。<br />出现提示：<br />Process /tmp/hello created: pid=80<br />Listening on port 2345
<p>(另一个终端下)<br />#cd /<br />#export PATH=$PATH:/usr/local/arm-gdb/bin<br />#arm-linux-gdb hello<br />(gdb) target remote 192.168.2.223:2345<br />（192.168.2.223为开发板IP）<br />出现提示：<br />Remote debugging using 192.168.2.223:2345<br />[New thread 80]<br />[Switching to thread 80]<br />0x40002a90 in ??()<br />同时在minicom下提示：<br />Remote debugging from host 192.168.2.100<br />(gdb)<br />连接成功，这时候就可以输入各种gdb命令如list、run、next、step、break等进行程序调试了。</p><p>         以上针对通过nfs mount和tftp的方式，只能在主机上调试好后下载到开发板上运行，如果有错误要反复这个过程，繁琐不说，有些程序只能在开发板上调试。所以笔者采用了gdbserver的远程调试方式。希望对大家调试程序有用！</p><img src ="http://www.cnitblog.com/schkui/aggbug/19043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">爱易</a> 2006-11-10 13:23 <a href="http://www.cnitblog.com/schkui/archive/2006/11/10/19043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ARM开发的调试方法概述</title><link>http://www.cnitblog.com/schkui/archive/2006/05/31/11330.html</link><dc:creator>爱易</dc:creator><author>爱易</author><pubDate>Wed, 31 May 2006 08:21:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/05/31/11330.html</guid><description><![CDATA[
		<font face="宋体">用户选用ARM处理器开发嵌入式系统时，选择合适的开发工具可以加快开发进度，节省开发成本。因此一套含有编辑软件、编
译软件、汇编软件、链接软件、调试软件、工程管理及函数库的集成开发环境（IDE）一般来说是必不可少的，至于嵌入式实时操作系统、评估板等其他开发工具
则可以根据应用软件规模和开发计划选用。 <br />    使用集成开发环境开发基于ARM的应用软件，包括编辑、编译、汇编、链接等工作全部在PC机上即可完成，调试工作则需要配合其他的模块或产品方可完成，目前常见的调试方法有以下几种： <br />1、指令集模拟器 <br />    
部分集成开发环境提供了指令集模拟器，可方便用户在PC机上完成一部分简单的调试工作，但是由于指令集模拟器与真实的硬件环境相差很大，因此即使用户使用
指令集模拟器调试通过的程序也有可能无法在真实的硬件环境下运行，用户最终必须在硬件平台上完成整个应用的开发。 <br />2、驻留监控软件 <br />    
驻留监控软件（Resident Monitors）是一段运行在目标板上的程序，集成开发环境中的调试软件通过以太网口、并行端口、串行端口等通讯端口
与驻留监控软件进行交互，由调试软件发布命令通知驻留监控软件控制程序的执行、读写存储器、读写寄存器、设置断点等。 <br />    驻留监控软件是一种比较低廉有效的调试方式，不需要任何其他的硬件调试和仿真设备。ARM公司的Angel就是该类软件，大部分嵌入式实时操作系统也是采用该类软件进行调试，不同的是在嵌入式实时操作系统中，驻留监控软件是作为操作系统的一个任务存在的。 <br />    驻留监控软件的不便之处在于它对硬件设备的要求比较高，一般在硬件稳定之后才能进行应用软件的开发，同时它占用目标板上的一部分资源，而且不能对程序的全速运行进行完全仿真，所以对一些要求严格的情况不是很适合。 <br />3、JTAG仿真器 <br />    JTAG
仿真器也称为JTAG调试器，是通过ARM芯片的JTAG边界扫描口进行调试的设备。JTAG仿真器比较便宜，连接比较方便，通过现有的JTAG边界扫描
口与 ARM CPU 核通信，属于完全非插入式(即不使用片上资源)调试，它无需目标存储器，不占用目标系统的任何端口，而这些是驻留监控软件所必需
的。另外，由于JTAG调试的目标程序是在目标板上执行，仿真更接近于目标硬件，因此，许多接口问题，如高频操作限制、AC和DC参数不匹配，电线长度的
限制等被最小化了。使用集成开发环境配合JTAG仿真器进行开发是目前采用最多的一种调试方式。 <br />4、在线仿真器 <br />    在线仿真器使
用仿真头完全取代目标板上的CPU，可以完全仿真ARM芯片的行为，提供更加深入的调试功能。但这类仿真器为了能够全速仿真时钟速度高于100MHz的处
理器，通常必须采用极其复杂的设计和工艺，因而其价格比较昂贵。在线仿真器通常用在ARM的硬件开发中，在软件的开发中较少使用，其价格高昂也是在线仿真
器难以普及的因素。</font>
<img src ="http://www.cnitblog.com/schkui/aggbug/11330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">爱易</a> 2006-05-31 16:21 <a href="http://www.cnitblog.com/schkui/archive/2006/05/31/11330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载：嵌入式设备上的 Linux 系统开发</title><link>http://www.cnitblog.com/schkui/archive/2006/05/30/11251.html</link><dc:creator>爱易</dc:creator><author>爱易</author><pubDate>Tue, 30 May 2006 10:41:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/05/30/11251.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/11251.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2006/05/30/11251.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/11251.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/11251.html</trackback:ping><description><![CDATA[
		<p>级别: 初级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#author">Anand K Santhanam</a>, 软件工程师, IBM Global Services<br /><a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#author">Vishal Kulkarni</a>, 软件工程师, IBM Global Services<br /></p>
		<p>2002 年  3 月  01 日</p>
		<blockquote>如
果您刚接触嵌入式开发，那么大量可用的引导装载程序（bootloader）、规模缩小的分发版（distribution）、文件系统和 GUI
看起来可能太多了。但是这些丰富的选项实际上是一种恩赐，允许您调整开发或用户环境以完全符合您的需要。对 Linux
嵌入式开发的概述将帮助您理解所有这些选项。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>Linux 正在嵌入式开发领域稳步发展。因为 Linux 使用 GPL（请参阅本文后面的
        <a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#resources">参考资料</a>），
所以任何对将 Linux 定制于 PDA、掌上机或者可佩带设备感兴趣的人都可以从因特网免费下载其内核和应用程序，并开始移植或开发。许多
Linux 改良品种迎合了嵌入式／实时市场。它们包括 RTLinux（实时 Linux）、uclinux（用于非 MMU 设备的
Linux）、Montavista Linux（用于 ARM、MIPS、PPC 的 Linux 分发版）、ARM-Linux（ARM 上的
Linux）和其它 Linux 系统（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#resources">参考资料</a>以链接到本文中提到的这些和其它术语及产品。）
      </p>
		<p>嵌
入式 Linux 开发大致涉及三个层次：引导装载程序、Linux 内核和图形用户界面（或称
GUI）。在本文中，我们将集中讨论涉及这三层的一些基本概念；深入了解引导装载程序、内核和文件系统是如何交互的；并将研究可用于文件系统、GUI
和引导装载程序的众多选项中的一部分。</p>
		<p>
				<a name="1">
						<span class="atitle">引导装载程序</span>
				</a>
		</p>
		<p>引
导装载程序通常是在任何硬件上执行的第一段代码。在象台式机这样的常规系统中，通常将引导装载程序装入主引导记录（Master Boot
Record，(MBR)）中，或者装入 Linux 驻留的磁盘的第一个扇区中。通常，在台式机或其它系统上，BIOS
将控制移交给引导装载程序。这就提出了一个有趣的问题：谁将引导装载程序装入（在大多数情况中）没有 BIOS 的嵌入式设备上呢？</p>
		<p>解决这个问题有两种常规技术：专用软件和微小的引导代码（tiny bootcode）。</p>
		<p>
				<b>专用软件</b>可以直接与远程系统上的闪存设备进行交互并将引导装载程序安装在闪存的给定位置中。
        <i>闪存设备</i>是与存储设备功能类似的特殊芯片，而且它们能持久存储信息 ― 即，在重新引导时不会擦除其内容。
      </p>
		<p>这个软件使用目标（在嵌入式开发中，嵌入式设备通常被称为
        <i>目标</i>）上的 JTAG 端口，它是用于执行外部输入（通常来自主机机器）的指令的接口。JFlash-linux 是一种用于直接写闪存的流行工具。它支持为数众多的闪存芯片；它在主机机器（通常是 i386 机器 ― 本文中我们把一台 i386 机器称为
        <i>主机</i>）上执行并通过 JTAG 接口使用并行端口访问目标的闪存芯片。当然，这意味着目标需要有一个并行接口使它能与主机通信。Jflash-linux 在 Linux 和 Windows 版本中都可使用，可以在命令行中用以下命令启动它：
        <br /></p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">Jflash-linux &lt;bootloader&gt;</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>某些种类的嵌入式设备具有
        <b>微小的引导代码</b>― 根据几个字节的指令 ― 它将初始化一些 DRAM 设置并启用目标上的一个串行（或者 USB，或者以太网）端口与主机程序通信。然后，主机程序或装入程序可以使用这个连接将引导装载程序传送到目标上，并将它写入闪存。
      </p>
		<p>在安装它并给予其控制后，这个引导装载程序执行下列各类功能：</p>
		<ul>
				<li>初始化 CPU 速度</li>
				<li>初始化内存，包括启用内存库、初始化内存配置寄存器等</li>
				<li>初始化串行端口（如果在目标上有的话）</li>
				<li>启用指令／数据高速缓存</li>
				<li>设置堆栈指针</li>
				<li>设置参数区域并构造参数结构和标记（这是重要的一步，因为内核在标识根设备、页面大小、内存大小以及更多内容时要使用引导参数）</li>
				<li>执行 POST（加电自检）来标识存在的设备并报告任何问题</li>
				<li>为电源管理提供挂起／恢复支持</li>
				<li>跳转到内核的开始</li>
		</ul>
		<p>带有引导装载程序、参数结构、内核和文件系统的系统典型内存布局可能如下所示：</p>
		<br />
		<a name="code1">
				<b>清单 1. 典型内存布局</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">   /* Top Of Memory */ <br /><br />        Bootloader<br />        Parameter Area <br />        Kernel <br />        Filesystem<br /><br />    /* End Of Memory */ <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>嵌入式设备上一些流行的并可免费使用的 Linux 引导装载程序有 Blob、Redboot 和 Bootldr（请参阅
        <a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#resources">参考资料</a>获得链接）。所有这些引导装载程序都用于基于 ARM 设备上的 Linux，并需要 Jflash-linux 工具用于安装。
      </p>
		<p>一旦将引导装载程序安装到目标的闪存中，它就会执行我们上面提到的所有初始化工作。然后，它准备接收来自主机的内核和文件系统。一旦装入了内核，引导装载程序就将控制转给内核。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="2">
						<span class="atitle">设置工具链</span>
				</a>
		</p>
		<p>设置工具链在主机机器上创建一个用于编译将在目标上运行的内核和应用程序的构建环境 ― 这是因为目标硬件可能没有与主机兼容的二进制执行级别。</p>
		<p>工具链由一套用于编译、汇编和链接内核及应用程序的组件组成。 这些组件包括：</p>
		<ul>
				<li>
						<b>Binutils</b> ― 用于操作二进制文件的实用程序集合。它们包括诸如 
          <code>ar</code> 、 
          <code>as</code> 、 
          <code>objdump</code> 、 
          <code>objcopy</code> 这样的实用程序。
        </li>
				<li>
						<b>Gcc</b>― GNU C 编译器。
        </li>
				<li>
						<b>Glibc</b>― 所有用户应用程序都将链接到的 C 库。避免使用任何 C 库函数的内核和其它应用程序可以在没有该库的情况下进行编译。
        </li>
		</ul>
		<p>构建工具链建立了一个交叉编译器环境。
        <i>本地编译器</i>编译与本机同类的处理器的指令。
        <i>交叉编译器</i>运
行在某一种处理器上，却可以编译另一种处理器的指令。重头设置交叉编译器工具链可不是一项简单的任务：它包括下载源代码、修补补丁、配置、编译、设置头文
件、安装以及很多很多的操作。另外，这样一个彻底的构建过程对内存和硬盘的需求是巨大的。如果没有足够的内存和硬盘空间，那么在构建阶段由于相关性、配置
或头文件设置等问题会突然冒出许多问题。 </p>
		<p>因此能够从因特网上获得已预编译的二进制文件是一件好事（但不太好的一点是，目前它们大多数只限于基于
ARM 的系统，但迟早会改变的）。一些比较流行的已预编译的工具链包括那些来自 Compaq（Familiar Linux
）、LART（LART Linux）和 Embedian（基于 Debian 但与它无关）的工具链 ― 所有这些工具链都用于基于 ARM
的平台。</p>
		<p>
				<a name="N100FA">
						<span class="smalltitle">内核设置</span>
				</a>
		</p>
		<p>Linux
社区正积极地为新硬件添加功能部件和支持、在内核中修正错误并且及时地进行常规改进。这导致大约每 6 个月（或 6 个月不到）就有一个稳定的
Linux
树的新发行版。不同的维护者维护针对特定体系结构的不同内核树和补丁。当为一个项目选择了一个内核时，您需要评估最新发行版的稳定性如何、它是否符合项目
要求和硬件平台、从编程角度来看它的舒适程度以及其它难以确定的方面。还有一点也非常重要：找到需要应用于基本内核的所有补丁，以便为特定的体系结构调整
内核。</p>
		<p>
				<a name="N10103">
						<span class="smalltitle">内核布局</span>
				</a>
		</p>
		<p>内
核布局分为特定于体系结构的部分和与体系结构无关的部分。内核中特定于体系结构的部分首先执行，设置硬件寄存器、配置内存映射、执行特定于体系结构的初始
化，然后将控制转给内核中与体系结构无关的部分。系统的其余部分在这第二个阶段期间进行初始化。内核树下的目录 arch/
由不同的子目录组成，每个子目录用于一个不同的体系结构（MIPS、ARM、i386、SPARC、PPC 等）。每一个这样的子目录都包含
kernel/ 和 mm/ 子目录，它们包含特定于体系结构的代码来完成象初始化内存、设置
IRQ、启用高速缓存、设置内核页面表等操作。一旦装入内核并给予其控制，就首先调用这些函数，然后初始化系统的其余部分。</p>
		<p>根据可用的系统资源和引导装载程序的功能，内核可以编译成 vmlinux、Image 或 zImage。vmlinux 和 zImage 之间的主要区别在于
        <i>vmlinux</i>是实际的（未压缩的）可执行文件，而
        <i>zImage</i>是或多或少包含相同信息的自解压压缩文件 ― 只是压缩它以处理（通常是 Intel 强制的）640 KB 引导时间的限制。有关所有这些的权威性解释，请参阅
        <i>Linux Magazine</i>的文章“Kernel Configuration: dealing with the unexpected”（请参阅
        <a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#resources">参考资料</a>）。
      </p>
		<p>
				<a name="N1011C">
						<span class="smalltitle">内核链接和装入</span>
				</a>
		</p>
		<p>一
旦为目标系统编译了内核后，通过使用引导装载程序（它已经被装入到目标的闪存中），内核就被装入到目标系统的内存（在 DRAM
中或者在闪存中）。通过使用串行、USB 或以太网端口，引导装载程序与主机通信以将内核传送到目标的闪存或 DRAM
中。在将内核完全装入目标后，引导装载程序将控制传递给装入内核的地址。</p>
		<p>内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节，如文本、数据、init 数据、bass 等等。这些对象文件都是由一个称为
        <i>链接器脚本</i>的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中；换句话说，它将所有输入对象文件都链接到单一的可执行文件中，将该可执行文件的各节装入到指定地址处。
        <i>vmlinux.lds</i>是存在于 arch/&lt;target&gt;/ 目录中的内核链接器脚本，它负责链接内核的各个节并将它们装入内存中特定偏移量处。典型的 vmlinux.lds 看起来象这样：
      </p>
		<br />
		<a name="code2">
				<b>清单 2. 典型的 vmlinux.lds 文件</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">OUTPUT_ARCH(&lt;arch&gt;)      /* &lt;arch&gt; includes architecture type */ <br /> ENTRY(stext)               /* stext is the kernel entry point */ <br /> SECTIONS                   /* SECTIONS command describes the layout<br />                   of the output file */ <br /> { <br />     .  = TEXTADDR;         /* TEXTADDR is LMA for the kernel */ <br />     .init : {          /* Init code and data*/ <br />              _stext = .;       /* First section is stext followed <br />                   by __init data section */ <br />              __init_begin = .; <br />                     *(.text.init) <br />              __init_end = .; <br />             } <br />     .text : {          /* Real text segment follows __init_data section */ <br />              _text = .; <br />                     *(.text) <br />              _etext = .;       /* End of text section*/ <br />             } <br />     .data :{ <br />              _data=.;          /* Data section comes after text section */ <br />                     *(.data) <br />              _edata=.;  <br />             }                  /* Data section ends here */ <br />     .bss : {                   /* BSS section follows symbol table section */ <br />              __bss_start = .; <br />                     *(.bss) <br />              _end = . ;        /* BSS section ends here */  <br />             } <br />  } <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>LMA</code> 是装入模块地址；它表示将要装入内核的目标虚拟内存中的地址。 
        <code>TEXTADDR</code> 是内核的虚拟起始地址，并且在 arch/&lt;target&gt;/ 下的 Makefile 中指定它的值。这个地址必须与引导装载程序使用的地址相匹配。
      </p>
		<p>一旦引导装载程序将内核复制到闪存或 DRAM 中，内核就被重新定位到 
        <code>TEXTADDR</code> — 它通常在 DRAM 中。然后，引导装载程序将控制转给这个地址，以便内核能开始执行。
      </p>
		<p>
				<a name="N1014A">
						<span class="smalltitle">参数传递和内核引导</span>
				</a>
		</p>
		<p>
				<code>stext</code> 是内核入口点，这意味着在内核引导时将首先执行这一节下的代码。它通常用汇编语言编写，并且通常它在 arch/&lt;target&gt;/ 内核目录下。这个代码设置内核页面目录、创建身份内核映射、标识体系结构和处理器以及执行分支 
        <code>start_kernel</code> （初始化系统的主例程）。
      </p>
		<p>
				<code>start_kernel</code> 调用 
        <code>setup_arch</code> 作为执行的第一步，在其中完成特定于体系结构的设置。这包括初始化硬件寄存器、标识根设备和系统中可用的 DRAM 和闪存的数量、指定系统中可用页面的数目、文件系统大小等等。所有这些信息都以参数形式从引导装载程序传递到内核。
      </p>
		<p>将参数从引导装载程序传递到内核有两种方法：parameter_structure 和标记列表。在这两种方法中，不赞成使用参数结构，因为它强加了限制：指定在内存中，每个参数必须位于 
        <code>param_struct</code> 中的特定偏移量处。最新的内核期望参数作为标记列表的格式来传递，并将参数转化为已标记格式。 
        <code>param_struct</code> 定义在 include/asm/setup.h 中。它的一些重要字段是：
      </p>
		<br />
		<a name="code3">
				<b>清单 3. 样本参数结构</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">struct param_struct  { <br />  unsigned long page_size;     /* 0:  Size of the page  */ <br />  unsigned long nr_pages;      /* 4:  Number of pages in the system */ <br />  unsigned long ramdisk        /* 8: ramdisk size */ <br />  unsigned long rootdev;       /* 16: Number representing the root device */ <br />  unsigned long initrd_start;  /* 64: starting address of initial ramdisk */<br />                                      /* This can be either in flash/dram */ <br />  unsigned long initrd_size;   /* 68: size of initial ramdisk */ <br /> }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>请注意：这些数表示定义字段的参数结构中的偏
移量。这意味着如果引导装载程序将参数结构放置在地址 0xc0000100，那么 rootdev 参数将放置在 0xc0000100 +
16，initrd_start 将放置在 0xc0000100 + 64 等等 ― 否则，内核将在解释正确的参数时遇到困难。</p>
		<p>正
如上面提到的，因为从引导装载程序到内核的参数传递会有一些约束条件，所以大多数 2.4.x
系列内核期望参数以已标记的列表格式传递。在已标记的列表中，每个标记由标识被传递参数的 tag_header
以及其后的参数值组成。标记列表中标记的常规格式可以如下所示：</p>
		<br />
		<a name="code4">
				<b>清单 4. 样本标记格式。内核通过 &lt;ATAG_TAGNAME&gt; 头来标识每个标记。</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">#define &lt;aTAG_TAGNAME&gt;  &lt;Some Magic number&gt; <br /><br /> struct &lt;tag_tagname&gt; { <br />         u32 &lt;tag_param&gt;; <br />         u32 &lt;tag_param&gt;; <br /> }; <br /><br /> /* Example tag for passing memory information */ <br /><br /> #define ATAG_MEM        0x54410002  /* Magic number */ <br /><br /> struct tag_mem32 { <br />         u32     size;               /* size of memory */ <br />         u32     start;              /* physical start address of memory*/ <br /> }; <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>setup_arch</code> 还需要对闪存存储库、系统寄存器和其它特定设备执行内存映射。一旦完成了特定于体系结构的设置，控制就返回到初始化系统其余部分的 start_kernel 函数。这些附加的初始化任务包含：
      </p>
		<ul>
				<li>设置陷阱</li>
				<li>初始化中断</li>
				<li>初始化计时器</li>
				<li>初始化控制台</li>
				<li>调用 
          <code>mem_init</code> ，它计算各种区域、高内存区等内的页面数量
        </li>
				<li>初始化 slab 分配器并为 VFS、缓冲区高速缓存等创建 slab 高速缓存</li>
				<li>建立各种文件系统，如 proc、ext2 和 JFFS2</li>
				<li>创建 
          <code>kernel_thread</code> ，它执行文件系统中的 init 命令并显示 lign 提示符。 如果在 /bin、/sbin 或 /etc 中没有 init 程序，那么内核将执行文件系统的 /bin 中的 shell。
        </li>
		</ul>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="3">
						<span class="atitle">设备驱动程序</span>
				</a>
		</p>
		<p>嵌
入式系统通常有许多设备用于与用户交互，象触摸屏、小键盘、滚动轮、传感器、RA232 接口、LCD
等等。除了这些设备外，还有许多其它专用设备，包括闪存、USB、GSM 等。内核通过所有这些设备各自的设备驱动程序来控制它们，包括 GUI
用户应用程序也通过访问这些驱动程序来访问设备。本节着重讨论通常几乎在每个嵌入式环境中都会使用的一些重要设备的设备驱动程序。</p>
		<p>
				<a name="N101BE">
						<span class="smalltitle">帧缓冲区驱动程序</span>
				</a>
		</p>
		<p>这
是最重要的驱动程序之一，因为通过这个驱动程序才能使系统屏幕显示内容。帧缓冲区驱动程序通常有三层。最底层是基本控制台驱动程序
drivers/char/console.c，它提供了文本控制台常规接口的一部分。通过使用控制台驱动程序函数，我们能将文本打印到屏幕上 ―
但图形或动画还不能（这样做需要使用视频模式功能，通常出现在中间层，也就是 drivers/video/fbcon.c
中）。这个第二层驱动程序提供了视频模式中绘图的常规接口。</p>
		<p>帧缓冲区是显卡上的内存，需要将它内存映射到用户空间以便可以将图形
和文本能写到这个内存段上：然后这个信息将反映到屏幕上。帧缓冲区支持提高了绘图的速度和整体性能。这也是顶层驱动程序引人注意之处：顶层是非常特定于硬
件的驱动程序，它需要支持显卡不同的硬件方面 ―
象启用／禁用显卡控制器、深度和模式的支持以及调色板等。所有这三层都相互依赖以实现正确的视频功能。与帧缓冲区有关的设备是
/dev/fb0（主设备号 29，次设备号 0）。</p>
		<p>
				<a name="N101CA">
						<span class="smalltitle">输入设备驱动程序</span>
				</a>
		</p>
		<p>可触摸板是用于嵌入式设备的最基本的用户交互设备之一 ― 小键盘、传感器和滚动轮也包含在许多不同设备中以用于不同的用途。</p>
		<p>触摸板设备的主要功能是随时报告用户的触摸，并标识触摸的坐标。这通常在每次发生触摸时，通过生成一个中断来实现。</p>
		<p>然后，这个设备驱动程序的角色是每当出现中断时就查询触摸屏控制器，并请求控制器发送触摸的坐标。一旦驱动程序接收到坐标，它就将有关触摸和任何可用数据的信号发送给用户应用程序，并将数据发送给应用程序（如果可能的话）。然后用户应用程序根据它的需要处理数据。</p>
		<p>几乎所有输入设备 ― 包括小键盘 ― 都以类似原理工作。</p>
		<p>
				<a name="N101DC">
						<span class="smalltitle">闪存 MTD 驱动程序</span>
				</a>
		</p>
		<p>MTD 设备是象闪存芯片、小型闪存卡、记忆棒等之类的设备，它们在嵌入式设备中的使用正在不断增长。</p>
		<p>MTD
驱动程序是在 Linux 下专门为嵌入式环境开发的新的一类驱动程序。相对于常规块设备驱动程序，使用 MTD 驱动程序的主要优点在于 MTD
驱动程序是专门为基于闪存的设备所设计的，所以它们通常有更好的支持、更好的管理和基于扇区的擦除和读写操作的更好的接口。Linux 下的 MTD
驱动程序接口被划分为两类模块：用户模块和硬件模块。</p>
		<p>
				<b>用户模块</b>
				<br />这些模块提供从用
户空间直接使用的接口：原始字符访问、原始块访问、FTL（闪存转换层，Flash Transition Layer ―
用在闪存上的一种文件系统）和 JFS（即日志文件系统，Journaled File System ―
在闪存上直接提供文件系统而不是模拟块设备）。用于闪存的 JFS 的当前版本是 JFFS2（稍后将在本文中描述）。 </p>
		<p>
				<b>硬件模块</b>
				<br />这些模块提供对内存设备的物理访问，但并不直接使用它们。通过上述的用户模块来访问它们。这些模块提供了在闪存上读、擦除和写操作的实际例程。
      </p>
		<p>
				<b>MTD 驱动程序设置</b>
				<br />为了访问特定的闪存设备并将文件系统置于其上，需要将 MTD 子系统编译到内核中。这包括选择适当的 MTD 硬件和用户模块。当前，MTD 子系统支持为数众多的闪存设备 ― 并且有越来越多的驱动程序正被添加进来以用于不同的闪存芯片。
      </p>
		<p>有两个流行的用户模块可启用对闪存的访问： 
        <code>MTD_CHAR</code> 和 
        <code>MTD_BLOCK</code> 。
      </p>
		<p>
				<code>MTD_CHAR</code> 提供对闪存的原始字符访问，而 
        <code>MTD_BLOCK</code> 将闪存设计为可以在上面创建文件系统的常规块设备（象 IDE 磁盘）。与 
        <code>MTD_CHAR</code> 关联的设备是 /dev/mtd0、mtd1、mtd2（等等），而与 
        <code>MTD_BLOCK</code> 关联的设备是 /dev/mtdblock0、mtdblock1（等等）。由于 
        <code>MTD_BLOCK</code> 设备提供象块设备那样的模拟，通常更可取的是在这个模拟基础上创建象 FTL 和 JFFS2 那样的文件系统。
      </p>
		<p>为了进行这个操作，可能需要创建分区表将闪存设备分拆到引导装载程序节、内核节和文件系统节中。样本分区表可能包含以下信息：</p>
		<br />
		<a name="code5">
				<b>清单 5. MTD 的简单闪存设备分区</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">struct mtd_partition sample_partition = { <br />      { <br />                                           /* First partition */ <br />            name : bootloader,             /* Bootloader section */ <br />            size    : 0x00010000,          /* Size  */ <br />            offset  : 0,          /* Offset from start of flash- location 0x0*/  <br />            mask_flags : MTD_WRITEABLE     /* This partition is not writable */ <br />      },  <br />      {                                    /* Second partition */ <br />            name : Kernel,                 /* Kernel section */ <br />            size    :  0x00100000,         /* Size */ <br />            offset : MTDPART_OFS_APPEND,   /* Append after bootloader section */ <br />            mask_flags : MTD_WRITEABLE     /* This partition is not writable */ <br />      },  <br />      {                                    /* Third partition */ <br />            name : JFFS2,                  /* JFFS2 filesystem */ <br />            size    :  MTDPART_SIZ_FULL,   /* Occupy rest of flash */ <br />            offset :  MTDPART_OFS_APPEND   /* Append after kernel section */ <br />      }<br /> }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面的分区表使用了 
        <code>MTD_BLOCK</code> 接口对闪存设备进行分区。这些分区的设备节点是：
      </p>
		<br />
		<a name="IDASLDEB">
				<b>简单闪存分区的设备节点</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section"> User      device node         Major number    Minor number<br /><br />  Bootloader    /dev/mtdblock0          31              0 <br />  Kernel        /dev/mtdblock1          31              1 <br />  Filesystem    /dev/mtdblock2          31              2 <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在本例中，引导装载程序必须将有关 root 设备节点（/dev/mtdblock2）和可以在闪存中找到文件系统的地址（本例中是 
        <code>FLASH_BASE_ADDRESS + 0x04000000</code> ）的正确参数传递到内核。一旦完成分区，闪存设备就准备装入或挂装文件系统。
      </p>
		<p>Linux 中 MTD 子系统的主要目标是在系统的硬件驱动程序和上层，或用户模块之间提供通用接口。硬件驱动程序不需要知道象 JFFS2 和 FTL 那样的用户模块使用的方法。所有它们真正需要提供的就是一组对底层闪存系统进行 
        <code>read</code> 、 
        <code>write</code> 和 
        <code>erase</code> 操作的简单例程。
      </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="4">
						<span class="atitle">嵌入式设备的文件系统</span>
				</a>
		</p>
		<p>
系统需要一种以结构化格式存储和检索信息的方法；这就需要文件系统的参与。Ramdisk（请参阅
        <a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#resources">参考资料</a>）是通过将计算机的 RAM 用作设备来创建和挂装文件系统的一种机制，它通常用于无盘系统（当然包括微型嵌入式设备，它只包含作为永久存储媒质的闪存芯片）。
      </p>
		<p>用户可以根据可靠性、健壮性和／或增强的功能的需求来选择文件系统的类型。下一节将讨论几个可用选项及其优缺点。</p>
		<p>
				<a name="N10266">
						<span class="smalltitle">第二版扩展文件系统（Ext2fs）</span>
				</a>
		</p>
		<p>
Ext2fs 是 Linux 事实上的标准文件系统，它已经取代了它的前任 ― 扩展文件系统（或 Extfs）。Extfs 支持的文件大小最大为
2 GB，支持的最大文件名称大小为 255 个字符 ― 而且它不支持索引节点（包括数据修改时间标记）。Ext2fs 做得更好；它的 <b>优点</b>是：
      </p>
		<ul>
				<li>Ext2fs 支持达 4 TB 的内存。</li>
				<li>Ext2fs 文件名称最长可以到 1012 个字符。</li>
				<li>当创建文件系统时，管理员可以选择逻辑块的大小（通常大小可选择 1024、2048 和 4096 字节）。</li>
				<li>Ext2fs 了实现快速符号链接：不需要为此目的而分配数据块，并且将目标名称直接存储在索引节点（inode）表中。这使性能有所提高，特别是在速度上。</li>
		</ul>
		<p>因为 Ext2 文件系统的稳定性、可靠性和健壮性，所以几乎在所有基于 Linux 的系统（包括台式机、服务器和工作站 ― 并且甚至一些嵌入式设备）上都使用 Ext2 文件系统。然而，当在嵌入式设备中使用 Ext2fs 时，它有一些
        <b>缺点</b>：
      </p>
		<ul>
				<li>Ext2fs 是为象 IDE 设备那样的块设备设计的，这些设备的逻辑块大小是 512 字节，1 K 字节等这样的倍数。这不太适合于扇区大小因设备不同而不同的闪存设备。</li>
				<li>Ext2
文件系统没有提供对基于扇区的擦除／写操作的良好管理。在 Ext2fs 中，为了在一个扇区中擦除单个字节，必须将整个扇区复制到
RAM，然后擦除，然后重写入。考虑到闪存设备具有有限的擦除寿命（大约能进行 100,000
次擦除），在此之后就不能使用它们，所以这不是一个特别好的方法。</li>
				<li>在出现电源故障时，Ext2fs 不是防崩溃的。</li>
				<li>Ext2 文件系统不支持损耗平衡，因此缩短了扇区／闪存的寿命。（损耗平衡确保将地址范围的不同区域轮流用于写和／或擦除操作以延长闪存设备的寿命。）</li>
				<li>Ext2fs 没有特别完美的扇区管理，这使设计块驱动程序十分困难。</li>
		</ul>
		<p>由于这些原因，通常相对于 Ext2fs，在嵌入式环境中使用 MTD/JFFS2 组合是更好的选择。</p>
		<p>
				<b>用 Ramdisk 挂装 Ext2fs</b>
				<br />通过使用 Ramdisk 的概念，可以在嵌入式设备中创建并挂装 Ext2 文件系统（以及用于这一目的的任何文件系统）。
      </p>
		<br />
		<a name="code6">
				<b>清单 6. 创建一个简单的基于 Ext2fs 的 Ramdisk</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section"> mke2fs -vm0 /dev/ram 4096<br />  mount -t ext2 /dev/ram /mnt<br />  cd /mnt<br />  cp /bin, /sbin, /etc, /dev ... files in mnt<br />  cd ../<br />  umount /mnt<br />  dd if=/dev/ram bs=1k count=4096 of=ext2ramdisk<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>mke2fs</code> 是用于在任何设备上创建 ext2 文件系统的实用程序 — 它创建超级块、索引节点以及索引节点表等等。
      </p>
		<p>在上面的用法中， 
        <code>/dev/ram</code> 是上面构建有 4096 个块的 ext2 文件系统的设备。然后，将这个设备（ 
        <code>/dev/ram</code> ）挂装在名为 
        <code>/mnt</code> 的临时目录上并且复制所有必需的文件。一旦复制完这些文件，就卸装这个文件系统并且设备（ 
        <code>/dev/ram</code> ）的内容被转储到一个文件（ext2ramdisk）中，它就是所需的 Ramdisk（Ext2 文件系统）。
      </p>
		<p>上面的顺序创建了一个 4 MB 的 Ramdisk，并用必需的文件实用程序来填充它。</p>
		<p>一些要包含在 Ramdisk 中的重要目录是：</p>
		<ul>
				<li>
						<b>/bin</b> ― 保存大多数象 
          <code>init</code> 、 
          <code>busybox</code> 、 
          <code>shell</code> 、文件管理实用程序等二进制文件。
        </li>
				<li>
						<b>/dev</b>― 包含用在设备中的所有设备节点
        </li>
				<li>
						<b>/etc</b>― 包含系统的所有配置文件
        </li>
				<li>
						<b>/lib</b>― 包含所有必需的库，如 libc、libdl 等
        </li>
		</ul>
		<p>
				<a name="N102F5">
						<span class="smalltitle">日志闪存文件系统，版本 2（JFFS2）</span>
				</a>
		</p>
		<p>
瑞典的 Axis Communications 开发了最初的 JFFS，Red Hat 的 David Woodhouse 对它进行了改进。
第二个版本，JFFS2，作为用于微型嵌入式设备的原始闪存芯片的实际文件系统而出现。JFFS2
文件系统是日志结构化的，这意味着它基本上是一长列节点。每个节点包含有关文件的部分信息 ― 可能是文件的名称、也许是一些数据。相对于
Ext2fs，JFFS2 因为有以下这些 <b>优点</b>而在无盘嵌入式设备中越来越受欢迎：
      </p>
		<ul>
				<li>JFFS2 在扇区级别上执行闪存擦除／写／读操作要比 Ext2 文件系统好。</li>
				<li>JFFS2
提供了比 Ext2fs 更好的崩溃／掉电安全保护。当需要更改少量数据时，Ext2
文件系统将整个扇区复制到内存（DRAM）中，在内存中合并新数据，并写回整个扇区。这意味着为了更改单个字，必须对整个扇区（64
KB）执行读／擦除／写例程 ― 这样做的效率非常低。要是运气差，当正在 DRAM
中合并数据时，发生了电源故障或其它事故，那么将丢失整个数据集合，因为在将数据读入 DRAM 后就擦除了闪存扇区。JFFS2
附加文件而不是重写整个扇区，并且具有崩溃／掉电安全保护这一功能。</li>
				<li>这可能是最重要的一点：JFFS2 是专门为象闪存芯片那样的嵌入式设备创建的，所以它的整个设计提供了更好的闪存管理。</li>
		</ul>
		<p>因为本文主要是写关于闪存设备的使用，所以在嵌入式环境中使用 JFFS2 的
        <b>缺点</b>很少：
      </p>
		<ul>
				<li>当文件系统已满或接近满时，JFFS2 会大大放慢运行速度。这是因为垃圾收集的问题（更多信息，请参阅
          <a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#resources">参考资料</a>）。
        </li>
		</ul>
		<p>
				<b>创建 JFFS2 文件系统</b>
				<br /> 在 Linux 下，用 
        <code>mkfs.jffs2</code> 命令创建 JFFS2 文件系统（基本上是使用 JFFS2 的 Ramdisk）。
      </p>
		<br />
		<a name="code7">
				<b>清单 7. 创建 JFFS2 文件系统</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">mkdir jffsfile <br /> cd jffsfile <br /><br /> /* copy all the /bin, /etc, /usr/bin, /sbin/ binaries and /dev entries <br />that are needed for the filesystem here */ <br /><br /> /* Type the following command under jffsfile directory to create the JFFS2 Image */ <br /><br /> ./mkfs.jffs2 -e 0x40000 -p -o ../jffs.image <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面显示了 mkfs.jffs2 的典型用法。 
        <code>-e</code> 选项确定闪存的擦除扇区大小（通常是 64 千字节）。 
        <code>-p</code> 选项用来在映像的剩余空间用零填充。 
        <code>-o</code> 选项用于输出文件，通常是 JFFS2 文件系统映像 ― 在本例中是 jffs.image。一旦创建了 JFFS2 文件系统，它就被装入闪存中适当的位置（引导装载程序告知内核查找文件系统的地址）以便内核能挂装它。
      </p>
		<p>
				<b>tmpfs</b>
				<br />
当 Linux 运行于嵌入式设备上时，该设备就成为功能齐全的单元，许多守护进程会在后台运行并生成许多日志消息。另外，所有内核日志记录机制，象
syslogd、dmesg 和 klogd，会在 /var 和 /tmp
目录下生成许多消息。由于这些进程产生了大量数据，所以允许将所有这些写操作都发生在闪存是不可取的。由于在重新引导时这些消息不需要持久存储，所以这个
问题的解决方案是使用 tmpfs。 </p>
		<p>tmpfs 是基于内存的文件系统，它主要用于减少对系统的不必要的闪存写操作这一唯一目的。因为
tmpfs 驻留在 RAM 中，所以写／读／擦除的操作发生在 RAM 中而不是在闪存中。因此，日志消息写入 RAM
而不是闪存中，在重新引导时不会保留它们。tmpfs 还使用磁盘交换空间来存储，并且当为存储文件而请求页面时，使用虚拟内存（VM）子系统。</p>
		<p>tmpfs 的
        <b>优点</b>包括：
      </p>
		<ul>
				<li>动态文件系统大小 ― 文件系统大小可以根据被复制、创建或删除的文件或目录的数量来缩放。使得能够最理想地使用内存。</li>
				<li>速度 ― 因为 tmpfs 驻留在 RAM，所以读和写几乎都是瞬时的。即使以交换的形式存储文件，I/O 操作的速度仍非常快。</li>
		</ul>
		<p>tmpfs 的一个
        <b>缺点</b>是当系统重新引导时会丢失所有数据。因此，重要的数据不能存储在 tmpfs 上。
      </p>
		<p>
				<b>挂装 tmpfs</b>
				<br />
诸如 Ext2fs 和 JFFS2 等大多数其它文件系统都驻留在底层块设备之上，而 tmpfs 与它们不同，它直接位于 VM 上。因而，挂装 tmpfs 文件系统是很简单的事：
      </p>
		<br />
		<a name="code8">
				<b>清单 8. 挂装 tmpfs</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">/* Entries in /etc/rc.d/rc.sysinit for creating/using tmpfs */ <br /><br /> # mount -t tmpfs tmpfs /var -o size=512k <br /> # mkdir -p /var/tmp <br /> # mkdir -p /var/log <br /> # ln -s /var/tmp /tmp <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面的命令将在 /var 上创建 tmpfs 并将 tmpfs 的最大大小限制为 512 K。同时，tmp/ 和 log/ 目录成为 tmpfs 的一部分以便在 RAM 中存储日志消息。</p>
		<p>如果您想将 tmpfs 的一个项添加到 /etc/fstab，那么它可能看起来象这样： 
        </p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">tmpfs /var tmpfs size=32m 0 0</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这将在 /var 上挂装一个新的 tmpfs 文件系统。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="5">
						<span class="atitle">图形用户界面（GUI）选项</span>
				</a>
		</p>
		<p>从
用户的观点来看，图形用户界面（GUI）是系统的一个最至关重要的方面：用户通过 GUI 与系统进行交互。所以 GUI
应该易于使用并且非常可靠。但它还需要是有内存意识的，以便在内存受限的、微型嵌入式设备上可以无缝执行。所以，它应该是轻量级的，并且能够快速装入。</p>
		<p>另一个要考虑的重要方面涉及许可证问题。一些 GUI 分发版具有允许免费使用的许可证，甚至在一些商业产品中也是如此。另一些许可证要求如果想将 GUI 合并入项目中则要支付版税。</p>
		<p>最
后，大多数开发人员可能会选择 XFree86，因为 XFree86 为他们提供了一个能使用他们喜欢的工具的熟悉环境。但是市场上较新的
GUI，象 Century Software 的 Microwindows（Nano-X）和 Trolltech 的
QT/Embedded，与 X 在嵌入式 Linux
的竞技舞台中展开了激烈竞争，这主要是因为它们占用很少的资源、执行的速度很快并且具有定制窗口构件的支持。</p>
		<p>让我们看一看这些选项中的每一个。</p>
		<p>
				<a name="N10393">
						<span class="smalltitle">Xfree86 4.X（带帧缓冲区支持的 X11R6.4）</span>
				</a>
		</p>
		<p>XFree86
Project, Inc. 是一家生产 XFree86 的公司，该产品是一个可以免费重复分发、开放源码的 X Window 系统。X
Window 系统（X11）为应用程序以图形方式进行显示提供了资源，并且它是 UNIX 和类 UNIX
的机器上最常用的窗口系统。它很小但很有效，它运行在为数众多的硬件上，它对网络透明并且有良好的文档说明。X11
为窗口管理、事件处理、同步和客户机间通信提供强大的功能 ― 并且大多数开发人员已经熟悉了它的
API。它具有对内核帧缓冲区的内置支持，并占用非常少的资源 ― 这非常有助于内存相对较少的设备。X 服务器支持 VGA 和非 VGA
图形卡，它对颜色深度 1、2、4、8、16 和 32 提供支持，并对渲染提供内置支持。最新的发行版是 XFree86 4.1.0。</p>
		<p>它的
        <b>优点</b>包括：
      </p>
		<ul>
				<li>帧缓冲区体系结构的使用提高了性能。</li>
				<li>占用的资源相对很小 ― 大小在 600 K 到 700 K 字节的范围内，这使它很容易在小型设备上运行。</li>
				<li>非常好的支持：在线有许多文档可用，还有许多专用于 XFree86 开发的邮递列表。</li>
				<li>X API 非常适合扩展。</li>
		</ul>
		<p>它的
        <b>缺点</b>包括：
      </p>
		<ul>
				<li>比最近出现的嵌入式 GUI 工具性能差。</li>
				<li>此外，当与 GUI 中最新的开发 ― 象专门为嵌入式环境设计的 Nano-X 或 QT/Embedded ― 相比时，XFree86 似乎需要更多的内存。</li>
		</ul>
		<p>
				<a name="N103C0">
						<span class="smalltitle">Microwindows</span>
				</a>
		</p>
		<p>Microwindows 是 Century Software 的开放源代码项目，设计用于带小型显示单元的微型设备。它有许多针对现代图形视窗环境的功能部件。象 X 一样，有多种平台支持 Microwindows。</p>
		<p>Microwindows 体系结构是基于客户机／服务器的并且具有分层设计。最底层是屏幕和输入设备驱动程序（关于键盘或鼠标）来与实际硬件交互。在中间层，可移植的图形引擎提供对线的绘制、区域的填充、多边形、裁剪以及颜色模型的支持。</p>
		<p>在
最上层，Microwindows 支持两种 API：Win32/WinCE API 实现，称为 Microwindows；另一种 API 与
GDK 非常相似，它称为 Nano-X。Nano-X 用在 Linux 上。它是象 X 的 API，用于占用资源少的应用程序。</p>
		<p>Microwindows
支持 1、2、4 和 8 bpp（每像素的位数）的 palletized 显示，以及 8、16、24 和 32 bpp
的真彩色显示。Microwindows 还支持使它速度更快的帧缓冲区。Nano-X 服务器占用的资源大约在 100 K 到 150 K 字节。</p>
		<p>原始 Nano-X 应用程序的平均大小在 30 K 到 60 K。由于 Nano-X 是为有内存限制的低端设备设计的，所以它不象 X 那样支持很多函数，因此它实际上不能作为微型 X（Xfree86 4.1）的替代品。</p>
		<p>可以在 Microwindows 上运行 FLNX，它是针对 Nano-X 而不是 X 进行修改的 FLTK（快速轻巧工具箱(Fast Light Toolkit)）应用程序开发环境的一个版本。本文中描述 FLTK。</p>
		<p>Nano-X 的
        <b>优点</b>包括：
      </p>
		<ul>
				<li>与 Xlib 实现不同，Nano-X 仍在每个客户机上同步运行，这意味着一旦发送了客户机请求包，服务器在为另一个客户机提供服务之前一直等待，直到整个包都到达为止。这使服务器代码非常简单，而运行的速度仍非常快。</li>
				<li>占用很小的资源</li>
		</ul>
		<p>Nano-X 的
        <b>缺点</b>包括：
      </p>
		<ul>
				<li>联网功能部件至今没有经过适当地调整（特别是网络透明性）。</li>
				<li>还没有太多现成的应用程序可用。</li>
				<li>与 X 相比，Nano-X 虽然近来正在加速开发，但仍没有那么多文档说明而且没有很好的支持，但这种情形会有所改变。</li>
		</ul>
		<p>
				<a name="N103F9">
						<span class="smalltitle">Microwindows 上的 FLTK API</span>
				</a>
		</p>
		<p>FLTK
是一个简单但灵活的 GUI 工具箱，它在 Linux 世界中赢得越来越多的关注，它特别适用于占用资源很少的环境。它提供了您期望从 GUI
工具箱中获得的大多数窗口构件，如按钮、对话框、文本框以及出色的“赋值器”选择（用于输入数值的窗口构件）。还包括滑动器、滚动条、刻度盘和其它一些构
件。</p>
		<p>针对 Microwindows GUI 引擎的 FLTK 的 Linux 版本被称为 FLNX。FLNX
由两个组件构成：Fl_Widget 和 FLUID。Fl_Widget 由所有基本窗口构件 API
组成。FLUID（快速轻巧的用户界面设计器(Fast Light User Interface Designer, FLUID)）是用来产生
FLTK 源代码的图形编辑器。总的来说，FLNX 是能用来为嵌入式环境创建应用程序的一个出色的 UI 构建器。</p>
		<p>Fl_Widget 占用的资源大约是 40 K 到 48 K，而 FLUID（包括了每个窗口构件）大约占用 380 K。这些非常小的资源占用率使 Fl_Widget 和 FLUID 在嵌入式开发世界中非常受欢迎。</p>
		<p>
				<b>优点</b>包括：
      </p>
		<ul>
				<li>习惯于在象 Windows 这样已建立得较好的环境中开发基于 GUI 的应用程序的任何人都会非常容易地适应 FLTK 环境。</li>
				<li>它的文档包括一本十分完整且编写良好的手册。</li>
				<li>它使用 LGPL 进行分发，所以开发人员可以灵活地发放他们应用程序的许可证。</li>
				<li>FLTK 是一个 C++ 库（Perl 和 Python 绑定也可用）。面向对象模型的选择是一个好的选择，因为大多数现代 GUI 环境都是面向对象的；这也使将编写的应用程序移植到类似的 API 中变得更容易。</li>
				<li>Century Software 的环境提供了几个有用的工具，诸如 ScreenToP 和 ViewML 浏览器。</li>
		</ul>
		<p>它的
        <b>缺点</b>是：
      </p>
		<ul>
				<li>普通的 FLTK 可以与 X 和 Windows API 一同工作，而 FLNX 不能。它与 X 的不兼容性阻碍了它在许多项目中的使用。</li>
		</ul>
		<p>
				<a name="N1042C">
						<span class="smalltitle">Qt/Embedded</span>
				</a>
		</p>
		<p>Qt/Embedded
是 Trolltech 新开发的用于嵌入式 Linux 的图形用户界面系统。Trolltech 最初创建 Qt 作为跨平台的开发工具用于
Linux 台式机。它支持各种有 UNIX 特点的系统以及 Microsoft Windows。KDE ― 最流行的 Linux
桌面环境之一，就是用 Qt 编写的。</p>
		<p>Qt/Embedded 以原始 Qt
为基础，并做了许多出色的调整以适用于嵌入式环境。Qt Embedded 通过 Qt API 与 Linux I/O
设施直接交互。那些熟悉并已适应了面向对象编程的人员将发现它是一个理想环境。而且，面向对象的体系结构使代码结构化、可重用并且运行快速。与其它
GUI 相比，Qt GUI 非常快，并且它没有分层，这使得 Qt/Embedded 成为用于运行基于 Qt 的程序的最紧凑环境。</p>
		<p>Trolltech
还推出了 Qt 掌上机环境（Qt Palmtop Environment，俗称 Qpe）。Qpe
提供了一个基本桌面窗口，并且该环境为开发提供了一个易于使用的界面。Qpe 包含全套的个人信息管理（Personal Information
Management (PIM)）应用程序、因特网客户机、实用程序等等。然而，为了将 Qt/Embedded 或 Qpe
集成到一个产品中，需要从 Trolltech 获得商业许可证。（原始 Qt 自版本 2.2 以后就可以根据 GPL 获得 。）</p>
		<p>它的
        <b>优点</b>包括：
      </p>
		<ul>
				<li>面向对象的体系结构有助于更快地执行</li>
				<li>占用很少的资源，大约 800 K</li>
				<li>抗锯齿文本和混合视频的象素映射</li>
		</ul>
		<p>它的
        <b>缺点</b>是：
      </p>
		<ul>
				<li>Qt/Embedded 和 Qpe 只能在获得商业许可证的情况下才能使用。</li>
		</ul>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="6">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>嵌
入式 Linux 开发正迅速地发展着。您必须学习并从引导装载程序和分发版到文件系统和 GUI
中的每一个事物的各种选项中作出选择。但是要感谢有这种选择自由度以及非常活跃的 Linux 社区，Linux
上的嵌入式开发已经达到了新的境界，并且调整模块以适合您的规范从未比现在更简单。这已经导致出现了许多时新的手持和微型设备作为开放盒，这是件好事
― 因为事实是您不必成为一个专家从这些模块中进行选择来调整您的设备以满足您自己的要求和需要。</p>
		<p>我们希望这篇对嵌入式 Linux 领域的介绍性概述能激起您进行试验的欲望，并且希望您将体会摆弄微型设备的乐趣以满足您的爱好。为进一步有助于您的项目，请参阅下面的“参考资料”，链接到有关我们这里已经概述的技术的更深入的信息。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">参考资料 </span>
				</a>
		</p>
		<p>
				<b>引导</b>：
      </p>
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的
          <a href="http://www.ibm.com/developerworks/library/l-embdev.html">英文原文</a>.
        <br /><br /></li>
				<li>如需获得对 vmlinux 和 zimage 之间区别的极好解释，请在 Alessandro Rubini 编写的“
          <a href="http://www.linux.it/kerneldocs/kconf/">Kernel Configuration: dealing with the unexpected</a>（
          <i>Linux Magazine</i>）的一文中找到“Booting your kernel”一节。
          <br /><br /><br /></li>
				<li>有关内核、映像和引导过程的更多信息，请阅读
          <a href="http://www.infocom.cqu.edu.au/Units/aut2000/85321/Resources/Study_Guide/Chapter_13/">中央昆士兰大学（Central Queensland University）的系统管理文本的第 13 章</a>。
          <br /><br /></li>
		</ul>
		<p>
				<b>小型分发版</b>：
      </p>
		<ul>
				<li>
						<a href="http://www.linuxdevices.com/articles/AT2760742655.html">The Embedded Linux Distributions Quick Reference Guide</a>涵盖了许多商业的和开放源码的分发版（
          <i>Linux Devices</i>，2001 年 8 月）。
          <br /><br /><br /></li>
				<li>请查看另一个
          <a href="http://linux-embedded.com/software.php3">详尽的分发版</a>和有用的工具的清单（
          <i>Linux-embedded.com</i>）。

        <br /></li>
		</ul>
		<p>
				<b>工具链</b>：
      </p>
		<ul>
				<li>
						<a href="http://tuxscreen.net/wiki/view/Main/ToolChain">Wiki 工具链页面</a>包含到本文提到的所有三个工具链的链接，还有对它们的评论。

        <br /></li>
		</ul>
		<p>
				<b>设备驱动程序</b>：
      </p>
		<ul>
				<li>
						<a href="http://linux-mtd.infradead.org/">Memory Technology Device (MTD) Subsystem for Linux</a>的目的是简化内存设备（特别是闪存设备）的驱动程序的创建。
          <br /><br /><br /></li>
				<li>Vipin Malik 编写的
          <a href="http://ftp.linux.org.uk/pub/people/dwmw2/mtd/cvs/mtd/mtd-jffs-HOWTO.txt">The Linux MTD, JFFS HOWTO</a>将帮助您使 MTD 和 JFFS2 一起工作。
          <br /><br /><br /></li>
				<li>
						<a href="http://penguinppc.org/embedded/howto/device-drivers.html">Linux for PowerPC Embedded Systems HOWTO</a>有一个很好的设备驱动程序清单。
          <br /><br /><br /></li>
				<li>理解
          <a href="http://www.penguinmagazine.com/Magazine/This_Issue/0015">Linux device drivers</a>有助于理解本篇介绍性文章（
          <i>Penguin Magazine</i>）。
          <br /><br /><br /></li>
				<li>要精通 Linux 设备驱动程序，请阅读 O'Reilly 的
          <a href="http://www.xml.com/ldd/chapter/book/">Linux Device Drivers，第 2 版</a>一书。

        <br /></li>
		</ul>
		<p>
				<b>有用的工具</b>：
      </p>
		<ul>
				<li>请查看 LART 上的
          <a href="http://www.lart.tudelft.nl/projects/jtag/">Jflash-linux</a>。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.gnu.org/directory/binutils.html">Binutils</a>、
          <a href="http://gcc.gnu.org/gcc-3.0/">GCC</a>和
          <a href="http://www.gnu.org/software/libc/libc.html">Glibc</a>都可从 Free Software Foundation 下载获得。
          <br /><br /><br /></li>
				<li>许多有用的下载都可从
          <a href="http://www.netwinder.org/services.html">Netwinder.org</a>获得，这是一个致力于 NetWinder 平台上开发工作的志愿者站点。
          <br /><br /><br /></li>
				<li>请在 Mark Nielsen 写得非常棒的
          <a href="http://www.gnujobs.com/mark/articles/Ramdisk.html">How to use a Ramdisk for Linux</a>一文中阅读有关 Ramdisk 的所有信息。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.viewml.com/download/">FLNX</a> 是以 FLTK（快速轻巧的工具箱）为基础的。

        <br /></li>
		</ul>
		<p>
				<b>文件系统</b>：
      </p>
		<ul>
				<li>第二版扩展文件系统
          <a href="http://e2fsprogs.sourceforge.net/ext2.html">Ext2fs</a>的主页在 SourceForge。
          <br /><br /><br /></li>
				<li>Red Hat 英国公司的 David Woodhouse 概述了大量有关
          <a href="http://sources.redhat.com/jffs2/jffs2-html/jffs2-html.html">JFFS2：日志闪存文件系统，第 2 版</a>的背景知识。
          <br /><br /><br /></li>
				<li>您可以在 Linux HeadQuarters 阅读更多有关
          <a href="http://www.linuxhq.com/kernel/v2.4/patch/patch-2.4.17-pre5/linux/Documentation/filesystems/tmpfs.txt.html">tmpfs</a>的信息。
          <br /><br /><br /></li>
				<li>Cliff Brake 和 Jeff Sutherland 编写的
          <a href="http://embedded.linuxjournal.com/magazine/issue04/4678/?sid=449c51a20d1809f80435d77163f511ee">Flash Filesystems for Embedded Linux Systems</a>一文论述了用于闪存设备的更多文件系统（
          <i>Embedded Linux Journal</i>）。

        <br /></li>
		</ul>
		<p>
				<b>GUI</b>：
      </p>
		<ul>
				<li>Xfree86 是
          <a href="http://www.xfree86.org/">X 开发</a>的主页。
          <br /><br /><br /></li>
				<li>请查看一篇对
          <a href="http://mail.gnome.org/archives/gtk-devel-list/2000-March/msg00157.html">Microwindows 的一些缺点</a>（GNOME gtk 开发人员的邮递列表）的讨论（时间比较长了）。
          <br /><br /><br /></li>
				<li>您将在
          <a href="http://home.twcny.rr.com/embedded/microwin/links.html">Microwindows Project Links</a>上找到丰富的 Microwindows/Nano-X 链接。
          <br /><br /><br /></li>
				<li>在 Trolltech 上查找有关
          <a href="http://www.trolltech.com/products/embedded/index.html">Qt/Embedded</a>的更多信息。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.linuxdevices.com/articles/AT9202043619.html">The Embedded Linux GUI/Windowing Quick Reference Guide</a>中有丰富的链接（
          <i>Linux Devices</i>，2002 年 2 月）。

        <br /></li>
		</ul>
		<p>
				<b>一般参考资料</b>：
      </p>
		<ul>
				<li>
						<a href="http://www.gnu.org/copyleft/gpl.html">General Public License 或 GPL</a>确保用户复制、分发和修改软件的权利。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.arm.linux.org.uk/docs/whatis.shtml">ARM Linux</a>是您了解有关 Linux 用于 ARM 处理器的信息的一个非常好的站点。它由 ARM 的创建者 Russell King 来维护。
          <br /><br /><br /></li>
				<li>
						<a href="http://penguinppc.org/about/">Penguinppc.org</a>是关于 Linux 用于 PowerPC 系列处理器的的主页。该站点上有一个关于为基于 PPC 的体系结构建立工具链的资料丰富的教程。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.linuxdevices.com/">Linux Devices</a>是一个非常全面的站点，它包含有关 Linux 和嵌入式开发的出版发行、快速参考、新闻和特色报告等各种信息。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.siliconpenguin.com/">Silicon Penguin</a>列表站点上拥有嵌入式 Linux 参考资料的详尽集合。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.aleph1.co.uk/armlinux/thebook.html">ARMLinux - the book</a>可从 Aleph One 上获得。您可以定购一本，也可以
          <a href="http://www.aleph1.co.uk/armlinux/book/book1.html">在线阅读</a>。
          <br /><br /><br /></li>
				<li>
						<a href="http://www.embedded-linux.org/vision.php3">嵌入式 Linux 协会（Embedded Linux Consortium）</a>是一个非赢利的互助协会，它欢迎致力于嵌入式 Linux 领域的开发人员成为会员。
          <br /><br /><br /></li>
				<li>IBM 的
          <a href="http://www.ibm.com/products/gallery/linuxwatch.shtml">Linux wristwatch</a>是运行 Linux 的微型嵌入式设备的示例；本文的作者之一，Vishal Kulkarni 也参与了它的研发。请在
                    <a href="http://www.freeos.com/articles/3800">本文</a>（
          <i>FreeOS.com</i>，2001 年 3 月）中阅读有关它的信息。
          <br /><br /><br /></li>
				<li>在
          <i>developerWorks</i>上浏览
          <a href="http://www.ibm.com/developerworks/linux/?article=lr">更多 Linux 参考资料</a>。
          <br /><br /><br /></li>
				<li>在
          <i>developerWorks</i>上浏览
          <a href="http://www.ibm.com/developerworks/wireless/">更多无线领域的参考资料</a>。
        <br /></li>
		</ul>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/linux/embed/embdev/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span class="atitle">作者简介</span>
				</a>
		</p>
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td colspan="3">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" />
								</td>
						</tr>
						<tr align="left" valign="top">
								<td>
										<br />
								</td>
								<td>
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" />
								</td>
								<td width="100%">
										<p>Anand
K Santhanam 在印度 Madras 大学获得计算机科学工学学士学位。自 1999 年 7 月以来他一直在印度为 IBM Global
Services（软件实验室）工作。他是 IBM Linux 小组的成员，这个小组主要致力于嵌入式系统中的
ARM-Linux、设备驱动程序和电源管理的研究和开发。他感兴趣的其它领域是 O/S 本质和联网。可以通过 <a href="mailto:asanthan@in.ibm.com">asanthan@in.ibm.com</a> 与他联系。

      </p>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td colspan="3">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" />
								</td>
						</tr>
						<tr align="left" valign="top">
								<td>
										<br />
								</td>
								<td>
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" />
								</td>
								<td width="100%">
										<p>Vishal
Kulkarni 从印度 Maharashtra 的 Shivaji 大学获得电子工程的学士学位。自 1999 年 3 月以来他一直在印度为
IBM Global Services（软件实验室）工作。在此之前，他曾在美国 IBM Austin 工作了一年半多。他是 IBM Linux
小组的成员，这个小组主要致力于嵌入式设备上的 ARM-Linux、设备驱动程序和 GUI。他感兴趣的其它领域是 O/S 本质和联网。可以通过 <a href="mailto:kvishal@in.ibm.com">kvishal@in.ibm.com</a>与他联系。
      </p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/schkui/aggbug/11251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">爱易</a> 2006-05-30 18:41 <a href="http://www.cnitblog.com/schkui/archive/2006/05/30/11251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>