windows无盘启动技术开发之不同网卡使用同一个启动镜像的问题

by fanxiushu 2023-07-13 转载或引用请注明原作者。

这是一个非常烦的问题,也不是实现技术有多难,而是繁琐。

这也更进一步制约了无盘启动技术朝广泛以及更通用的方向发展,只能用在特定场所。

我所知道的,目前用得最多的地方就是网吧网咖了。

制作好的无盘启动镜像,动不动的,放到别的稍微不同的配置(主要是网卡配置)的机器上就启动不了。

哪像云桌面(简陋的来说就是我们通常理解的远程控制,传输图像的那种远程控制),

云桌面制作好的镜像,随便到哪个终端都能运行,基本不挑食。

当然它也有它的问题:运算压力都在服务器上。

先让我们来看看,无盘启动为何会发生这种问题。

在前面四篇文章阐述 Leagcy BIOS和UEFI的无盘引导程序开发的时候,

说过BIOS和UEFI引导程序,成功加载windows的基本内核文件和 start==0 的驱动到内存之后,

控制权就交给windows内核,windows接过了控制权 ,开始一点点的建立自己的势力范围,

windows的这个启动过程基本划分为三个阶段:

1, Boot-Start 阶段

2,系统初始化阶段

3,登录阶段。

其中我们最关心的就是 Boot-Start 阶段。

这个阶段,windows首先是执行引导程序加载到内存的基本内核(ntoskrnl.exe),以及hal.dll等基础库,建立基本的运行环境。

这个时候,各种基本环境建立起来,比如线程,各种EVENT,OBJECT等等。

然后windows内核开始运行BIOS或UEFI引导程序加载到内存的各种驱动(注册表中的services, 全部 start==0 的驱动)

在整个Boot-Start阶段,windows可以不访问磁盘,这是合法的。

当然如果有哪个处于 start==0的驱动,需要访问磁盘,得注意是否能成功,需要做好不能成功访问磁盘的准备。

但是在Boot-Start阶段,却是建立磁盘的阶段。

简单的说,Boot-Start阶段可以没有磁盘,但是必须在这个阶段建立起磁盘,能让windows进入下一个阶段前,正常访问磁盘。

否则没有磁盘系统,在进入下一个阶段前,

windows就会弹出经典的 7B ( INACCESSIBLE_BOOT_DEVICE )蓝屏界面。

建立磁盘的方式,就是执行磁盘驱动,让磁盘驱动控制磁盘硬件,从而建立起来磁盘访问系统。

因此,作为windows系统盘的磁盘驱动,必定是在boot-start阶段(也就是注册表中start==0)的驱动。

因此开发无盘启动,windows的虚拟磁盘驱动是必不可少的。而且必须是在boot-start阶段运行的。

而我们的虚拟磁盘驱动,要让它正常工作起来,就必须在boot-start阶段能正常进行网络通信。

要正常进行网络通信,windows中的NDIS驱动必不可少。

NDIS驱动分成三种(底层的NDIS小端口驱动,NDIS中间驱动, NDIS协议驱动)

NDIS小端口驱动,就是具体的网卡驱动。

因此要在 boot-start 阶段正常进行网络通信,网卡驱动也必须是start==0, 而默认情况下,网卡驱动基本都是start=3,

所以需要我们做些修改。

同时必须确定对应的网卡驱动能在boot-start阶段运行,

(可能有些网卡驱动使用了系统初始化阶段才能运行的某些库,虽然很少见,但是可能存在,

这种情况下,这个网卡不能作为无盘启动使用)

光能运行还不行,还得确保确实能在boot-start阶段能建立网络通信。

比如通常的无线网卡就没法在boot阶段建立网络通信。

这个时候,我们使用NDIS协议驱动或中间驱动,就能跟这个网卡驱动通讯,建立起正常的网络通信渠道。

有人会说,何必使用NDIS协议驱动这么麻烦,直接使用TDI驱动或WSK驱动,建立起类似应用层的socket通信不更好!

想法是美好的,实际情况是TDI或WSK等驱动基本是在系统初始化阶段才建立起来的。

