嵌入式Linux-ARM9代码移植实现方法的研究

本文作者:admin       点击: 2007-09-11 00:00
前言:
一.综述

ARM公司在32位RISC (Reduced Instruction Set Computer) CPU开发领域不断取得突破,其结构已经从V3发展到V6。ARM公司一直以IP 核(Intelligence Property)提供者的身份,其设计的芯核具有功耗低、成本低等显著优点,获得众多的半导体厂家的大力支持,在32位嵌入式应用领域获得了巨大的成功,目前已经占有75%以上的32位RISC嵌入式产品市场。在嵌入式应用领域确立了市场领导地位。

Linux在短短的十几年时间已经发展成为功能强大、设计完善的操作系统之一;可运行在X86、 Alpha、MIPS、Motorola、ARM等多种硬件平台,而且开放源代码,可与商业操作系统分庭抗争。越来越多的企业和研发机构都转向嵌入式Linux的开发和研究上,在新兴的嵌入式操作系统领域内也获得了飞速发展。其中,由于Linux操作系统设计本身具有的不同平台之间的可移植性,充分利用Arm芯片的特点,将PC机上的Linux应用程序丰富的代码资源,强大的功能,向ARM下嵌入式Linux平台的移植有着相当关键的作用。本文就从代码移植的实现方法进行具体的研究。

嵌入式系统是以应用为中心,以计算机为基础,软硬件可裁剪,适用于系统对功能、可靠性、成本、功耗严格要求的专用计算机系统,系统结构见图1。
实时性是嵌入式系统的基本要求,其次,还要求代码小,速度快,可靠性高。嵌入式Linux(Embedded Linux)是指对Linux经过裁剪小型化后,可固化在存储器或单片机中,应用于特定嵌入式场合的专用Linux操作系统。嵌入式Linux的开发和研究已经成为目前操作系统领域的一个热点。与其它嵌入式操作系统相比(详见表1)

Linux操作系统是层次结构,由很多体积小且性能高的微内核系统组成,且内核完全开放。在内核代码完全开放的前提下,不同领域和不同层次的用户可以根据自己的应用需要方便地对内核进行改造,低成本地设计和开发出满足自己需要的嵌入式系统。Linux诞生于因特网时代并具有Unix的特性,保证了它支持所有标准因特网协议,并且可以利用Linux的网络协议栈将其开发成为嵌入式的TCP/IP网络协议栈。此外,Linux还支持ext2、fat16、fat32、romfs等文件系统,为开发嵌入式系统应用打下了很好的基础。Linux具备一整套工具链,容易自行建立嵌入式系统的开发环境和交叉运行环境,可以跨越嵌入式系统开发中仿真工具的障碍。Linux也符合IEEE POSIX.1标准,使应用程序具有较好的可移植性。传统的嵌入式开发的程序调试和调试工具是用在线仿真器(ICE)实现的。它通过取代目标板的微处理器,给目标程序提供一个完整的仿真环境,完成 监视和调试程序;但一般价格比较昂贵,只适合做非常底层的调试。使用嵌入式Linux,一旦软硬件能够支持正常的串口功能,即使不用仿真器,也可以很好地进行开发和调试工作,从而节省一笔不小的开发费用。嵌入式Linux为开发者提供了一套完整的工具链(tool chain)。它利用GNU的gcc做编译器,用gdb、kgdb、xgdb做调试工具,能够很方便地实现从操作系统到应用软件各个级别的调试。Linux具有广泛的硬件支持特性,无论是RISC还是CISC、32位还是64位等各种处理器,Linux都能运行。Linux支持各种主流硬件设备和最新硬件技术,甚至可以在没有存储管理单元(MMU)的处理器上运行。

一个小型的嵌入式Linux系统只需要下面三个基本元素:引导工具(Linux微内核,由内存管理、进程管理和事务处理构成),初始化进程,硬件驱动程序(提供所需功能的一个或更多应用程序)另外需要一个文件系统(也许在ROM或RAM中)TCP/IP网络堆栈,存储半过渡数据和交换用的磁盘。
  
二.嵌入式系统的开发

