1 引言
μC/OS-II是专门为嵌入式系统应用而设计的嵌入式实时操作系统,人们在学习μC/OS-II时,一开始往往在基于PC机的DOS或 Windows环境下进行分析与研究。在这种环境中,带有μC/OS-II内核的应用系统(简称μC/OS-II应用系统)的运行,让人觉得它好像是一个 DOS程序,人们无法真实地领略实时操作系统的面貌。实际上,在PC机的DOS或Windows环境中,μC/OS-II应用系统确实是一个DOS可执行程序,它的运行离不开DOS或Windows环境。为了让更多的人掌握和理解μC/OS-II实时操作系统,笔者对μC/OS-II进行移植,使其完全脱离DOS或Windows环境而运行。首先设计Bootloader引导程序,由它来装入μC/OS-II应用系统;其次修改BORLAND C++编译器中的EXE启动代码,剥去与DOS相关的代码;最后修改μC/OS-II内核代码中与硬件平台相关部分的代码,使其能正常运行和正常退出。
2 bootloader的设计
Bootloader引导程序的设计是嵌入式系统软件开发的一个重要环节,它把操作系统和硬件平台衔接在一起,通过初始化硬件设备、建立内存空间映射,为最终加载操作系统内核建立正确的环境。由于Bootloader的实现依赖于CPU的体系结构,因此大多数初始化引导程序分为两部分,第一部分主要包含依赖于CPU体系结构的硬件初始化代码,第二部分实现的功能比第一部分更多更复杂,它为内核程序准备运行的环境,将内核装入到指定位置,并转到内核处运行。
软盘采用FAT文件系统,并对它进行格式化,使用工具将BOOT写到0面0磁道1扇区中,将LOADER和μC/OS-II应用系统程序复制到软盘中,然后用软盘启动系统,就能观察到μC/OS-II实时操作系统的运行情况,它完全脱离了DOS运行环境。同样,也可以通过Bochs、QEMU或 VMware等虚拟机做一个磁盘映像文件,用BOOT替换该映像文件的前512个字节,将LOADER和μC/OS-II应用系统复制到该映像文件中,然后就可以在虚拟机中完成系统的启动。这样,在每次修改程序后,不需要重新启动机器来验证系统的正确性,而只需要调整映像文件,在虚拟机中重启系统即可,使用虚拟机使内核的修改和调试变得十分容易。
2.1 BOOT的设计
当PC机加电后,首先进行自检,然后寻找启动盘,如果从软盘启动,计算机读取软盘的0面0磁道1扇区的内容,若该扇区最后两个字节是0x55、 0xaa,则其为引导扇区,计算机将其内容装入到内存地址0x7c00开始处,并转到该处运行。因BOOT只能占用一个扇区,其大小固定为512个字节,其实现的功能受到限制,所以BOOT的主要功能是在磁盘的目录区中寻找LOADER程序,并将其装入到内存中,最后将CPU的控制权交给LOADER,其后的任务就由LOADER完成。BOOT程序的算法描述如下:
(1) 在显示屏上显示“Booting...”提示信息,同时使软驱复位;
(2) 在磁盘的目录区中寻找LOADER文件;
(3) 若LOADER文件存在,则转(5);
(4) LOADER文件不存在,显示提示信息“Boot fail!”,关闭软驱马达,程序进入死循环;
(5) 将LOADER读到内存0x90000处;
(6) CPU转到0x90000处运行,即将CPU的控制权交给LOADER。
这段程序用汇编语言编写,它经过汇编连接后,使用工具软件,比如debug将其写到软盘的0面0道1扇区。
2.2 LOADER的设计
2.2.1 EXE文件格式
在DOS或Windows环境中,μC/OS-II使用BORLAND C++开发工具,因此,μC/OS-II应用系统的文件采用DOS的EXE格式,在装入μC/OS-II应用系统时,引导程序将按EXE文件格式的要求将内核加载到内存中。EXE文件由两部分组成:文件首部和程序主体。文件首部包含重定位信息和控制信息,它由编译器和连接程序自动生成;程序主体包含代码段、栈段、数据段等,它由EXE启动代码和程序员编的程序构成,它是程序实际运行部分。EXE文件首部内容如表1所示。
表1 EXE文件首部
2.2.2 LOADER程序的设计
LOADER程序实现的主要功能是负责将内核装入到内存指定位置。假定TEST.EXE为带μC/OS-II内核的应用程序的文件名,LOADER 装入程序将首先在磁盘中查找TEST.EXE文件,若找到,将其读入内存地址0x10000开始的空间中。LOADER根据EXE文件首部的重定位表对加载到内存中的程序进行地址重定位后,初始化运行环境,然后转到程序主体的入口处运行。LOADER程序算法描述如下:
(1) 软驱复位,然后在软盘目录表中查找文件TEST.EXE,若找到转(3);
(2) 在软盘中没有找到TEST.EXE文件,显示信息“Kernel file do not exist!”,关闭软驱马达,程序进入死循环;
(3) 将TEST.EXE程序读到内存0x10000h处;
(4) 根据重定位表对装入内存中的TEST.EXE相关内容进行调整;
(5) 初始化TEST.EXE的运行环境;
(6) 转TEST.EXE入口处,开始运行TEST.EXE;
(7) 结束。