转载自:https://devblogs.microsoft.com/oldnewthing/20071224-00/?p=24063
作者:Raymond Chen
日期:2007年12月24日
欢迎,Slashdot 读者。请记住,本网站仅供娱乐。
Sean 想知道 MS-DOS 在 Windows 95 中的作用。我可能会后悔回答这个问题,因为它显然是 Slashdot 的诱饵。(即使 Sean 无意如此,它也会演变成那样。)
言归正传。请记住,我在这里写的内容可能不是 100% 真实,但它“足够真实”。(换句话说,它能说明问题,而不会陷入吹毛求疵的细节。)
MS-DOS 在 Windows 95 中扮演着两个角色。
- 它充当了引导加载程序。
- 它充当了16 位旧版设备驱动层。
当 Windows 95 启动时,会加载一个定制版的 MS-DOS,正是这个定制版处理你的 CONFIG.SYS 文件,启动 COMMAND.COM,它运行你的 AUTOEXEC.BAT,并最终运行 WIN.COM,从而开始引导 VMM(或 32 位虚拟机管理器)的过程。
这个定制版的 MS-DOS 功能齐全,就“功能齐全”这个词最初应用于 MS-DOS 而言。它必须如此,因为当你以“单 MS-DOS 应用程序模式”运行 Windows 95 时,它就是唯一运行的东西。
WIN.COM 程序开始引导大多数人认为的“真正的 Windows”。它使用 MS-DOS 的副本加载虚拟机管理器,读取 SYSTEM.INI 文件,加载虚拟设备驱动程序,然后关闭任何正在运行的 EMM386 副本并切换到保护模式。保护模式就是大多数人认为的“真正的 Windows”。
一旦进入保护模式,虚拟设备驱动程序就会发挥其魔力。这些驱动程序除了其他事情之外,还会“吸干 MS-DOS 的大脑”,将所有状态传输给 32 位文件系统管理器,然后关闭 MS-DOS。所有未来的文件系统操作都将路由到 32 位文件系统管理器。如果程序发出 int 21h,32 位文件系统管理器将负责处理它。
这就是 MS-DOS 第二个作用的体现。因为,MS-DOS 程序和设备驱动程序喜欢修改操作系统本身。它们会替换 int 21h 服务向量,它们会修补操作系统,它们会修补低级磁盘 I/O 服务 int 25h 和 int 26h。它们还会对 BIOS 中断(例如 int 13h,低级磁盘 I/O 中断)做一些疯狂的事情。
当程序发出 int 21h 调用来访问 MS-DOS 时,调用会首先到达 32 位文件系统管理器,它会进行一些初步处理,然后,如果它检测到有人钩挂了 int 21h 向量,它会跳回 16 位代码以让钩子运行。替换 int 21h 服务向量在逻辑上类似于子类化窗口。你获取旧向量并设置新向量。当你的替换处理程序被调用时,你做一些事情,然后调用原始向量来做“通常会发生的事情”。在原始向量返回后,你可能会在返回给原始调用者之前做更多的工作。
CONFIG.SYS 加载的 16 位驱动程序之一叫做 IFSMGR.SYS。这个 16 位驱动程序的任务是在其他驱动程序和程序有机会之前首先钩挂 MS-DOS!这个驱动程序与 32 位文件系统管理器串通一气,它的任务是从 16 位代码跳回 32 位代码,让 32 位文件系统管理器继续其工作。
换句话说,MS-DOS 只是一个极其精巧的诱饵。任何 16 位驱动程序和程序都会修补或钩挂它们认为是真正的 MS-DOS 的东西,而实际上那只是一个诱饵。如果 32 位文件系统管理器检测到有人上钩,它就会让诱饵发出“嘎嘎”声。
让我们从一个不包含任何修补或钩挂 MS-DOS 的“邪恶”驱动程序或程序的系统开始。- 程序调用 int 21h -> 32 位文件系统管理器
- 检查是否有人修补或钩挂了 MS-DOS
- 执行请求的操作
- 更新 MS-DOS 内部的状态变量
- 返回给调用者
- 程序得到结果
复制代码 这是天堂。32 位文件系统管理器能够完成所有工作,而无需处理那些做奇怪事情的烦人驱动程序。请注意更新 MS-DOS 内部状态变量的额外步骤。尽管我们在引导过程中从 MS-DOS 中提取了状态变量,但我们保持这些状态变量同步,因为驱动程序和程序经常“知道”这些状态变量如何工作并绕过操作系统直接访问它们。因此,文件系统管理器必须维持 MS-DOS 正在主导的假象(即使它没有),以便这些驱动程序和程序看到它们想要看到的东西。
另请注意,这些状态变量是每个 VM 的。(即,你打开的每个 MS-DOS“盒子”都有自己的状态变量副本。)毕竟,每个 MS-DOS 盒子都有自己对当前目录、文件表等内容的看法。然而,这都只是一个表演,因为真正的打开文件列表是由 32 位文件系统管理器维护的。它必须如此,因为磁盘缓存必须保持一致,并且需要全局强制执行文件共享。如果一个 MS-DOS 盒子以独占方式打开一个文件,那么在另一个 MS-DOS 盒子中运行的程序尝试打开该文件应该会因共享冲突而失败。
好了,那是简单的情况。困难的情况是如果你有一个钩挂了 int 21h 的驱动程序。我不知道这个驱动程序做什么,假设它是一个网络驱动程序,它拦截对网络驱动器的 I/O 并以某种特殊方式处理它们。我们再假设在 MS-DOS 盒子中运行着一个 TSR,它钩挂了 int 21h,以便在 int 21h 激活时在屏幕上打印 1,在 int 21h 完成时打印 2。让我们跟踪对本地设备(不是网络设备,所以网络驱动程序不执行任何操作)的调用:- 程序调用 int 21h -> 32 位文件系统管理器
- 注意到有人修补或钩挂了 MS-DOS
- 跳到钩子(即 16 位 TSR)
- 16 位 TSR(前端)
- 在屏幕上打印 1
- 调用上一个处理程序(即 16 位网络驱动程序)
- 16 位网络驱动程序(前端)
- 决定这不是网络 I/O 请求 调用上一个处理程序(即 16 位 IFSMGR 钩子)
- 16 位 IFSMGR 钩子
- 告诉 32 位文件系统管理器
- 是时候“制作甜甜圈”了
- 32 位文件系统管理器
- 重新获得控制权
- 执行请求的操作
- 更新 MS-DOS 内部的状态变量
- 返回给调用者
- 16 位网络驱动程序(后端)
- 返回给调用者
- 16 位 TSR(后端)
- 在屏幕上打印 2
- 返回给调用者
- 程序得到结果
复制代码 请注意,所有工作仍然由 32 位文件系统管理器完成。只是调用通过所有 16 位的东西路由,以维持 16 位 MS-DOS 仍在主导的假象。唯一真正运行的 16 位代码(红色部分)是 TSR 和网络驱动程序安装的代码,加上 16 位 IFSMGR 钩子中的一小部分粘合代码。请注意,没有运行任何 16 位 MS-DOS 代码。32 位文件管理器接管了 MS-DOS。
当 I/O 子系统从 16 位设备驱动程序手中接管你的硬盘控制权时,也发生了一系列类似的“接管但如果有人做奇怪的事情就让其发生”的舞蹈。如果它识别出这些驱动程序,它就会“吸干它们的大脑”并接管所有操作,就像 32 位文件系统管理器从 16 位 MS-DOS 接管操作一样。另一方面,如果驱动程序不是 I/O 子系统识别的驱动程序,它就会让该驱动程序负责驱动器。如果发生这种情况,据说你正在通过“实模式映射器”,因为“实模式”是 CPU 未运行保护模式时的名称;换句话说,映射器让 16 位驱动程序完成工作。
现在,如果你不幸使用了实模式映射器,你可能会注意到该驱动器的系统性能相当糟糕。那是因为你使用的是老旧的笨重单线程 16 位驱动程序,而不是更快、支持多线程的 32 位驱动程序。(当 16 位驱动程序运行时,没有其他 I/O 可以发生,因为 16 位驱动程序不是为多线程设计的。)
实模式映射器的这种糟糕表现实际上以一种反向的方式派上了用场,因为它早期表明你的计算机感染了 MS-DOS 病毒。毕竟,MS-DOS 病毒做的正是 TSR 和驱动程序所做的事情:它们钩挂中断向量并接管你的硬盘控制权。从 I/O 子系统的角度来看,它们看起来就像一个 16 位硬盘设备驱动程序!当人们抱怨“Windows 突然运行得很慢”时,我们会让他们查看控制面板中的系统性能页面,看看它是否显示“某些驱动器正在使用 MS-DOS 兼容性”。如果是这样,那么就意味着实模式映射器正在负责,如果你没有更换硬件,那很可能意味着病毒。
现在,MS-DOS 的某些部分与文件 I/O 无关。例如,有用于分配内存、将包含潜在通配符的字符串解析为 FCB 格式等功能。这些功能仍然由 MS-DOS 处理,因为它们只是“辅助库”类型的功能,除了能够说你做到了之外,用 32 位代码重新实现它们没有任何好处。旧的 16 位代码运行良好,如果你让它完成工作,你就能保持与那些修补 MS-DOS 以改变这些功能行为的程序的兼容性。
Welcome, Slashdot readers. Remember, this Web site is for entertainment purposes only.
Sean wants to know what the role of MS-DOS was in Windows 95. I may regret answering this question since it’s clear Slashdot bait. (Even if Sean didn’t intend it that way, that’s what it’s going to turn into.)
Here goes. Remember, what I write here may not be 100% true, but it is “true enough.” (In other words, it gets the point across without getting bogged down in nitpicky details.)
MS-DOS served two purposes in Windows 95.
- It served as the boot loader.
- It acted as the 16-bit legacy device driver layerf.
When Windows 95 started up, a customized version of MS-DOS was loaded, and it’s that customized version that processed your CONFIG.SYS file, launched COMMAND.COM, which ran your AUTOEXEC.BAT and which eventually ran WIN.COM, which began the process of booting up the VMM, or the 32-bit virtual machine manager.
The customized version of MS-DOS was fully functional as far as the phrase “fully functional” can be applied to MS-DOS in the first place. It had to be, since it was all that was running when you ran Windows 95 in “single MS-DOS application mode.”
The WIN.COM program started booting what most people think of as “Windows” proper. It used the copy of MS-DOS to load the virtual machine manager, read the SYSTEM.INI file, load the virtual device drivers, and then it turned off any running copy of EMM386 and switched into protected mode. It’s protected mode that is what most people think of as “the real Windows.”
Once in protected mode, the virtual device drivers did their magic. Among other things those drivers did was “suck the brains out of MS-DOS,” transfer all that state to the 32-bit file system manager, and then shut off MS-DOS. All future file system operations would get routed to the 32-bit file system manager. If a program issued an int 21h, the 32-bit file system manager would be responsible for handling it.
And that’s where the second role of MS-DOS comes into play. For you see, MS-DOS programs and device drivers loved to mess with the operating system itself. They would replace the int 21h service vector, they would patch the operating system, they would patch the low-level disk I/O services int 25h and int 26h. They would also do crazy things to the BIOS interrupts such as int 13h, the low-level disk I/O interrupt.
When a program issued an int 21h call to access MS-DOS, the call would go first to the 32-bit file system manager, who would do some preliminary munging and then, if it detected that somebody had hooked the int 21h vector, it would jump back into the 16-bit code to let the hook run. Replacing the int 21h service vector is logically analogous to subclassing a window. You get the old vector and set your new vector. When your replacement handler is called, you do some stuff, and then call the original vector to do “whatever would normally happen.” After the original vector returned, you might do some more work before returning to the original caller.
One of the 16-bit drivers loaded by CONFIG.SYS was called IFSMGR.SYS. The job of this 16-bit driver was*to hook MS-DOS first before the other drivers and programs got a chance! This driver was in cahoots with the 32-bit file system manager, for its job was to jump from 16-bit code back into 32-bit code to let the 32-bit file system manager continue its work.
In other words, MS-DOS was just an extremely elaborate decoy. Any 16-bit drivers and programs would patch or hook what they thought was the real MS-DOS, but which was in reality just a decoy. If the 32-bit file system manager detected that somebody bought the decoy, it told the decoy to quack.
Let’s start with a system that didn’t contain any “evil” drivers or programs that patched or hooked MS-DOS.- Program calls int 21h -> 32-bit file system manager
- checks that nobody has patched or hooked MS-DOS
- performs the requested operation
- updates the state variables inside MS-DOS
- returns to caller
- Program gets result
复制代码 This was paradise. The 32-bit file system manager was able to do all the work without having to deal with pesky drivers that did bizarro things. Note the extra step of updating the state variables inside MS-DOS. Even though we extracted the state variables from MS-DOS during the boot process, we keep those state variables in sync because drivers and programs frequently “knew” how those state variables worked and bypassed the operating system and accessed them directly. Therefore, the file system manager had to maintain the charade that MS-DOS was running the show (even though it wasn’t) so that those drivers and programs saw what they wanted.
Note also that those state variables were per-VM. (I.e., each MS-DOS “box” you opened got its own copy of those state variables.) After all, each MS-DOS box had its idea of what the current directory was, what was in the file tables, that sort of thing. This was all an act, however, because the real list of open files was kept in by the 32-bit file system manager. It had to be, because disk caches had to be kept coherent, and file sharing need to be enforced globally. If one MS-DOS box opened a file for exclusive access, then an attempt by a program running in another MS-DOS box to open the file should fail with a sharing violation.
Okay, that was the easy case. The hard case is if you had a driver that hooked int 21h. I don’t know what the driver does, let’s say that it’s a network driver that intercepts I/O to network drives and handles them in some special way. Let’s suppose also that there’s some TSR running in the MS-DOS box which has hooked int 21h so it can print a 1 to the screen when the int 21h is active and a 2 when the int 21h completes. Let’s follow a call to a local device (not a network device, so the network driver doesn’t do anything):- Program calls int 21h -> 32-bit file system manager
- notices that somebody has patched or hooked MS-DOS
- jumps to the hook (which is the 16-bit TSR)
- 16-bit TSR (front end)
- prints a 1 to the screen
- calls previous handler (which is the 16-bit network driver)
- 16-bit network driver (front end)
- decides that this isn’t a network I/O request calls previous handler (which is the 16-bit IFSMGR hook)
- 16-bit IFSMGR hook
- tells 32-bit file system manager
- that it’s time to make the donuts
- 32-bit file system manager
- regains control
- performs the requested operation
- updates the state variables inside MS-DOS
- returns to caller
- 16-bit network driver (back end)
- returns to caller
- 16-bit TSR (back end)
- prints a 2 to the screen
- returns to caller
- Program gets result
复制代码 Notice that all the work is still being done by the 32-bit file system manager. It’s just that the call gets routed through all the 16-bit stuff to maintain the charade that 16-bit MS-DOS is still running the show. The only 16-bit code that actually ran (in red) is the stuff that the TSR and network driver installed, plus a tiny bit of glue in the 16-bit IFSMGR hook. Notice that no 16-bit MS-DOS code ran. The 32-bit file manager took over for MS-DOS.
A similar sort of “take over but let the crazy stuff happen if somebody is doing crazy stuff” dance took place when the I/O subsystem took over control of your hard drive from 16-bit device drivers. If it recognized the drivers, it would “suck their brains out” and take over all the operations, in the same way that the 32-bit file system manager took over operations from 16-bit MS-DOS. On the other hand, if the driver wasn’t one that the I/O subsystem recognized, it let the driver be the one in charge of the drive. If this happened, it was said that you were going through the “real-mode mapper” since “real mode” was name for the CPU mode when protected mode was not running; in other words, the mapper was letting the 16-bit drivers do the work.
Now, if you were unlucky enough to be using the real-mode mapper, you probably noticed that system performance to that drive was pretty awful. That’s because you were using the old clunky single-threaded 16-bit drivers instead of the faster, multithread-enabled 32-bit drivers. (When a 16-bit driver was running, no other I/O could happen because 16-bit drivers were not designed for multi-threading.)
This awfulness of the real-mode mapper actually came in handy in a backwards way, because it was an early indication that your computer got infected with an MS-DOS virus. After all, MS-DOS viruses did what TSRs and drivers did: They hooked interrupt vectors and took over control of your hard drive. From the I/O subsystem’s point of view, they looked just like a 16-bit hard disk device driver! When people complained, “Windows suddenly started running really slow,” we asked them to look at the system performance page in the control panel and see if it says that “Some drives are using MS-DOS compatibility.” If so, then it meant that the real-mode mapper was in charge, and if you didn’t change hardware, it probably means a virus.
Now, there are parts of MS-DOS that are unrelated to file I/O. For example, there are functions for allocating memory, parsing a string containing potential wildcards into FCB format, that sort of thing. Those functions were still handled by MS-DOS since they were just “helper library” type functions and there was no benefit to reimplementing them in 32-bit code aside from just being able to say that you did it. The old 16-bit code worked just fine, and if you let it do the work, you preserved compatibility with programs that patched MS-DOS in order to alter the behavior of those functions.
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |