我参加过一些基本的操作系统课程、视频系列等,并且对 OS 驱动程序和 BIOS 驱动程序有疑问。基本操作系统如何知道每个硬件的内存地址?操作系统如何在任何计算机上开箱即用。是否存在每个人都知道的标准设备内存布局?或者操作系统会将其 IVT 重定向到 BIOS 设备驱动程序?请为我提供一些关于这个主题的阅读材料。
答案1
基本操作系统如何知道每个硬件的内存地址?操作系统如何在任何计算机上开箱即用。
CPU 只知道要执行的第一个地址。BIOS/固件应该“回答”这个地址以便 CPU 进行引导。
对于内存和 I/O(我希望您知道 x86 中有两个空间:内存和 I/O,对吗?),有很多标准。
第一台个人电脑时代
内存中有一个半官方区域,称为 BIOS 数据区。它包含有关 COM 和 LPT 端口数量、软盘驱动器控制器及其基本 I/O 地址等信息。操作系统还使用 BIOS 调用(记录中断)来访问硬件。主板供应商硬编码指向 BIOS 的地址。一些设备有官方记录的 I/O 地址。
ISA 之类的扩展卡除了扩展卡 BIOS 之外没有任何可检测的工具:系统 BIOS 扫描内存以查找特殊模式,从而找到扩展卡 BIOS 并运行它。卡 BIOS 可能会将自身安装为中断向量,以“隐藏”BIOS 功能,从而启用网络启动等。
在很多情况下,用户有责任使用跳线配置卡并向软件提供信息(例如BLASTER
声卡参数的环境变量等)。
PnP 时代
PnP 是一组关于硬件检测的规范。有 ISA PNP、COM PORT PNP、LPT PNP 等。规范描述了软件应该做什么来检查哪个设备已连接以及设备应该如何操作。一些总线(如 PCI)内置了 PNP 功能。软件可以枚举 PCI 上的所有卡并询问它们所需的资源、它们的供应商和类别(以查找驱动程序)等,然后对它们进行配置。枚举也可用于 USB。
在这种情况下,“软件”可能是 PNPBIOS 或启用 PNP 的操作系统。因此,BIOS 使用该规范来查找启动设备和 PCI 主机桥(PCI 总线的“根”)并将此信息存储在内存中的特殊表中(根据 PNPBIOS 规范),操作系统读取它们并使用 PCI 和 USB 功能来枚举和启用设备(PCI 和 USB 协议已记录)。
ACPI 时代
ACPI 表由主板供应商填写并存储在固件中(现代固件是不是”BIOS,但可以模拟它)。
称为 DSDT 的特殊表描述任何系统设备,包括特殊的笔记本电脑按钮、笔记本电脑电池、风扇、PCI-Express 根复合体等。
设备用一种叫做 AML 的语言来描述,操作系统应该有它的解释器。DSDT 可能描述内存、IO 和“方法”(也用 AML 编写)来执行一些操作,例如“更改亮度”。
ACPI 是一项巨大的规范。操作系统使用 DSDT 来填充其内部“设备树”,一旦获得对“PCI-Express 根复合体”或根 USB 的访问权限,它就会使用 PCI-Express 和 USB 协议进行进一步的枚举和配置:卡可能会报告它支持内存范围 A 和 B,而操作系统会将其配置为使用“B”。
答案2
大多数操作系统由各种组件组成,例如内存管理器、输入输出、文件系统管理器等。几年前,单片操作系统的所有内容都是一起构建的。大多数现代操作系统都有某种方式可以动态更改各种组件。一些操作系统,即微内核,只具有操作系统的基本管理功能,而大多数附加组件(例如文件系统)都是附加部件。
现代操作系统也由一系列层组成,类似于网络堆栈的 OSI 模型(参见https://en.wikipedia.org/wiki/OSI_model) 以尽可能地提供与运行它们的实际硬件的独立性。
因此,操作系统基本上是一个抽象的机器,其中插入了具体的硬件特定模块。有一些接口规范,这些规范往往是抽象的机器描述,描述了硬件特定模块要向操作系统提供的控制、数据和服务。
因此,特定设备驱动程序堆栈的安装程序知道其特定、具体的硬件需求和设备接口,但操作系统不知道这些特定的硬件需求。操作系统将所有复杂的设备特定内容委托给设备驱动程序堆栈。
我使用“堆栈”一词是因为执行实际设备通信的功能通常由一系列层组成。您可以在大多数设备上使用 Windows 设备管理器查看这一点,其中显示了一组用于特定设备的驱动程序文件。
因此,各种软件组件实际上可能来自不同的供应商。
因此,如果操作系统想要了解有关硬件的详细信息,它会向设备驱动程序询问这些详细信息。
操作系统可以在各种硬件平台上开箱即用,因为构成平台的特定硬件的供应商提供了操作系统在具体特定硬件上运行所需的驱动程序堆栈。
不同的操作系统对于操作系统设计使用的设备驱动程序具有不同的接口规范。因此,对于 Linux,您必须具有提供 Linux 驱动程序接口的 Linux 操作系统兼容驱动程序。对于 Windows,您必须具有 Windows 接口驱动程序。
由于存在驱动程序堆栈,只要使用相同的硬件,堆栈中的某些软件组件在不同的操作系统之间可能是相同的。直接与硬件设备对话的层的部分可能相同,但堆栈的上层(必须与实际操作系统接口的部分)将有所不同,因为不同的操作系统具有不同的设备驱动程序接口。
关于操作系统的书籍有很多,而且针对各种操作系统的开源项目也有很多。
看看这个讨论https://www.quora.com/What-is-the-best-book-on-operating-systems
有许多免费的在线书籍,例如http://pages.cs.wisc.edu/~remzi/OSTEP/
看看这个关于开源操作系统的 Github 页面https://github.com/showcases/open-source-operating-systems
答案3
在现代 PC 上,每个硬件在被询问时都会报告一些有关自身的基本信息。例如,许多外围设备连接到PCI 总线当操作系统想知道哪些外设连接到 PCI 总线时,它会在总线上发送一条指令,要求每个外设发送描述。这称为枚举总线上的设备。此描述使用数字代码来识别每个设备模型,称为PCI 编号当操作系统发现存在具有特定 PCI ID 的设备时,它会尝试加载该 PCI ID 的驱动程序;如果操作系统没有驱动程序,它会尝试下载一个,或者向用户报告存在未知设备。
例如,在 Linux 上,您可以运行命令lspci
来列出 PCI 设备。它有各种选项来显示不同类型的信息,如果您感兴趣,可以尝试一下。我在这个答案。这只是一个例子;其他 PC 操作系统也有机制可以做同样的事情,但这种机制可能完全不同。
操作系统如何知道有 PCI 总线,以及如何访问总线?我认为,如果你为 PC 架构构建它,那么这是硬编码的。请注意,“PC 架构”比“x86 CPU”更具体 — 你可以在 x86 CPU 周围放置一组不同的总线,但这样它就不能称为(现代)PC。
不同的机器架构可能有或没有方法来枚举现有的驱动程序。例如,直到 20 世纪 90 年代中期,PC 都没有这样的方法。在 PCI 总线出现之前,ISA 总线在 ISA 总线上,如果您想知道某个设备是否存在于某个地址,您可以向其发送命令。如果您得到了您能理解的答案,那就太好了。如果命令锁定了计算机,或者由于存在完全不同的外围设备而导致意外影响,那就糟糕了。在 1908 年代的 PC 上,操作系统确实会向 BIOS 询问已配置的设备(但 BIOS 并未列出所有设备,只列出了 BIOS 知道的设备类型),并且安装扩展卡的用户需要在 BIOS 或操作系统配置中提供其配置详细信息。BIOS 包含一些用于键盘和屏幕的基本驱动程序,DOS 等操作系统会调用这些驱动程序;其他操作系统(或应用程序)可能会直接访问硬件(尤其是显示器,因为 BIOS 驱动程序速度慢且功能有限)。
即使在今天,大多数嵌入式系统也没有办法枚举内置外围设备。许多设备(尤其是基于 ARM 的设备,但不仅仅是这些设备)在称为设备树. 该数据结构存储在 ROM 或闪存中,并且引导加载程序(相当于 BIOS)将数据传送给操作系统。这样,操作系统就不必为特定的设备集构建,它会在启动时读取这些信息。