基于MPC850上的嵌入式Linux实现
These papers introduce the implement and key techniques for transplanting Linux-2.4.4 kernel to MPC850 development board.
MPC850是一种多用途的通信微处理器,其内部集成了一个PowerPCRISC内核和CPM通信处理模块,具有较高的性价比和通信及网络处理能力,可用于各种通信及控制系统中。Linux作为一种强大的开放式操作系统,凭借其开放的源代码,高效、稳定、可裁剪的内核等诸多优点,被越来越多地应用于嵌入式系统当中。本文详细介绍了将Linux-2.4.4版内核移植到MPC850 Rpxlite board上的具体实现。
1 建立交叉编译器
在对内核进行移植之前,需要交叉编译器来编译内核和应用程序。这里交叉编译是指在主机平台上生成目标机平台上可执行的代码。由于目标机上的硬件资源的限制,不可能在目标机上编译大型程序,所以必须在主机平台上构造一个交叉编译器来编译Linux内核。图1描述了在主机平台上交叉编译应用程序到目标机上执行的全过程:用户在主机上编写完成应用程序后,通过安装在主机上的交叉编译器进行编译、连接形成在目标机上可以执行的二进制目标文件,然后通过以太网口、串口将目标文件下载到目标机的内存中执行,最后目标机把程序执行的结果返回到主机的控制台上。
交叉编译器由一套用于编译、汇编和链接内核及应用程序的组件组成。这些组件包括:
(1)Binutils:用于操作二进制文件的实用工具集。他包括ar,as,objcopy,objdump等。
(2)Gcc:C编译器,可以编译C,C++等程序。
(3)Glibc:Glibc是所有用户应用程序都连接到的C库。

①host主机平台。
②target目的平台。
③perfix安装位置。
④xxx-xxxx-xxxxx平台描述,完整格式是CPU-制造厂商-操作系统。
假设使用的主机平台是x86,操作系统为Linux,目标板是基于MPC850的嵌入式开发板,交叉编译器的安装位置是/usr/bcng。可以按以下步骤来构造交叉编译器(make和make install省略):
1.1 载源码包
binutils-2.10.1gcc-2.95.2gcc-core-2.95.2glibc-2.1.3Linux-2.4.4
1.2 构造binutils
./configure-target=powerpc-linux-prefix=/usr/bcng
编译完成后,在/usr/bcng/bin目录下将生成交叉汇编器和连接器以及一些实用工具。最后应在环境变量PATH中增加路径:PATH=/usr/bcng/bin:$PATH。
1.3 建立bootstrap gcc
生成交叉汇编器(crossassembler)和交叉连接器(crosslinker)之后,现在需要构造一个交叉编译器。如果只想编译内核,则只需建立一个bootstrap gcc即可。但如果还想编译其他使用共享库的应用程序就必须构造一个glibc,并重构一个完整的gcc。重构gcc首先要build一个bootstrap gcc,然后用他来生成重构完整gcc所需的头文件和共享库,最后重构完整的gcc。注意:应使用gcc-core源码包来建立bootstrap gcc。
./configure-target=powerpc-linux-with-newlib-
without-headers-prefix=/usr/bcng
1.4 交叉编译Linux内核
用bootstrap gcc交叉编译Linux-2.4.4内核,形成构造gcc所需的目标特定头文件的版本信息(version.h)及符号连接。在Linux-2.4.4根目录下的Makefile文件中输出如下环境变量:
ARCH:=ppc
CROSS_COMPILE:=powerpc-linux
依次执行make menuconfig,make dep,make clean,make zImage来编译Linux内核,编译完成后将在./include/linux目录下形成version.h文件。
1.5 交叉编译Glibc
交叉编译Glibc形成构造完整gcc所需的库。在编译Glibc时要特别注意MPC850不支持浮点运算并且CPUCache不是源码中默认的32 B而是16 B,所以在编译之前,应该对源码进行修改或是下载patch。
在/usr/bcng/powerpc-linux/include下建立2个符号连接asm,linux分别指向linux-2.2.4/include/asm和linux目录。
输出如下环境变量:

