windows无盘启动技术开发之使用本地镜像文件启动电脑

                                             by fanxiushu 2023-07-26 转载或引用请注明原始作者。
其实使用本地镜像文件启动电脑,这个windows操作系统本身就是自带的功能。

win7以上的系统,制作 vhd或vhdx格式的镜像文件,
然后在镜像文件中安装windows操作系统,然后放到真实硬盘的某个分区的某个目录中。
然后在真实的操作系统中修改BCD配置文件,把BCD配置成从刚才安装了操作系统的vhd或vhdx镜像文件启动,
这样电脑下次启动的时候,就自然从vhd或vhdx的镜像文件中启动了。

自从win7开始,创造了 vhd或vhdx格式的镜像文件以来,就有了这样的功能。
只不过我一直没用过,不知道能用来干嘛。
不过也确实挺新奇的,
你想啊,本来按照正常的思路,应该是老老实实的在真实硬盘分区中安装操作系统,
然后从真实硬盘分区中启动电脑,
现在变成了:可以从真实硬盘中的某个镜像文件(vhd或vhdx格式文件)中启动电脑。

本文并不打算介绍windows自带的这种功能,
而是从windows无盘启动技术出发,开发我们自己的从本地镜像文件启动windows操作系统的功能。
这个应该是我在阐述 UEFI引导程序开发的第2篇文章末尾提到过这么一个类似的功能:
windows无盘启动技术开发之UEFI(新一代BIOS)引导程序开发之二_uefi驱动开发_雨中风华的博客-CSDN博客

从无盘启动技术出发,开发自己的从本地镜像文件启动windows操作系统。
可以让我们从原理上深入理解windows上面的从vhdx这样的镜像文件启动系统的骚操作。
同时从原理上掌握,让我们有了更多的自主权,
比如镜像文件格式可以自己定义,(我一般都是使用原始镜像文件格式,因为这样简单而且高效)
比如把各类不同操作系统集成到一起来,
比如把linux和windows的镜像文件都放到NTFS分区的硬盘中,
当然这需要linux和windows中都开发类似的功能,工作量也不少。
而且牵涉到linux使用不同的文件系统,还得在linux内核中开发对应的NTFS文件系统。

当然,如果全程都是自己开发的网络方式的无盘启动,这个事情就变得轻松了些,
甚至可以把从从本地镜像文件启动这个功能,加入到网络无盘启动中去,作为一个小小的附加子功能。
我就是这么做的,在实现了网络方式的无盘启动之后,
也许是好玩,也许是验证这种技术可行性,当然目前好像也没发现这玩意有啥用处。

反正不管怎么说,先让我们来看看下面的演示视频:

win10系统的无盘启动过程

 

win7 无盘系统启动过程+


第二个视频的前半部分,是展示从网络方式的无盘启动过程。
视频的后半部分,展示的是从本地镜像文件启动的过程。
本地镜像启动稍微快些,因为毕竟是读写本地镜像文件,比网络传输快些。

现在,我们来看看本地镜像启动的具体实现过程。
其实正如我在在阐述 UEFI引导程序开发的第2篇文章末尾所提到的。
如果你对整个无盘启动技术熟悉,那么对从本地镜像文件启动的理解,也不会有什么难度。

本文主要讲述的是在UEFI启动环境下的本地镜像文件启动。
其实传统的BIOS也可以实现的,但是在传统BIOS下实现起来过于繁琐。
主要是我不是太熟练传统BIOS环境下16位程序的详细开发过程。
(CSDN阐述 Legacy BIOS引导程序开发,那个代码基本做于多年前,
当时也是花了想当多的精力到处查资料,恶补16环境下的程序开发,
随着传统BIOS渐渐退出历史舞台,对16位程序的开发只会越来越陌生。)
比如第一个难题就是如何在传统BIOS环境下,实现 NTFS文件系统。
虽然可以查很早以前关于DOS的实现,
或者比如WINXP泄露的代码,找到16位环境的NTFS实现,但是我想肯定得花相当多的精力。
再比如Legacy BIOS中,有部分实现代码必须是放到固定扇区的,
实现NTFS文件系统的代码也必须放到固定扇区中,就像 windows中的ntldr,bootmgr等这些引导程序一样。
Legacy BIOS不像  UEFI,
UEFI全程使用文件系统方式,你不用关心引导文件究竟该放到磁盘哪些扇区位置。
所以最终也只好放弃,只实现 UEFI 环境下的本地镜像文件启动。

自己实现本地镜像文件的启动,其实跟网络方式的无盘启动类似,
基本也需要实现两个核心部分:
1, UEFI环境下的引导程序,具体需要实现哪些功能,下面会讲述。
2,windows环境中的虚拟磁盘驱动。

对于第一部分,UEFI环境下的引导程序。
这个引导程序不限于放到本地磁盘的ESP分区的 EFI\Boot\bootx64.efi 中,
就如上面视频演示的那样,
这个UEFI引导程序也可以通过网络方式加载,比如PXE引导方式加载。
反正只要让他在UEFI环境中能正常运行起来就行。
这就是与传统BIOS的引导程序差别巨大的地方,可以说是十分方便。
当然,既然是本地镜像文件启动,放到本地硬盘的ESP启动分区的 EFI\Boot\bootx64.efi  更合理些。