1 一般开发过程
嵌入式ARM-Linux融合了ARM嵌入式系统和Linux的特点,其开发与一般的应用程序开发相比有着自己的特点,下面简要的介绍一下嵌入式Linux开发的一般过程。
(1)了解硬件
了解硬件指的是了解整个硬件,判断硬件对于当前的应用来说是否合适。嵌入式系统中需要使用到CPU (arm核)和各种外围设备,由此掌握相关硬件的资料,包括CPU,芯片手册和各种外围设备的手册以及相关的各种电路图等,并对整体系统有较深入的了解。
(2)工具准备
这些工具包括:针对所用CPU的编译器/汇编器/连接器,相应的库工具,目标文件分析/管理工具,符号查看器等等。由于Linux的开放性,针对不同目标平台的Linux工具都可在网上免费得到,绝大部分的这些工具都由GNU 提供。所需要的其他工具还包括硬件厂商提供给公司的工具,如编程器,下载工具和查错器等等。所有这些工具对以后的开发、调试等都可说是必不可少的。
(3)安排内存地址
如SDRAM的内存地址,Flash的内存地址等,这需要与实际应用和硬件状况相结合来考虑,要根据硬件的限制以及实际应用的需要对内存地址进行合理的安排,同时要注意内存地址的安排要具有一定的伸缩性,以便于将来需要改动时所做的变动达到最小。一般来说,嵌入式Linux的内存地址安排体现在连接脚本当中。
(4)编写启动代码和机器相关代码
各种不同目标系统,甚至相同目标系统的启动代码和机器相关代码也是不相同的。启动代码一般需要完成硬件初始化,装载内核及安装根文件系统以及开始内核执行的工作,不同目标平台的启动代码一般可通过参考Linux下已有的启动代码和相关CPU的手册进行编写。
(5)编写驱动程序
Linux编写驱动程序与一般情况下编写驱动程序并没有太大的区别,都需要对相关的硬件做出了解,同时需要遵循Linux编写驱动程序的一些规则进行,编写完一个驱动程序后,一般就写一个相应的测试程序,已便随时进行测试。Linux下各种不同类型的设备都有相当多的驱动程序源码可以参考,因此实际编写时更多的时间是花在对特定硬件特性的熟悉上。
除了以上提到的这些步骤外,进行实际开发时,很多时候还要进行库(这里所提到的库均指C库),GUI和系统程序的移植。这是因为嵌入式Linux中所用的库一般不能直接使用标准库,而需要进行精简,虽然已有些精简的C库如uClibc等可供使用,但还是需要经常对其进行修改。嵌入式Linux常用的GUI有Microwindows, MiniGUI,QT/Embedded,TinyX等等,各自均有其使用的场合,所针对的目标平台和应用层次也不一样,必须根据实际需要进行选择。系统程序如mount,ls等等有些是应用时所必须的,有些则是进行调试时所需要的,初始时则需要一些通用的系统程序即可。
2 Linux操作系统及程序的移植
(1)操作系统的移植
嵌入式系统由于硬件的限制,通常只具有极稀少的硬件资源,如主频较低的CPU、较小的内存、小容量的固态电子盘芯片DoC(Disk on Chip)或DoM(Disk on Module)替代磁盘等。在使用电池的系统中,它还要实现低功耗,延长电池使用时间的功能。
嵌入式Linux系统需要下面三个基本元素:系统引导工具(用于机器加电后的系统定位引导)、Linux微内核(内存管理、 程序管理)、初始化进程。但如果要它成为完整的操作系统并且继续保持小型化,还必须加上硬件驱动程序、硬件接口程序和应用程序组。
Linux是基于GNU的C编译器,作为GNU工具链的一部分,与gdb源调试器一起工作的。它提供了开发嵌入式Linux系统的所有软件工具。
Linux的移植是把操作系统针对具体的目标平台做必要改写之后,安装到目标平台上并运行起来。具体的改写工作需要对目标平台非常熟悉并且精通汇编语言,这部分工作通常由平台开发商提供。具体步骤如下:
① 到ARM公司网站ftp://ftp.arm.linux.org.uk上下载Linux内核和关于ARM平台的补丁。下载到Linux的usr/src目录下,一般文件名称为Patch-x.x.x-rmkx.gz
② 给Linux源代码打补丁。在同内核相同的目录运行:
   zcat  /patch.x.x.x-rmkx.gz | patch -pl
