嵌入式跨平台虚拟软件技术的研究与应用
2012-09-25高杰
高杰
(南昌大学共青学院 信息工程系,九江 332020)
引 言
从RISC到CISC的目的就是使得在CISC上运行的程序(OS+APP)能够运行在RISC的体系结构上,转化过程包括指令解码、为OS建立运行环境等。嵌入式跨平台体系结构如图1所示。RISC体系结构的CPU有ARM处理器、MIPS处理器、龙芯、Godson等,CISC的平台主要有X86系列。首先要完成的指令解码包括ARM到X86(简称A2X86)、MIPS到 X86(简称 M2X86)、龙芯到 X86(简称D2X86)、Godson到X86(简称G2X86)。其次要完成BIOS功能。众所周知,CISC上运行OS需要BIOS的支持,因此需要在指令解码上一层为OS建立BIOS,即需要一个Vbios来支撑OS的运行。
1 基本理论
1.1 嵌入式跨平台虚拟软件概述
图1 嵌入式跨平台体系结构
龙芯2E体系结构和X86(在本文中所指定的X86主要包括8086、80286、80386、80486)的体系结构有很大的差别,包括指令操作码不同、寻址方式不同、内存管理不同、中断处理机制不同等。从应用架构上看,其结构方式也不一样,X86CPU体系结构经过多年的发展已经形成了一套运行微软操作系统的标准。支持X86CPU的软件也有自己的规范和要求,X86下的软件非常丰富也很成熟,包括OS和应用软件在内的软件都是根据X86的架构设计的,所以这些软件很难移植到像龙芯这样的体系结构上。鉴于此,在龙芯2E硬件层上设计一个软件层虚拟机程序,让龙芯2ECPU上能够运行X86下的OS和应用程序。具体的运行过程是,让虚拟机程序能够在系统加电后开始运行,来解析X86下的程序,从而使X86下的程序能够运行在龙芯2E体系结构上。解释X86程序的软件叫Vx86虚拟机。简单地说,Vx86虚拟机要完成的功能就是在龙芯2E的体系结构上建立一个可以运行X86程序的X86虚拟硬件环境。跨平台虚拟机层次结构如图2所示。
龙芯2E没有像X86下BIOS那样一个标准的初始化程序,它是由一个bootloader来完成初始化的。龙芯虚拟X86CPU需要完成以下几个模块:bootloader初始化程序、VBIOS程序、Vx86虚拟机程序。Vx86虚拟机在龙芯2E上的启动过程如图3所示。首要的任务是完成语言的识别和CPU处理的模拟,X86实现了在RISC的处理器上虚拟一个软件X86处理器模型,包括其所有寄存器和运算、取指、加载、计算、保存结果的指令流水线,同时还翻译所有X86系列的语言——X86二进制机器码。
图2 跨平台虚拟机的层次结构
图3 Vx86虚拟机在龙芯2E上的启动过程
1.2 嵌入式跨平台虚拟机开发环境
虚拟机的开发使用开源的开发环境,虚拟机是和操作系统无关的,所以在选择开发环境时只需要选择和硬件相关的开发环境即可,在这里使用龙芯2E的开源的 MIPS GCC编译器,版本号3.4.6。编译器运行在Linux操作系统下。开发语言选用C语言和MIPS汇编语言。
1.3 VBIOS
VBIOS是为了运行X86OS来初始化Vx86的BIOS程序。VBIOS的功能和X86BIOS的功能相同,是在Vx86运行起来的,其功能就是测试和初始化基本的外围设备,初始化完成后就去引导操作系统。
2 嵌入式跨平台虚拟机CPU虚拟设计
2.1 虚拟机CPU虚拟设计概述
CPU的虚拟就是用软件仿真一个X86的CPU,主要的设计有CPU处理器虚拟设计、寄存器虚拟设计、中断虚拟设计、取指虚拟设计、解码虚拟设计5大模块。Vx86 2.0设计中,这些设计相互间联系紧密,没有进行绝对的划分,下面将其揉合到一起来说明。
CPU虚拟中的功能包括了中断检查、取指和指令执行等几大模块,CPU虚拟中断程序流程如图4所示。
图4 CPU虚拟中断程序流程
在虚拟CPU的无限循环中,每次在取指和指令执行前都要进行中断检查,如果有中断到达,就先进行中断处理,处理结束后再回到中断时的位置继续执行。在这些过程中要虚拟真实CPU的取指令、译码指令、中断管理、内存管理等过程。下面定义的数据结构是为了完成CPU虚拟的核心数据结构。
2.2 CPU模块虚拟
Vx86在设计时采用了动态翻译的设计方法。虚拟机每次取指后,将取回的指令翻译成指令虚拟函数,接着执行这些翻译后的虚拟函数,执行后将翻译后结果保存在全局结构中,以方便下次使用。下一次CPU遇到同样的地址时,先到保存的缓存区中查找,如果找到就直接从保存的全局缓冲区中使用,如果没有找到就去重新翻译。这样的设计方法可大大提高虚拟机执行速度。
2.3 虚拟机取指和翻译虚拟
CPU的取指主要靠CS和IP/EIP来实现,在完成虚拟机时需要用软件模拟CPU的取指过程。在保护模式下取指需要解决如下的问题:
①段式管理。
②页式管理。
③指令跨页问题。由于在80386模式下有页式管理,页式管理时把物理内存分成了大小相同的4KB块。线性地址会把不连续的4KB物理内存映射到连续的线性地址空间,所以在虚拟时就要解决指令跨页问题。
④指令指针移动问题。根据系统设计说明书可知,80386的指令最长可达16字节,指令不定长,所以每次在取指完要对eip进行修改。
⑤判断访问的物理内存是否越界。解码虚拟主要完成的工作是根据80386的指令结构特点,将指令中的各个字段解析出来,然后根据各个指令码的特点寻找指令虚拟函数。根据需求分析和系统设计可知,指令结构由指令码前缀、指令码、MOD-REG-R/M、SCALE-INDEX-BASE、偏移量、立即数几部分组成。
3 嵌入式平台虚拟机的bootloader设计
3.1 bootloader概述
在嵌入式系统中,bootloader是芯片复位后执行的一段代码,这段代码完成硬件的检测与初始化、设置系统运行环境、引导OS,作用与PC启动时的BIOS相当。bootloader的执行可以分成两个阶段,一是boot,二是loader。前一阶段与平台硬件紧密相关,用汇编语言来实现;后一阶段与平台无关,用C语言来实现,使代码具有更好的可读性和可移植性。与其他bootloader不同的是,本文的bootloader不是引导OS,而是引导Vx86虚拟机,并且与Vx86虚拟机一起编译到一个BIN文件中,再下载到开发板上的Flash上。因此,引导时把Vx86虚拟机拷贝到RAM中,再跳转执行就可以了。
设计bootloader首先要先了解目标平台的CPU特点、异常处理、存储映射关系、I/O设备操作方法。因此本文先介绍龙芯系统平台的特点,再说明从CPU启动开始,如何初始化系统平台,直到引导Vx86执行。
3.2 龙芯系统平台概述
龙芯开发板上的CPU是龙芯2E处理器。龙芯2E是实现了MIPS III指令集的通用RISC处理器,采用9级指令流水线,包括取指、预译码、译码、寄存器重命名、调度、发射、读寄存器、执行、提交。龙芯2E使用了3个独立的Cache:一级指令Cache,64KB的容量,采用4路组相联的结构;一级数据Cache,64KB的容量,采用4路组相联的结构;二级混合Cache,片上Cache,512KB的容量,采用4路组相联的结构,使用的是写回法。龙芯2E对程序地址空间的映射分为4部分,如图5所示。
图5 龙芯2E地址空间的映射关系
kuseg:0x000 0000~0x7FFF FFFF(低端2GB),这些是用户模式下可用的地址。在带有MMU的机器里,这些地址都将由MMU加以转换。
kseg0:0x8000 0000~0x9FFF FFFF(512MB),只需要把最高位清零,这些地址就被转换(translate)为物理地址,然后把它们连续地映射到物理内存中512MB大小的低字段 (0x0000 0000~0x1FFF FFFF)内。一般情况下,都是通过快速缓存对这段区域内的地址进行访问。因此在Cache被正确地初始化之前,不要使用这些地址。
kseg1:0xA000 0000~0xBFFF FFFF(512MB),通过将最高3位清零的方法,把这些地址映射为相应的物理地址,然后象kseg0一样,再映射到物理内存中512MB大小的低字段。但要注意,kseg1是不通过Cache存取的(uncached)。kseg1是唯一的在系统重启时能正常工作的地址空间,这也是为什么重新启动时的入口向量0xBFC0 0000会在这个区域内。
kseg2:0xC000 0000~0xFFFF FFFF(1GB),这段地址空间只能在核心态下使用并且要经过MMU的转换。在MMU设置好之前,不要对其进行访问。
3.3 系统初始化过程
对于本文来说,bootloader的工作主要在boot龙芯平台,即初始化能运行系统的最小硬件环境,如北桥和南桥、DDRAM控制器、龙芯2E的Cache;初始化调试环境,如串口;然后把整个系统搬移到RAM中运行,再执行Vx86虚拟机。下面介绍详细的过程。
当CPU启动时,从地址0xBFC0 0000处取代码执行,这个地址被映射到开发板上的Flash零地址偏移处,因此必须把bootloader烧录到Flash的零地址偏移处才能正确执行。在连接脚本中有ENTRY(_start),程序的入口点是标号为start的代码,从start开始的代码被烧录到Flash的零地址处偏移处。
“mtc0zero,COP_0_STATUS_REG”是CPU执行的第一条指令,把状态寄存器清零。然后把COP_0_CAUSE_REG清零,接着是设置状态寄存器的BEV位,这样发生异常时,CPU从Flash上取异常处理的代码。在异常处理时可以打印出触发异常发生的原因、指令,便于调试。接着设置引导程序的堆栈空间,“la sp,stack”是把栈首地址给sp寄存器,“la gp,_gp”是把编译器中的_gp全局地址给gp寄存器,这样做是让全局变量可以进行相对寄存器寻址。最后,执行Vx86虚拟机,直接通过函数调用来实现:VX86_Entry()。
结 语
本文讨论的嵌入式跨平台虚拟软件技术应用,重点讲述嵌入式跨平台虚拟机CPU虚拟设计和bootloader设计。根据以上的分析可知龙芯2E虚拟80386、80486,甚至Pentium 4以下的机器都是可行的。龙芯2E已经提供了一个可行的硬件环境,实现X86平台的软件可以运行在MIPS平台上。
[1]张凯龙.传统OA的Linux中间件平台移植技术及其实现[D].西安:西北工业大学,2003.
[2]戴梅萼,史嘉权.微型计算机技术及应用[M].4版.北京:清华大学出版社,2008.
[3]Dominic Sweetman.See MIPS Run[M].SanFranciso:Morgan Kaufmann Publishers,2008.
[4]李小波.龙芯2号功能部件半形式化验证方法的研究与实现[D].北京:首都师范大学,2006.
[5]李会,邬迪.嵌入式系统在工业控制中的应用[J].微计算机信息,2007(2).
[6]Bill Blunden.Virtual Machine Design and Implementation in C/C++[M].[S.I.],2003.