这个UEFI环境下的引导程序开发,也没有多少好讲述的,
因为在CSDN前面阐述 UEFI引导程序开发的两篇文章中,已经阐述了关于UEFI引导程序的开发。
都是需要在 UEFI 引导程序中实现 BlockIO接口的虚拟磁盘驱动,
然后使用 LoadImage和StartImage等函数,从这个虚拟磁盘驱动中找到 EFI\Boot\bootx64.efi 引导程序,
然后加载它,之后就完事了,接着就是windows自己的事情。
与网络引导方式的唯一不同的就是这个 BlockIO虚拟磁盘驱动的数据来源。
网络引导方式的虚拟磁盘驱动,当然是从网络传输过来,所以必须实现 SNP(UNDI)或者UDP接口网络通信。
而现在这个数据来源是来自本地磁盘上的某个镜像文件,
因此,现在我就必须得正确读写本地磁盘上的这个镜像文件。

假如我们的本地硬盘格式化为NTFS文件系统,镜像文件放到某个NTFS分区上。
那我们就必须在UEFI引导程序中实现NTFS文件系统的访问。
同样的,如果本地磁盘格式是其他的。比如ext3、ext4等linux下的文件系统,
我们也必须在UEFI的引导程序中实现对这些文件系统的访问。

我这里采用的是 ntfs-3g 这个开源的 NTFS文件系统,
https://github.com/tuxera/ntfs-3g
这个代码里底层实现中,
读写具体扇区的接口函数,只实现了 windows和unix下,没有实现 UEFI。
但是我们可以仿照源码中windows和unix读写扇区的接口函数,实现UEFI中的扇区读写接口。
也可以不用麻烦自己实现,因为github上,有人已经实现了 UEFI环境下的 NTFS对应接口。
当然,大部分都是以UEFI单独驱动方式实现。
我们这里是直接集成到自己的 UEFI引导程序中,没必要再安装一个单独的 DXE驱动。
因此得做些修改。

在我们的UEFI引导程序中,通过 BS的LocateHandleBuffer 函数遍历所有 BlockIO设备,
然后尝试使用 NTFS-3G 去挂载BlockIO,能挂载成功,说明是 NTFS分区。
就这样,把所有是NTFS系统的分区都挂载上。
然后,我们就可以通过手动输入具体的某个镜像文件名,
或者遍历NTFS分区的某些目录,找到感兴趣的镜像文件。
然后以这个镜像文件作为我们新建立的BlockIO虚拟磁盘驱动的数据源。

至此,本地镜像启动的UEFI引导程序基本完成。
当然,为了让windows下的我们的虚拟磁盘驱动,
能接着访问UEFI引导程序使用的镜像文件,
我们还得通过共享内存的手段,把UEFI访问的镜像文件名等参数,传递给 windows下的虚拟磁盘驱动。
这个功能就像 iSCSI磁盘下所谓的 iBFT 一样。当然,原理一样,传递的参数等各方面都不同。

然后,接下来,就是windows平台下的虚拟磁盘驱动开发了。
这个也没必要细说,因为我在CSDN上介绍了许多这方面的知识。
你可以使用 windows的StorPort框架,也可以自己全套实现类似StorPort框架的虚拟磁盘驱动。

接着就是找到UEFI引导程序共享内存中的关于哪个镜像文件名等相关参数。
然后打开这个镜像文件,创建基于这个镜像文件的虚拟磁盘作为接下来的windows系统磁盘。

当然,上面的过程看似简单,但是,可能也并不是那么美好。
因为毕竟是在  Boot-Start 阶段,是非常早的启动阶段。
这个阶段,我们要访问真实硬盘中的镜像文件,
前提是对应的真实硬盘驱动必须启动起来,
这就又回到了前一篇文章阐述的无盘网络引导,网卡驱动的问题了。
但是情况稍好的是,大部分硬盘驱动,都是windows自己带的,
不像网卡驱动,种类繁多,非常难搞。
硬盘驱动种类不多,而且基本都是windows自己集成了对应驱动。
而且即便是第三方的磁盘控制器驱动,对应的厂商也会想方设法的跟windows联系,
把他们的磁盘控制器驱动集成到windows内核包中,否则真就没办法使用他们的硬盘启动系统了。
因此大部分磁盘,都能在boot-start阶段,找到对应的驱动能启动起来。

自然,如果遇到某些其他情况,磁盘控制器驱动是第三方的,而且并没有集成到windows的内核包中,
我们也得像上篇文章介绍的那样,手动在镜像文件中添加对应的硬盘控制器驱动。

以上说的是镜像文件放到 NTFS文件系统中的情况,
在NTFS文件系统中,windows端的虚拟磁盘驱动就省事多了,因为NTFS文件系统是现成的。

如果现在换一下,比如是linux系统下常用的 ext4 文件系统。又该如何办呢?
UEFI引导程序没啥好说的,都一样的工作量,无非是把 NTFS-3G换成了ext4,ext4开源代码肯定更多。
至于windows端,工作量就提升上来了。
主要就是对ext4文件系统的集成。
我们可以单独实现一个 boot-start 阶段运行的ext4文件系统驱动,
让它像windows中的ntfs文件系统驱动那样工作,能自动被识别,自动被挂载。
这样,我们在虚拟磁盘驱动中,依然可以简单使用 ZwCreateFile 函数打开ext4文件系统下的镜像文件。

当然,我们也可以把ext4开源代码直接集成到自己的虚拟磁盘驱动中来,
这省去了单独开发windows下的ext4文件系统驱动的麻烦,尤其是跟windows内核接口融合部分。
但是却增加了虚拟磁盘驱动的开发负担。
具体采用哪种办法,可以根据情况自己来定。