我也曾尝试过把TDI,TCPIP,WSK等驱动的start设置为 0,让它在boot-start阶段启动。

结果还是没成功,还是无法在Boot-Start阶段使用TDI,WSK这些库。

因此只能认为这些windows自带的驱动框架确实不能在boot-start阶段完全启动起来。

有人会说,windows自带的iSCSI协议的虚拟磁盘也能作为无盘启动使用,

也就是说它也是可以在Boot-Start阶段运行的。

而 iSCSI 是使用 TCP 协议通信的,也就是说TCPIP.sys在 boot-start 阶段被使用了起来。

而我这里的实际情况则是:使用通用的TDI,WSK框架,确实没法在boot-start阶段使用。

因此推测windows自带的iSCSI是通过某种特殊办法,在Boot-Start阶段建立了TCP通信

(比如在boot阶段绕过了WSK等框架,直接使用TCPIP,毕竟是微软自己的内核系统,想怎么搞都行;

其实我们也可以在NDIS协议驱动基础上,建立自己的TCPIP协议栈,

比如使用开源的LWIP等,但是效率肯定没有windows自带的TCPIP好,

而且就为了磁盘读写这种单一的网络请求,而绕这么一大圈,纯粹是找不自在),

具体我没仔细研究iSCSI协议如何在Boot阶段保持TCP通信的。

当然也欢迎有质疑的同学,提出自己的不同意见。

好了,回到正题。当使用NDIS协议驱动连接网卡驱动,建立网络通信,可以正常读写镜像服务器上的镜像的时候。

我们的虚拟磁盘驱动就能正常工作了。这个时候,boot-start阶段的磁盘驱动建立了起来。

windows正常进入下一步的系统初始化阶段,也不会再出现 INACCESSIBLE_BOOT_DEVICE 的蓝屏。

一切流程似乎都很美好,没啥可以指摘的。

可是一切问题都出在网卡驱动上,

地球上,网卡很多,发展了几十年,即便没上万,起码也得有好几千各种类型的通常在使用的网卡吧。

而且我也怀疑,估计早过万了。

于是乎,不同类型的网卡都对应不同的驱动。

A电脑上对应A网卡,在A电脑上制作的无盘镜像,是A网卡的。

如果把这个无盘镜像放到B电脑的B网卡上,因为镜像中没有B网卡驱动,

不认识B网卡,Boot-Start阶段无法建立网络通信,虚拟磁盘驱动无法跟服务端的镜像沟通,无法模拟出启动盘。

自然就会出现 7B的经典蓝屏了。

而且更玄乎的是:即便是A电脑,比如有多个PCI插槽位置,当把A网卡放到一号插槽位置,制作启动镜像。

然后再把A网卡换到二号插槽位置,结果先前制作的启动镜像也可能没法启动。

这是因为windows系统中,不同插槽位置,可能会生成不同的实例串,而一号插槽位置的网卡驱动生成的实例串与二号的不同。

于是当把A网卡插到二号插槽,依然找不到网卡驱动。

(这里不要把处于 Boot-Start阶段的驱动和windows正常运行起来能自动从网上下载安装硬件驱动混为一谈!)

这事情就奇葩了,

所以最保险的就是A电脑固定网卡位置制作的镜像,就供给A电脑使用,或者与A电脑相同的网卡配置使用。

如此显然无法满更多的足实际需求。

让我们回到 Leagcy BIOS和UEFI上来,

上面说得这么热闹,几千乃至上万的各中类型网卡在windows都对应着各种不同的驱动的问题,

而在BIOS和UEFI中,好像完全没这方面的概念,现在随便哪块网卡,直接插上,就能在BIOS和UEFI中设置PXE网络启动 。

那是因为在BIOS和UEFI中,规范了PXE网络启动的接口,

任何要支持网络启动的网卡,都必须符合BIOS和UEFI提供的 UNDI 接口规范。

那么问题来了,windows中也提供了 NDIS接口规范啊,为何会造成两个差别这么大。

这是因为NDIS规范把具体硬件和windows上层协议隔离开来,设计NDIS目的就是为了让上层不关心任何与硬件相关的细节。