③ 建立嵌入式Linux交叉开发环境。
目前,常用的交叉开发环境主要有开放和商业两种类型。开放的交叉开发环境的典型代表是GNU工具链(Tools chain),目前已经能够支持x86、ARM、MIPS、PowerPC等多种处理器。商业的交叉开发环境主要有Metrowerks CodeWarrior、ARM Software Development Toolkit、SDS Cross compiler、WindRiver Tornado、Microsoft Embedded Visual C++等。交叉开发环境是指编译、链接和调试嵌入式应用软件的环境。它与运行嵌入式应用软件的环境有所不同,通常采用宿主机/目标机模式。在基于ARM体系结构的gcc交叉开发环境中,arm-linux-gcc是交叉编译器,arm-linux-ld是交叉链接器。编写好的嵌入式软件经过交叉编译和交叉链接后,通常会生成两种类型的可执行文件:用于调试的可执行文件和用于固化的可执行文件。
④ 修改内核目录的Makefile文件, 参看《GNU Make manual》
⑤ 修改剪裁内核,编译。
(2)程序的移植
实现程序从PC上的Linux到ARM Linux上的移植建立在Linux操作系统移植的基础上。一般说来还需要以下几个方面的工作(见应用开发流程图)。   
① 建立交叉编译环境,与Linux操作系统的交叉编译环境类似。
② 在宿主机上编写程序。如helloworld.c 
#include 
main()
{
Printf(“hello world\n”);
}
③ 交叉编译和链接。
在完成嵌入式软件的编码之后,就是进行编译和链接,以生成可执行代码。由于开发过程大多(包括AMD)是在Intel公司x86系列CPU的通用计算机上进行的,而目标环境的处理器芯片却大多为ARM、MIPS、PowerPC、DragonBall等系列的微处理器,这就要求在建立好的交叉开发环境中进行交叉编译和链接。
使用GNU编译程序,需要有Makefile文件。对于上述的程序,Makefile 的形式如下:
〔Tab〕CC=armv4l-unknown-linux-gcc
〔Tab〕EXEC=helloworld
〔Tab〕OBJS=helloworld.o
...参见《Gnu make manual》
这是一个很简单的程序,不需要使用更多的设备如:LCD,声卡,网卡通信等,所以不需要编写特别的驱动,而对于大多数的应用来说,编写驱动的工作量是很大的。驱动的编写详见具体的产品开发说明书。
④ 交叉调试

可以分为软件调试和硬件调试两方面,但是很多时候是需要同时进行的。
a)硬件调试。如果不采用在线仿真器,可以让CPU直接在其内部实现调试功能,并通过在开发板上引出的调试端口,发送调试命令和接收调试信息,完成调试过程。目前,Motorola公司提供的开发板上使用的是DBM调试端口,而ARM公司提供的开发板上使用的则是JTAG调试端口。使用合适的软件工具与这些调试端口进行连接,可以获得与ICE类似的调试效果。

b)软件调试。在嵌入式Linux系统中,Linux系统内核调试,可以先在Linux内核中设置一个调试桩(debug stub),用作调试过程中和宿主机之间的通信服务器。然后,可以在宿主机中通过调试器的串口与调试桩进行通信,并通过调试器控制目标机上Linux内核的运行。

嵌入式上层应用软件的调试可以使用本地调试和远程调试两种方法。如果采用的是本地调试,首先要将所需的调试器移植到目标系统中,然后就可以直接在目标机上运行调试器来调试应用程序了;如果采用的是远程调试,则需要移植一个调试服务器到目标系统中,并通过它与宿主机上的调试器共同完成应用程序的调试。在嵌入式Linux系统的开发中,远程调试时目标机上使用的调试服务器通常是gdbserver,而宿主机上使用的调试器则是gdb。两者相互配合共同完成调试过程。

⑤ 系统测试。整个软件系统编译过程,嵌入式系统的硬件一般采用专门的测试仪器进行测试,而软件则需要有相关的测试技术和测试工具的支持,并要采用特定的测试策略。测试技术指的是软件测试的专门途径,以及能够更加有效地运用这些途径的特定方法。在嵌入式软件测试中,常常要在基于目标机的测试和基于宿主机的测试之间做出折衷。基于目标机的测试需要消耗较多的时间和经费,而基于宿主机的测试虽然代价较小,但毕竟是在仿真环境中进行的,因此难以完全反映软件运行时的实际情况。这两种环境下的测试可以发现不同的软件缺陷,关键是要对目标机环境和宿主机环境下的测试内容进行合理取舍。嵌入式软件测试中经常用到的测试工具主要有:内存分析工具、性能分析工具、覆盖分析工具、缺陷跟踪工具等。

嵌入式Linux的开发涉及到很多的问题,需要对Linux内核和编程有深层的理解,还需要有较强的硬件基础,具体细节参考相应平台的技术资料。
  
三.结束语

随着电子信息产业的迅速发展,目前以嵌入式设备为中心的智能产品的应用愈加广泛,深入到了社会生活的方方面面,而Arm-Linux以其卓越的性能价格比,超前的发展趋势,可以预见到这种组合应用的光明前景。