摘要:本文介绍了在PowerPC405上利用嵌入式Linux来构建数字视频播放系统软件平台的过程,探讨了嵌入式Linux系统里交叉编译器、bootloader、Linux内核、根文件系统等几个主要部分的构建过程。
关键词:PowerPC405 嵌入式Linux 数字视频播放机 U-BOOT
引言: 数字视频播放设备在近几年的发展十分迅速,种类繁多。传统的视频播放设备(如DVD播放机)的软件系统一般都是一简单的控制环系统,没有操作系统,功能扩展和升级受到限制。本课题研究的便携式数字视频播放设备构建于嵌入式32位PowerPC405 CPU之上,运行Linux操作系统,以大容量的硬盘作为存储介质,具有网络功能。PowerPC405是IBM公司推出的一款专门针对嵌入式应用的RISC处理器,应用十分广泛。嵌入式Linux[1]作为一种开源的操作系统软件,具有免费、支持众多CPU、可裁减、支持网络、丰富的软件资源等特点。利用嵌入式Linux来构建数字视频播放系统的软件平台使得该播放机成本低,易于升级和管理,支持多种接口如USB,从而使得视频节目交换方便等优势,代表了该种设备未来发展的一个方向。本文主要探讨了构建应用于数字视频播放机的嵌入式Linux系统的bootloader、Linux内核移植的主要过程和可能碰到的问题,给出了相应的解决方案。
1 数字视频播放系统框图 图1-1 码流播放系统硬件框图
图1-1为本播放机的系统框图,其核心控制系统为基于PowerPC405的嵌入式Linux,通过其上的应用程序来把数据存储系统里的节目经过一定处理后搬移到码流控制系统里的FPGA里,由FPGA完成解密后送给解码系统,经过解码系统解压缩后输出RGB信号给显示设备来显示。其中我们要关注的就是核心控制系统里嵌入式Linux系统的搭建。 播放机的嵌入式Linux系统的层次结构如图1-2,硬件上电后,CPU的程序指针首先指向一个特定的存储器地址,该地址处一般存放着bootloader,bootloader在初始化完CPU以及内存等设备后,把Linux内核从一般ROM设备里搬移解压到内存里,然后程序指针跳转到内核在内存里的开始位置处,由Linux内核来继续完成剩下的系统引导工作。内核在重新初始化完系统后,就加载根文件系统,运行用户应用程序。整个嵌入式Linux系统平台的构建过程可以参照系统的启动过程,主要要做的工作有构建bootloader、Linux内核、根文件系统这几个部分。
2 嵌入式Linux系统平台搭建的准备 要搭建嵌入式Linux系统平台,首先要准备好跨平台开发工具链。它运行于本地主机上,编译链接生成的二进制可执行程序能够运行于开发板的CPU及操作系统上。构建这样一个主要包括编译器gcc,链接器ld,C库glibc等的工具链的方法有很多种,可以去相关网站下载源代码手工编译,而最便捷的方法则为利用完善的已编译好开发包,如德国denx公司的ELDK开发包。
3 bootloader与Kernel的选择 准备好了开发工具链之后,就可以开始嵌入式Linux系统的开发,首先是bootloader的选择。
3.1 bootloader的选择 一般的PC机启动后先是进入BIOS,通过BIOS进行一定的系统初始化后,再引导操作系统如Windows或Linux等,而一般嵌入式系统里没有BIOS,但也需要实现类似功能的模块,这就是bootloader(引导装载器),其主要的功能是初始化CPU、内存等硬件设备,以及导入操作系统。Bootloader种类很多,如blob、lilo、grub、U-BOOT等。目前在嵌入式领域用得最广泛的是denx公司的免费开源软件U-BOOT,它支持PowerPC、ARM、MIPS、x86等多种CPU,超过100种开发板,源码结构清晰,移植容易,开发文档丰富,用户在使用中可能碰到的问题一般都能够很快被解决。因此,我们选用U-BOOT做为开发板的bootloader。 根据不同的开发板,flash的大小以及型号不同,内存的大小不一样,启动方式的不同等使得利用U-BOOT时需要做一些相应的修改,以适应用户自己的开发板,具体移植方法及常见问题可参见[3]。
3.2 Linux内核的移植 bootloader初始化完系统硬件后,把Linux内核从外部存储介质中导入内存里,然后,就将控制权交给Linux内核,由内核来继续完成系统的引导工作。 如果内核里没有支持用户所使用的开发板,那么用户就需要自己手工修改Linux的内核,做一些相关的移植工作,要关注的是对开发板的硬件外设部分的处理,包括内核对板子硬件基本信息的处理,板上硬件设备的初始化、中断的分配等。 开发板级别的Linux内核移植最方便的方法是利用内核里已有的且与用户使用的硬件平台最接近的开发板为模板,在此基础上再做修改。我们使用的开发板与IBM walnut开发板类似,主要的外设包括硬盘、USB设备等都是利用PCI总线接口转接(PCI转IDE,PCI转USB),所以内核的移植工作主要有两部分, 一为bootloader和内核之间板子硬件信息的传递,二为PCI外设的初始化。 3.2.1 U-BOOT与Linux内核的配合 U-BOOT在初始化完硬件设备后,把内核装入内存,然后程序指针跳转到内核所在位置处的同时,会传递一些参数给内核来使用,其中就包括有board_info数据结构,内容包括板子的CPU主频、SDRAM和flash大小、ip地址、MAC地址等,Linux会利用这些参数来初始化系统。但Linux内核与U-BOOT的开发并不是同一个组织,要修改Linux内核的相关部分来匹配U-BOOT传递过来的数据,对于我们所使用的PowerPC,U-BOOT是利用五个通用寄存器(r3,r4,r5,r6,r7)来传递参数,我们需要修改通过r3寄存器传递过来的board_info数据结构(定义在Linux内核里arch/ppc/platforms/cs2000.h),使之与U-BOOT源代码里u-boot-1.1.1/include/asm-ppc/u-boot.h里定义的bd_info数据结构内容一致,这样内核才不会对U-BOOT传递过来的board_info数据结构进行错误解读。 3.2.2 PCI外设初始化部分的修改 Linux内核初始化PCI部分的主要过程为:扫描整个PCI总线,找到连接在总线上的所有设备,根据各PCI设备配置空间寄存器的信息,给各PCI设备统筹分配I/O空间,memory空间,以及IRQ中断号。对于x86平台,这部分工作其实已经在BIOS部分做过,Linux内核只需调用BIOS生成的配置即可,但对于我们嵌入式Linux系统,没有BIOS,这部分工作Linux内核要自己做。而对于各个不同的开发板,需要补充到标准的PCI初始化代码里的内容有两部分,一为PCI设备配置空间寄存器的访问方式,另一为PCI中断的配置。 根据PCI的协议规范,访问某PCI设备配置空间的方法为先使能该设备的IDSEL管脚,才可以读写该设备的配置寄存器组。但PCI规范并没有定义IDSEL管脚的连接方法,所以根据各开发板PCI从设备的IDSEL管脚硬件连线方法的不同,访问PCI设备配置空间的方法也不同。
图3-1PCI设备IDSEL管脚的两种接法
如图3-1所示,对于一般接法的(a)图,PCI从设备的IDSEL管脚是通过一电阻串联到PCI总线的地址线AD[11-31]中某一根,这样可通过在访问PCI总线的地址期内往AD[11-31]这些地址线一个个的置高电平,如果读回来的配置寄存器数据有效,说明该地址线连了某设备的IDSEL,若无效,说明未连接。而我们开发板则采用了图3-1里面的(b)接法,把PCI从设备的IDSEL管脚与CPU的一个GPIO端口相连,这样就可以通过控制GPIO来灵活的控制PCI总线上某设备的使能或者失效。在我们这种硬件连接下,访问PCI从设备配置空间时,需要先置该设备IDSEL管脚所连接的GPIO为高,再读写配置寄存器组。所以,对于我们这种开发板,需要在一般的读取配置寄存器空间的源码里(arch/ppc/kernel/indirect_pci.c),读写配置寄存器之前,插入下列代码: switch (dev_function) { case PCI_DEV1: set_gpio1_high(); //置相应的GPIO为高 case PCI_DEV2: set_gpio2_high(); default:break; } 另外一项需要修改的PCI初始化代码是有关PCI设备的中断号分配。对于没有BIOS的嵌入式Linux,PCI设备中断号分配是由内核根据板子的硬件连线来决定的。一般嵌入式设备不需要中断路径互连器,直接把插槽的/INT管脚与CPU的IRQ线相连。连接方法有很多种,如把一个插槽的四个中断脚都连到一个IRQ上,由操作系统来控制中断的复用关系,也可以一个PCI中断管脚只连一个IRQ线。所以PCI IRQ的分配这部分Linux代码要根据各开发板实际的中断连接方法来修改。 在我们的开发板里,每个PCI的/INT管脚都连接到一单独的IRQ线上,根据这种连接关系,我们从软件上可以构造出下面这样一张表: /* arch/ppc/platforms/our_board_name.c:ppc405_map_irq ()*/ static char pci_irq_table[][4] = /* PCI /INT PIN->INTLINE * A B C D */ { {28, 29, 30, 30}, /* IDSEL 1 - PCI 插槽 1 */ {31, 31, 31, 31}, /* IDSEL 2 - PCI 插槽2 */ }; 上表描述的PCI插槽1的/INT A中断的号是28,而这个28号中断的由来是该槽的/INT A与CPU的28号中断的IRQ线相连了。把所有PCI插槽的中断线与CPU IRQ线的连接关系填入表中,就可以通过内核里标准的PCI初始化代码正确分配各PCI设备的中断号了。当然,在板子的IRQ初始化部分(arch/ppc/platforms/our_board_name.c:board_setup_irq())还要正确设置这些分配了的中断线的触发方式,极性等。 Linux内核的移植牵涉到很多硬件的知识,对开发板的硬件原理图有比较清楚的认识可以对移植工作有事半功倍的效果。
4 结束语 有了bootloader,内核,再利用Busybox[4][5]来构建一个简单的根文件系统后,这个嵌入式Linux系统平台就已经搭建完毕,用前述过程所搭建的嵌入式Linux系统平台体积小,功能强,运行稳定,对于像数字视频播放机这种需要长期工作运行的设备而言非常适合,而且升级性强,对于未来的一些应用需求,可以通过开发板上的PCI、USB、Ethernet等接口进行扩展,可以说是为以后设备的进一步功能增强奠定了坚实的基础。本论文的创新点在于将传统的视频播放设备的简单控制系统升级为嵌入式Linux系统,并对嵌入式Linux系统的构建和移植作了详细探讨,特别是根据PCI设备的新连接方法提出了一种新的初始化算法,具有很强的应用价值。