硬件的各种麻烦的中断,IO等交给网卡驱动处理,只向上提供一个统一的接口即可。

也就是硬件本身可以随意做,只需要硬件厂商开发的驱动能提供统一的NDIS协议接口就可以。

而BIOS和UEFI中的UNDI规范,更像是规范一个硬件接口,

也就是硬件只能这么做,只能提供这么一个硬件接口,才能符合UNDI规范。

而BIOS和UEFI本身的定位就是基本的前期IO系统,只需要基本的通信功能即可,这么规定没啥问题。

而如果像windows,linux这些系统把硬件要求固定死,

显然很不利于硬件发展以及在windows,linux系统上发挥最大的硬件性能。

于是可能就有另外一种想法,为何不把UNDI功能集成到windows内核中,

也就是windows内核提供一套类似BIOS或UEFI那样的统一接口函数,直接访问本来是提供给BIOS使用的网卡UNDI接口。

这个我没法回答,因为毕竟对底层硬件方面了解不是太多。

最大的推测可能是到了windows启动阶段,网卡厂商的网卡驱动全面接管网卡硬件之后,UNDI接口已经失效,

或者UNDI接口无法形成一套有效的能在windows使用的通用接口。

(这就像是在现在的windows想要通过 Leagcy BIOS的 13H中断访问硬盘一样无法办到。)

如果真的这么好做,我相信UNDI早就集成到windows内核中了,否则发展了这么多年,Intel还在大量推广UEFI等情况下。

也找不到现代系统内核(不限于windows,linux中也找不到)中对UNDI的支持。

说了这么多,可如何解决这个问题呢?

好像都没啥称得上很完善的办法。

一个目前来说比较常用的办法,就是提取真实电脑的网卡信息,然后合并到镜像文件中。

首先在新的不同配置的网卡的真实电脑中,提取网卡在注册表中的信息。

主要是三个地方,当然有些网卡可能不止这些地方,因此会需要特殊对待。

A,\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\XXXX, XXXX是对应网卡服务名

B,\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\PCI\VEN_XXX&DEV_XXX&SUBSYS_XXX&REV_XXX

C,\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\XXX,

找到对应网卡的具体位置,然后把上面这些位置从注册表导出来,

再找到对应的sys文件,也可能包括dll文件。

这样,大体算收集完成。

然后把注册表信息和对应的sys文件,合并到镜像文件中。

以上说的比较笼统。我这么做过,不过没成功,主要是测试对象是vmware虚拟机中,而且对应win7系统的虚拟机。

没有多余的真实机器来测试,只好vmware中测试。

在测试vmware虚拟机过程中,如果镜像是WIN7,使用NDIS5 才能启动到无盘,使用NDIS6 却无法成功,

只有vmware中装镜像是WIN10才能使用NDIS6启动到无盘。

后来调试才发现,vmware虚拟机在启动win7过程中,

不知道什么原因,如果是NDIS6协议驱动,Boot-Start阶段,无法得到网卡的Bind消息通知,

也就是NDIS6协议驱动的BindAdapterHandlerEx回调函数得不到调用,

就好像是vmware底层模拟的网卡硬件压根不存在一样。但是正常进入系统,却又能得到调用。

所以基本确定是vmware的问题。后来也懒得再去做测试了.

不过在真实电脑上,这么收集网卡信息,应该是没多大问题的,至少许多网卡都不会有太大问题。

目前好像大部分提供无盘启动的软件,都有类似的 网卡PNP提取工具,或者叫网卡PNP收集工具。

更先进点的,还可能是提供了一个数据库,专门从服务器上提供, 然后自动给镜像添加需要的网卡信息。

比如举一个可能的自动添加网卡信息的实现方案:

Leagcy BIOS或UEFI引导程序运行的时候,获取到网卡的硬件ID信息,然后发给服务器端。

于是服务器端判断无盘镜像中是否存在对应的网卡驱动,

如果没有,则从数据库中提取对应windows网卡驱动信息,然后合并到无盘镜像中。

接着再来响应引导程序的磁盘读写请求。这样到windows引导阶段,自然就不会再出现找不到网卡驱动的问题了。