完成上述工作后,就可以配置并交叉编译Glibc了。在配置时应当注意:如果使用Linux为目标板的操作系统,则应该打开-enable-add-ons=linuxthreads(需要下载glibe-linuxthreads-2.2.4源码包)选项开关以使glibc库支持Linux多线程。

1.6 重新构造完整的gcc
编译完Glibc后,就可以使用生成的头文件和库回过头重新构造完整的gcc了。

以上步骤完成后,就可以用自己的交叉编译工具来编译内核及应用程序了。如果还需要调试器的话,可以下载gdb和gdbserver源码编译生成gdb调试器。
2 裁剪Linux内核
Linux内核的可裁剪性使我们能够方便地将内核通过修改、裁剪、编译移植到一个嵌入式系统中。这里以Linux-2.4.4为例(可从从www.kernel.org下载源码)介绍如何对内核进行裁剪和修改,嵌入到MPC850 Rpxliteboard上。
2.1 内核启动顺序
对Linux内核进行移植,必须对内核的布局及其启动过程有所了解。从内核的布局上看,分为特定于体系结构的部分和与体系结构无关的部分。在内核源码树下,Linux把特定于体系结构的代码放在arch目录下,而所需的头文件放在include目录下。例如arch/ppc目录下就是特定于PowerPC体系结构的代码。
内核启动时总是特定于体系结构的部分首先执行,设置硬件寄存器、配置内存映射、执行特定于体系结构的初始化,然后将控制转给内核中与体系结构无关的部分,内核启动流程如图2所示。

(1)CPU复位后,调用存储在ROM中的初始化代码完成对片上设备的必要初始化。
(2)Bootloader把内核解压到RAM中的指定位置,之后从内核入口地址处调用内核初始化程序(arch/ppc/kernel/head_8xx.S)并传递内核启动参数。
(3)内核得到系统控制权后,完成特定于体系结构的初始化如:设置中断向量,MMU,BSS等,接着跳转到start_kernel()(init/main.c)开始进行与体系结构无关的内核初始化工作。
(3)start_kernel()首先完成对硬件相关部分的初始化,然后初始化定时器、中断、控制台以及内核内部数据结构(VFS,IPC…)等,最后创建一个init线程。
(4)init()函数(init/main.c)对设备进行初始化后,挂入root文件系统,最后执行系统调用exec("/sbin/init")创建第一个用户进程。
2.2 裁剪内核

当然可以根据自己的需要和硬件配置情况,增加对网络、NFS等的支持。内核配置完成后,menuconfig将在include/linux/下生成autoconf.h宏定义文件,这样就可以根据该文件的定义来交叉编译内核了。
2.3 修改内核源文件
完成内核配置后,还需要对内核源码中与特定于硬件和体系结构的部分进行修改,通常需要修改如下几方面的代码:
(1)与体系结构及硬件相关的代码(arch/ppc,include/asm/ppc)。
(2)内存映射地址。
(3)设备驱动(/driver、arch/ppc/8xx_io)。修改内核代码时,应注意几点:
(1)内存映射基地址IMAP_ADDR(include/asmppc/rpxlite.h)应该和bootloader中的定义值相同。
(2)内核启动程序的入口地址应和bootloader中定义相同。
(3)bootloader传递给内核启动程序的参数地址及顺序应该相同。
(4)根据SMCs和以太网口的配置,修改arch/ppc/8xx_io/uart.c和enet.c。
2.4 交叉编译内核
在源码树根目录下的Makefile文件中,输出如下环境变量:

