首先,是否有可能破解 Windows 并完全删除 BSOD 错误消息,并将其替换为“忍受并处理它”代码,该代码会强制 CPU 执行下一条指令,就好像从未发生过错误一样?如果可以,会发生什么?这样做会对计算机造成什么影响?我之所以问这个问题,是因为当我开始为 68K 自制计算机编写自己的操作系统时,如果发生内核崩溃,我想让用户在两个选项之间进行选择:重新启动,或者处理它并保持正常运行。我只是想确保在我意外损坏完好的硬件之前会发生什么。当我得到一台更好的计算机时,我可能会稍后尝试破解。
答案1
BSOD 只是 Windows 所称的 bugcheck 的视觉错误消息。Bugcheck(或 *nix 所称的内核崩溃)的发生是因为操作系统不能“处理它”。
例如 - 一条指令试图从不存在的地址读取数据。或者在无法解决页面错误的情况下尝试读取内存时引发页面错误。
您究竟会向需要读取操作结果的代码提供什么数据,以便它可以“继续”?
这些错误通常是因为相关指令访问了错误的地址。重试时你会将其更改为哪个地址?你怎么知道它应该是什么?
当然,写入内存时也会出现这些错误。好吧,你可以不写入,继续。但代码不会因为感觉像写入内存就写入内存。稍后其他代码将需要那些应该写入内存的信息,然后它会遇到与“继续”相同的问题。稍后会详细介绍。
一种可能的解决方法是更好地隔离组件。假设此错误发生在您的声卡驱动程序中 - 对于我们在机器上执行的许多操作而言,这是一个相当不重要的设备。您可能会说“让我们报告错误并停止使用声卡直到下次重新启动,也许用户会更新驱动程序或更换声卡。”
问题在于,内核模式下的所有代码和数据都同样值得信任。根据刚才看到的证据,在内核模式下引发的错误意味着内核模式下的所有代码和数据都不是值得信赖。而且无法知道它在引发操作系统注意到的错误之前是否造成了更微妙的损害。(这导致了“受害者并不总是罪魁祸首”的咒语。很常见的是,引发错误的代码之所以会这样,是因为内核模式中的其他组件破坏了内存内容。找到其他组件通常非常困难。)
错误检查方法的另一个方面:这些错误在被注意到后会立即被“报告”(通过崩溃)(通常是因为它们引发了无法处理的异常)。在一些错误检查原因中,实际上可以做一些看似合理的事情并继续下去。然而,这掩盖了错误发生的事实。内核模式中的错误最终可能会导致“I真的无法继续”的情况。
在上面给出的内存写入失败的例子中,是的,你可以说“所以不要写入”。但最终会有一些东西需要未写入的数据,然后那代码将会失败。
在内核模式出现错误的第一个迹象时崩溃,即使是某种可恢复的错误,也会让你得到尽可能接近问题的内存转储。长期经验(操作系统可以追溯到 NT 首次发布之前的几十年;BSD 和 VMS 都可以追溯到 70 年代末/80 年代初)表明,即使你设法修复问题并继续运行,并且系统后来崩溃了,找到问题也会变得更加困难。
问题不在于你“毁坏了好的硬件”。而是你根本就没有办法耸耸肩,继续前行,这样可能会有一个令人满意的结果。这就像你走到了岔路口,但你的 GPS 却告诉你要直走,这是一条不存在的路。你没有办法按照那个方向走,也没有提示你该走哪条岔路。你可以随机选择一条路……但这不太可能让你到达你想去的地方。(或者一个稳定的操作系统。)
但是,如果每个驱动程序都处于某种自己的沙箱或内存分区中,那么我们可以假设它没有对该分区之外造成任何损害,对吗?
确实如此!现在的问题在于您没有描述 x86/x64 架构或操作系统通常使用它的方式。
但是,嗯……如果你可以在自己的进程中运行每个驱动程序会怎么样?进程是相互隔离的,对吧?如果其中一个进程犯了这样的错误,我们可以关闭该进程,而操作系统的其余部分将继续运行。
事实证明,对于速度不太重要的设备,您可以这样做!这就是 Windows 的“用户模式驱动程序框架”的目的。
但是调用这些用户模式驱动程序需要很长的代码路径,包括许多环路转换和进程间上下文切换。(嗯,与调用内核模式驱动程序相比,很长。)您不会想将 UMDF 用于磁盘或视频卡。您可以将 HID 驱动程序移到那里,但 HID 驱动程序的问题基本上已经解决了。
不过,有些设备可以容忍延迟(尤其是在当今的快速 CPU 上),未来您将看到越来越多的驱动程序转向用户模式。对于真正需要 USB 3 速度的设备,UMDF 驱动程序可能太慢,但可以在 USB 1.1 上正常工作的设备(如串行端口适配器)可能不会介意使用 UMDF 功能驱动程序。随着 Win 8.1 带来的 UMDF 架构的改进,您将看到越来越多的设备使用 UMDF。
处理所有 USB 设备的 USB 主机控制器接口的“总线驱动程序”的至少一部分仍处于内核模式,因为它必须接触 I/O 端口和寄存器,并且这些内容只能在内核模式下访问;更改这一点将使所有安全性不复存在。
这导致了这样的结果:对于核心操作系统和内核模式驱动程序,它们必须保持内核模式才能执行它们必须执行的一些操作 - 使用特权指令、响应中断和可处理的异常、访问 I/O 硬件……x86/x64 指令集参考的“系统编程”部分中的所有内容。对于内核模式代码中无法处理的异常,恐怕“继续”的答案仍然是“到底做什么?”
抱歉,说得直白些,但说在内核模式下尝试未定义的操作只会导致错误消息并“处理它”是对内核模式的误解。您不能只是编造一个结果,并有理由认为后续代码会对此感到满意。