Foxdisk3.0 开发历程
2009年的时候,第一次看到张老师,才知道软件原来可以这么玩的啊。因此,我停掉了想继续开发的自己的习作软件-Foxdisk,开发到3.02后,不再继续原定的任务了。我想用点时间去学习windows内核开发,为我当时遇到的一些问题寻求解决答案。
另外一个原因,我知道UEFI 的发展趋势劲头十足,Foxdisk作为一个多操作系统界面引导程序,根本核心还是在于通过修改的MBR,引导操作系统,并管理多个操作系统本身的引导MBR。这个天然的弱势,导致它在新的BIOS架构下,会逐渐消失。从1.0,2.0,到现在的3.0,传统bios下的引导程序,就这样了。所以,我借用博客,把它的开发历程记录下来,并且,在同事的怂恿下,把Release后的程序也发布出去,看看是不是有人和我有同样的需求。如果有任何人从中得到一些什么东西的话,那就是对我最好的回报了。
1 回顾
从参加工作起,我经常需要在若干个操作系统间使用不同的软件。比如有些软件只能在win2000下用,有些必须在XP下用。因此,借用了公司的一个引导软件,我在业余时间开始了自己的多系统引导程序的编写。
一般来说,我允许自己在同一台计算机、同一个硬盘上安装4个操作系统。Foxdisk1.0写得比较简单,主要就是实现了引导界面,把代码控制在31K之内(因为只有62个保留扇区可以使用)。为了使用尽可能多的功能,所以,全部使用汇编代码编写。写了大概8000行左右的代码,说句实话,写的时候很兴奋,重新去修改的时候实在头疼。除了使用宏之外,几乎没有办法去让程序变得更有可读性。
Foxdisk2.0的主要功能差不多,我花了比较大的精力在界面部分,希望营造出渐变、透明的效果,并且为它写了一个鼠标驱动。测试的结果,兼容性并不是很好,总是会有机器无法出现鼠标,大概是BIOS没有提供相应的中断接口。
这些都是06年左右的事情了。之后,在31K代码这个限制下,我觉得我无法添加什么功能,也就将就着用这个软件用了两年。
终于在2008年的某一天,我实在无法忍受了,重新制定了计划。主要目标如下:
A 采用C嵌汇编的方式开发,以C为主,保证未来代码可以移植;
B 脱离31K的限制,将代码写在硬盘末端,设计一致的存储规则,以保证未来的升级不影响原有功能;
C提供完整的分区功能,自动检查登载在Foxdisk上系统间分区交叉情况;
D提供更换壁纸功能,最大支持7张壁纸录入;
E 提供Windows、Linux、Mego等系统的引导支持,最大四个;
F 提供虚拟软盘功能,以允许运行Dos下的各种软件,方便用户维护系统;
最终的结果,除去最后一个功能,因为代码限制(我采用了small 方式编译,方便C与汇编间的交互,最大code为64K,data为64K)无法实现,其他基本完成了。
2 概览
先上图看看效果。
图1 开机启动界面
图2 主程序界面
图1中的启动界面允许用户替换为喜欢的图像,限制在1024x768 256色的bmp图,这也是为了程序处理简单,我没有花精力去研究图像格式的显示,直接用最习惯的bmp来做壁纸了。主界面中提供了完整的硬盘分区功能,参考的是开源的Spfdisk代码。在此谢谢作者冯绪平,读这样的代码给了我很多的惊喜和享受。不过,原有代码中有些BUG(参考的是2003版),我在自己的代码中修改了,估计作者后续也修改了,我没有作者发布2003年之后的代码。
3 程序设计构造
加载了Foxdisk3.0的硬盘结构如下图所示。
图3 硬盘布局图
其中,SETMAX_LBA是作为一个概念存在的。因为总是遇到有客户要求将系统隔离,即放在硬盘前端的系统不能访问硬盘后端的系统,而ATA标准中是提供了这样的命令的,即SetMax的命令,我预留了这样的机制,但是并没有去实现它。
整个程序分为安装代码和运行代码(所谓运行代码,指的是POST 之后,不依赖于操作系统运行的代码)。程序将Foxdisk运行代码安装在硬盘上,安装后的硬盘布局图如图3。
Para和os位置存放的是两个表格,Para的结构由Common.h中的struct FoxdiskPara表示,os的结构由同一文件中的OperationSystem结构表示。Os表的存放地址也在Para中,由其子段lba_ios表示。除去Para本身外,后续的所有数据位置,包括osmbr、wp的code&data及wallpapers(壁纸)都在Para的子段中包含了。
osmbr是操作系统的引导区代码,总共可以保存四个操作系统的MBR和一个保留的MBR,每个MBR有512个字节。缺省启动的是0号操作系统的MBR。
Code&data为Foxdisk核心代码,实际的映像是数据段在前(在硬盘内),代码段在后的。
Wallpapers是壁纸的存放位置,可以存放7张壁纸,缺省启动显示的壁纸是第七张。很容易可以计算出1024x768 256色的bmp图占用了多少个扇区(1024x768/512=1536个),这使得程序设计相对简单。当然,为了针对虚拟机等环境也可以正常使用,我是获取硬盘表来了解一个扇区占用多少个字节的(不一定是512字节),这样方便我去调试。
Para的存放位置是固定为maxCyl-ReservedCyl+1处,ReservedCyl定义在Global.h中。实际代码中,在初始化磁盘访问驱动的时候,CreateDiskParaTable中把maxCyl减去了相应的保留扇区。所以在运行代码中用到的maxCyl是已经减去了保留磁道后的值,但是磁盘驱动中的tnSectors段表示的还是实际的最大扇区数。除去Para,其他所有的数据位置均根据情况自动生成,并保存在Para中,初始化代码在安装文件Setup.c的InitKeyData()中。
实际上,整个程序的架构可以从下图看出。
图4 源代码结构图
在实际开发中,基于VESA标准的图形编程已经做得比较完整了,除去与硬件打交道的那些代码,实际的图形函数可以方便的移植到别的项目中。事实上,我已经做过这样的事情了,在UEFI下,开发了一个图形界面,就是用这里的代码移植的。
硬盘访问代码,用的是int13h。因为大部分是移植自spfdisk的代码,我没有去重组其架构,个人感觉那些代码还是不错的,值得一看。
汉字显示是编写时的一个难题,我希望显示宋体、楷体两种字体,并且能够对字进行阴影化、放大缩小等处理。因此,做了一些工具程序,可以自动的从源代码中提取汉字并自动从汉字点阵库中获取汉字点阵,以保证代码中只包含所需汉字的点阵。并且利用上面开发的图形函数,对汉字进行我所需要的变形处理。
另外值得一提的是主界面中时钟的显示和用户输入时的游标、大小写字母的转换,均使用了时间中断来循环处理。这部分的代码,因为希望足够快速而高效(实际上也没有这么严格),我使用汇编来写这些中断函数了。与我当时制定的只在引导函数部分使用汇编的初衷,有点违背了。但是当时最头疼的就是C的栈处理,一不小心就溢出了,所以,还是直接借用了Foxdisk2.0的代码。不过,我留下了鼠标驱动的接口,准备什么时候可以支持鼠标的,可惜最后也没有去实现。
其他的代码,比如内存操作、数值计算(因为要画不规则图形,用到了一些数学函数),在没有操作系统支持的情况下,只能自己写了。参考了linux的代码。
4 后记
09年4月左右,写完最后一行程序日志, Foxdisk 3就再也没有去更新了。我一直在自己的办公电脑上使用它,直到现在。使用过程中,发现了一些BUG,主要是对linux的支持做得不好,安装比较复杂。另外,我想为它写一个工具软件,可以让我方便的去操纵其内置的数据,以定制一些原有软件无法提供的功能。但是,这些想法统统搁浅了—我实在提不起劲去重写一款注定淘汰的软件。
因此,最后的结局,就是在同事的怂恿下,把软件的开发历程总结出来。本来我是准备将代码全部发布的,去年公司有个项目,要求是引导操作系统前出现客户要求的界面。我当时犯了懒,就直接用Foxdisk3的代码,使用其中的壁纸功能实现了这个要求。
所以,Foxdisk3中的代码就成了商业软件了。我无法全部公开这些代码,但是可以在探讨技术的前提下,共享部分代码。综上,如果你感兴趣的话,请让我知道:luobing4365@163.com。
目前我正在UEFI下开发一些东西,希望有机会可以开发一款基于UEFI的Foxdisk,为我当年刚出校门时的这份热情划上一个句号,那就比较完美了^^
这是Foxdisk3 的软件链接,运行在DOS环境下,可以用U盘做个DOS启动盘或者干脆用光盘来启动。我是把安装程序和运行用的代码编译在一起的,安装时,ifox.bmp是必不可少的。链接为:http://www.kuaipan.cn/file/id_113054401203013148.htm。声明在先,千万不要在有数据的硬盘上做实验,作者不承担数据丢失的责任。尽量用虚拟机或者闲置硬盘安装,我曾经吃过这样的亏,我不希望别人再重复一次。
真实的Foxdisk的界面设计图是这样的:
希望大家喜欢。