所以,这些都不是很难解决的技术问题,而是很繁琐。那么多网卡,都去收集一遍,

而且针对特殊网卡,还得特殊处理,去多方面尝试。

而且随着windows版本的繁多,网卡驱动版本的繁多,以及不断新出现的网卡,遇到的实际问题可能更多。

当然经历了这么多年发展,无盘技术在这方面搜刮的网卡数据库应该是比较丰富的了。

所以,这里就不再进一步去啰嗦了。


除了上面讲述的,还有其他办法吗? 当然是有的。

我的目标是尽量让windows自己原汁原味的去安装网卡驱动,而不是收集网卡驱动然后合并到镜像文件中。

而让windows自己安装网卡驱动,就得让无盘镜像去启动不同配置的电脑,

而不同配置的电脑,因为网卡不同,是无法直接启动镜像的,于是乎,这似乎成了一个悖论。

但是我们可以换个思路,弄一个移动硬盘,没错,移动硬盘。

在移动硬盘中安装需要制作镜像的操作系统,这是可以办到的,

熟悉Windows To Go的安装制作的,对这个操作肯定不会陌生。

比如在A电脑使用移动硬盘安装操作系统,顺便当然也把A网卡的驱动安装了,其他驱动也一起安装了。

然后把移动硬盘插到不同配置的B电脑上,在B电脑上运行移动硬盘的操作系统,把B网卡的驱动也装上了。

然后就是C电脑,如此循环。直到完成。

然后制作无盘镜像上传到服务端。

以后这个移动硬盘都做同样的用途,如果需要安装新的软件,或者新的不同配置的电脑,都同样来一遍,然后上传新镜像。

虽然好像有些麻烦,但胜在简单,保险,网卡和各种驱动都是原汁原味的安装和更新。

比如,还有一个办法,弄一个USB接口的千兆有线网卡。

这个网卡有些需求,就是保证在不同电脑,生成的驱动实例必须一致,这个应该比较容易满足。

正规的USB设备都有唯一序列号,序列号保证了不同电脑都能生成唯一的实例。

然后在A电脑装上系统 ,同时装上这个USB网卡驱动。然后上传镜像。

接着在B电脑启动无盘,正常情况下,镜像中没有B网卡驱动,是无法启动的。

但是可以把USB网卡插到B电脑中,镜像中有USB网卡的驱动。

不过这里可能有些小问题,BIOS或UEFI可能 不认USB网卡作为PXE启动网卡。

于是可能就会出现PXE启动过程使用的是B电脑内置的网卡,

而到了windows启动阶段,才能使用USB网卡。

也就是出现了前后不一致,这需要无盘启动程序对这种情况提供一个支持。

使用USB网卡启动到windows之后,按照正常方式安装B网卡驱动。

这个安装的驱动就直接装到无盘镜像中了。

所以从通用性来说,还是使用移动硬盘的方式通用一点。

以上两种办法都是让某些硬件动起来,要么让硬盘动起来,要么让网卡动起来。

相信经常折腾无盘启动的,应该还有更多的解决办法。

相关推荐
弗锐土豆3 小时前
Windows系统中Oracle VM VirtualBox的安装
windows·虚拟机·virtualbox
秋の花3 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
零意@6 小时前
ubuntu切换不同版本的python
windows·python·ubuntu
写bug的小屁孩7 小时前
前后端交互接口(三)
运维·服务器·数据库·windows·用户界面·qt6.3
hairenjing11239 小时前
在 Android 手机上从SD 卡恢复数据的 6 个有效应用程序
android·人工智能·windows·macos·智能手机
plmm烟酒僧12 小时前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
Jtti15 小时前
Windows系统服务器怎么设置远程连接?详细步骤
运维·服务器·windows
TeYiToKu15 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
小奥超人15 小时前
PPT文件设置了修改权限,如何取消权?
windows·经验分享·microsoft·ppt·办公技巧
hairenjing11231 天前
使用 Mac 数据恢复从 iPhoto 图库中恢复照片
windows·stm32·嵌入式硬件·macos·word