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网卡驱动。

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

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

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

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

相关推荐
非凡ghost25 分钟前
猫眼浏览器(Chrome内核增强版浏览器)官方便携版
前端·网络·chrome·windows·软件需求
熊文豪6 小时前
Windows安装RabbitMQ保姆级教程
windows·分布式·rabbitmq·安装rabbitmq
搬砖的小码农_Sky6 小时前
Windows操作系统上`ping`命令的用法详解
运维·网络·windows
Kiri霧13 小时前
Rust模式匹配详解
开发语言·windows·rust
程序设计实验室15 小时前
使用命令行删除 Windows 网络映射驱动器
windows
用户311879455921817 小时前
Windows 电脑安装 XTerminal 1.25.1 x64 版(带安装包下载关键词)
windows
Logintern0918 小时前
windows如何设置mongodb的副本集
数据库·windows·mongodb
Chandler241 天前
一图掌握 操作系统 核心要点
linux·windows·后端·系统
ajassi20001 天前
开源 C# 快速开发(十七)进程--消息队列MSMQ
windows·开源·c#
Python私教1 天前
5分钟上手 MongoDB:从零安装到第一条数据插入(Windows / macOS / Linux 全平台图解)
windows·mongodb·macos