修改完成后,依次使用make clean,dep,zImage生成压缩内核映像文件vmlinux.gz。
3 root文件系统
在Linux内核启动后,内核需要挂入一个文件系统作为其root文件系统。在嵌入式系统中通常采用Ramdisk(initrd)和NFS作为Linux的root文件系统。如果使用Ramdisk,则需要制作一个压缩文件系统映像文件。如果使用NFS,就需要在主机上输出包含文件系统的目录。这里简要介绍一下Linux文件系统的基本结构以及如何制作压缩文件系统映像。
3.1 Linux文件系统的基本结构
文件系统必须包括支持完整Linux系统的全部东西,因此他至少应包括:基本文件系统结构,至少含有目录/dev,/proc,/bin,/etc,/lib,/usr;最基本的应用程序,如sh,ls,cp,mv等;最低限度的配置文件,如rc(系统启动脚本),inittab(包含启动过程参数),fstab(要登录的文件系统)等;设备:/dev/console,/dev/ttyS*,/dev/tty*等;基本程序运行所需的函数库。
3.2 制作压缩文件系统映像
(1)建立linuxfs目录将所需的文件系统的目录和文件copy到里面。
(2)dd if=/dev/zero of=ramdisk bs=1k count=6144,建立一个6144 k大小的空文件。
(3)losetup/dev/loop0 ramdisk,将该文件绑定到一个loopback设备上,形成一个虚拟盘。
(4)mke2fs-m 0/dev/loop0,在该虚拟盘上建立ext2文件系统。
(5)mount-o loop/dev/loop0/mnt/loop,把虚拟盘挂到/mnt/loop目录。
(6)把linuxfs下的文件和目录copy到/mnt/loop目录下,然后卸下这个挂接点。
最后,用gzip对ramdisk文件进行压缩后,就形成了Linux所需的文件系统的压缩文件。
4 PPCBOOT
有了Linux内核和文件系统,现在需要一个Bootloader来初始化MPC850 CPU和周边硬件并引导操作系统。PPCBOOT是一种与Linux紧密结合的嵌入式Power PCBootloader具有强大的功能、便捷的操作和良好人机界面。PPCBOOT主要完成对系统硬件资源(CPU,SDRAM,通信接口等)的初始化,下载并启动Linux内核。这里以PPCBOOT1.1.6为例介绍如何使用PPCBOOT来引导内核:
(1)在主机服务器上配置并开启TFTPServer。
(2)使用PPCBOOT的mkimage工具将内核和文件系统压缩文件转换成PPCBOOT可识别的映像文件。
(3)在PPCBOOTShell提示符下设置主机和目标板的IP及内核启动参数等,环境变量如下:

bootargs是PPCBOOT传递给内核启动的参数,这里表示使用ramdisk作为内核的root文件系统。如果将bootargs设置为:
![]()
则表示使用NFS方式将主机192.168.0.108上的目录/home/bcng/export作为输出的文件系统,挂入到内核作为其root文件系统。
在系统开发阶段,通常需要频繁修改文件系统中的文件,使用NFS作为root文件系统是非常方便的。选择NFS就必须在配置内核时设置对网络及NFS的支持,并且还要在主机服务器上开启NFSServer,在/etc/exports文件中输出与nfsroot变量相同的目录作为NFS文件系统目录。
(4)用tftp下载并引导内核。
如果能过在控制台终端上看到Linux内核启动的打印信息,最后出现Shell的命令提示符,那就说明内核已成功移植到MPC850上了。
5 结 语
本文所介绍的基于MPC850的嵌入式Linux内核的移植过程,是笔者所做工作的总结,供读者参考。移植过程并不是千遍一律的,有可能会碰到许多新的问题,这就要求根据实际情况具体问题具体分析。根据出现问题的位置认真分析原因反复修改调试,从而实现内核的成功移植。
参考文献
[1]Motorola Inc.MPC850 family user′s manual.2001.1.
[2]Wolfgang Denk.DENXPPCBoot and Linux guide(TQM8xxL).http://www.denx.de/doc/TQM8xxL/2002.11.2.
[3]Boas Betzle.Linux for PowerPC Embedded syst ems HOWTO.http://penguinppc.org/embedded-/howto/PowerPC-Embedded-HOWTO.html2001.8.21.

