BIOS 实现提供可由操作系统和应用程序调用的中断,以使用 IBM PC 兼容^[a]^ 计算机上固件的功能。传统上,BIOS 调用主要由 DOS 程序和其他一些软件(如引导加载程序)使用(包括历史上直接引导并在没有操作系统的情况下运行的相对简单的应用程序软件,尤其是游戏软件)。BIOS 在 x86 CPU 的实地址模式(实模式)下运行,因此调用 BIOS 的程序要么也必须在实模式下运行,要么必须在调用 BIOS 然后再次切换回来之前从保护模式切换到实模式。因此,在保护模式或长模式下使用 CPU 的现代操作系统通常不使用 BIOS 中断调用来支持系统功能,尽管它们使用 BIOS 中断调用在启动期间探测和初始化硬件。^[1]^ 实模式有 1MB 内存限制,现代引导加载程序(例如 GRUB2、Windows 引导管理器)使用虚幻模式或保护模式(并在虚拟 8086 模式下执行 BIOS 中断调用,但仅用于操作系统引导)访问高达 4GB 的内存。^[2]^

在所有计算机中,软件指令从打开电源的那一刻起就控制物理硬件(屏幕、磁盘、键盘等)。在 PC 中,预装在主板 ROM 中的 BIOS 在 CPU 重置后立即进行控制,包括在上电期间、按下硬件重置按钮或关键软件故障(三重故障)导致主板电路自动触发硬件重置时。BIOS 测试硬件并初始化其状态;查找、加载和运行引导程序(通常是操作系统引导加载程序和历史 ROM BASIC);并为机器上运行的软件提供基本的硬件控制,该软件通常是操作系统(带有应用程序),但可能是直接启动的单个软件应用程序。

就IBM而言,他们在对早期IBM PC型号(PS / 2之前)进行编程时,提供了充分利用其BIOS或直接利用硬件并完全避免使用BIOS所需的所有信息。从一开始,程序员就可以选择是否使用BIOS,基于每个硬件外设。IBM 确实强烈鼓励编写仅通过 BIOS INT 调用(和 DOS 服务调用)访问硬件的“行为良好”程序,以支持软件与具有不同外围硬件的当前和未来 PC 型号的兼容性,但 IBM 明白,对于某些软件开发人员和硬件客户来说,用户软件直接控制硬件的能力是必需的。部分原因是 BIOS 服务未公开所有硬件特性和功能的重要子集。对于两个示例(在众多示例中),MDA 和 CGA 适配器能够进行硬件滚动,PC 串行适配器能够进行中断驱动的数据传输,但 IBM BIOS 不支持这些有用的技术特性。

今天,新PC中的BIOS仍然支持IBM为IBM AT(1984年推出)定义的大多数(如果不是全部)BIOS中断函数调用,以及更多较新的调用,以及对其他各种组织和协作行业组织颁布的一些原始功能的扩展(例如扩展参数范围)。这与类似程度的硬件兼容性相结合,意味着大多数为 IBM AT 编写的程序今天仍然可以在新 PC 上正常运行,前提是更快的执行速度是可以接受的(通常适用于除使用基于 CPU 的计时的游戏之外的所有游戏)。尽管通过BIOS中断访问的服务存在相当大的局限性,但它们已被证明对技术变革非常有用和持久。

BIOS调用的目的

BIOS 中断调用执行程序请求的硬件控制或 I/O 功能,将系统信息返回到程序,或同时执行这两项操作。BIOS 调用目的的一个关键要素是抽象 - BIOS 调用执行通常定义的功能,并且如何在系统的特定硬件上执行这些功能的特定细节封装在 BIOS 中并从程序中隐藏。因此,例如,想要从硬盘读取的程序不需要知道硬盘是 ATA、SCSI 还是 SATA 驱动器(或者在早期,是 ESDI 驱动器,还是带有希捷 ST-506 控制器的 MFM 或 RLL 驱动器,也许是几个西部数据之一)。控制器类型,或具有其他品牌的不同专有控制器)。该程序只需要识别它希望访问的驱动器的 BIOS 定义的编号以及它需要读取或写入的扇区的地址,BIOS 将负责将此常规请求转换为通过连接到该驱动器的特定磁盘控制器硬件完成任务所需的特定基本操作序列。该程序无需知道如何在低级别上控制可能需要访问的每种类型的硬盘(或显示适配器,或端口接口或实时时钟外围设备)。这既使操作系统和应用程序的编程更容易,又使程序更小,减少了程序代码的重复,因为BIOS中包含的功能不需要包含在需要它的每个程序中;对 BIOS 的相对较短的调用包含在程序中。(在不使用 BIOS 的操作系统中,操作系统本身提供的服务调用通常实现相同的功能和目的。

BIOS 还使计算机硬件设计人员(在某种程度上,程序是为专门使用 BIOS)解放出来,使其在设计新系统时不受限制,以保持与旧系统的确切硬件兼容性,以保持与现有软件的兼容性。例如,IBM PCjr 上的键盘硬件与早期 IBM PC 型号上的键盘硬件的工作方式大不相同,但对于仅通过 BIOS 使用键盘的程序,这种差异几乎是看不见的。(作为这个问题另一面的一个很好的例子,在引入 PCjr 时使用的 PC 程序中有很大一部分并没有专门通过 BIOS 使用键盘,因此 IBM 还在 PCjr 中包含硬件功能,以模拟原始 IBM PC 和 IBM PC XT 键盘硬件的工作方式。硬件仿真并不精确,因此并非所有尝试直接使用键盘硬件的程序都可以在 PCjr 上正常工作,但所有仅使用 BIOS 键盘服务的程序都可以。

除了提供对硬件设施的访问之外,BIOS 还提供了在 BIOS 软件中实现的附加功能。例如,BIOS 为多达八个文本显示页面保持单独的光标位置,并提供类似 TTY 的输出,具有自动换行和基本控制字符(如回车和换行)的解释,而 CGA 兼容的文本显示硬件只有一个全局显示光标,无法自动前进光标, 使用光标位置寻址显示内存(以便确定将更改或检查哪个字符单元格),或解释控制字符。对于另一个示例,BIOS 键盘界面解释许多击键和组合键,以跟踪各种移位状态(左和右 ShiftCtrlAlt),在按下 Shift+PrtScrn 时调用打印屏幕服务,在按 Ctrl+Alt+Del 时重新启动系统按下以跟踪锁定状态(大写锁定、数字锁定和滚动锁定),并在 AT 类机器中控制键盘上相应的锁定状态指示灯,并对键盘执行其他类似的解释和管理功能。相比之下,标准PC和PC-AT键盘硬件的常规功能仅限于向系统报告按下或释放单个键的每个基元事件(即从“释放”状态过渡到“按下”状态,反之亦然),对键盘单元执行命令复位和自检, 对于 AT 类键盘,从主机系统执行命令以设置锁定状态指示灯 (LED) 的绝对状态。

调用 BIOS:BIOS 软件中断

操作系统和其他软件与 BIOS 软件通信,以便通过软件中断控制已安装的硬件。软件中断是中断的一般概念的特定变体。中断是 CPU 可以 指示停止执行主线程序并立即执行称为中断服务例程 (ISR) 的特殊程序。ISR 完成后,CPU 将继续执行主程序。在 x86 CPU 上,当发生中断时,通过在内存中的 ISR 起始点地址表(称为“中断向量”)中查找要调用的 ISR:中断向量表 (IVT)。中断由其类型号(从 0 到 255)调用,类型号用作中断向量表的索引,并在表中的该索引处找到将为响应中断而运行的 ISR 的地址。软件中断只是由软件命令触发的中断;因此,软件中断的功能类似于子例程,主要区别在于进行软件中断调用的程序不需要知道 ISR 的地址,只需要知道它的中断号。这在系统配置的模块化、兼容性和灵活性方面具有优势。

可以将 BIOS 中断调用视为在 BIOS 和 BIOS 客户端软件(如操作系统)之间传递消息的机制。消息从 BIOS 请求数据或操作,并将请求的数据、状态信息和/或所请求操作的乘积返回给调用方。消息被分成几个类别,每个类别都有自己的中断编号,大多数类别包含子类别,称为“功能”,由“功能编号”标识。BIOS 客户端将大部分信息传递到 CPU 寄存器中的 BIOS,并以相同的方式接收大部分信息,但太大而无法放入寄存器的数据(例如控制参数表或磁盘传输的磁盘扇区数据)是通过在内存中分配缓冲区(即一些空间)并在寄存器中传递缓冲区地址来传递的。(有时,内存中数据项的多个地址可能会在内存中的数据结构中传递,该结构的地址在寄存器中传递到 BIOS。中断号被指定为软件中断指令的参数(在英特尔汇编语言中,“INT”指令),函数号在AH寄存器中指定;也就是说,调用方将 AH 寄存器设置为所需函数的编号。通常,对应于每个中断号的 BIOS 服务彼此独立运行,但一个中断服务中的功能由同一 BIOS 程序处理,并且不是独立的。(最后一点与重入有关。

如果不成功,BIOS 软件通常会返回给调用方错误代码,如果成功,则返回状态代码和/或请求的数据。数据本身可以小到一位,也可以大到整个原始磁盘扇区的 65,536 字节(一个实模式内存段可容纳的最大值)。多年来,许多不同的公司实体多次扩展和增强 BIOS,不幸的是,这种演变的结果是,并非所有可以调用的 BIOS 功能都使用一致的约定来格式化和传达数据或报告结果。某些 BIOS 函数报告详细的状态信息,而其他函数甚至可能不报告成功或失败,而只是静默返回,让调用方假设成功(或以其他方式测试结果)。有时,还可能难以确定某台计算机上的 BIOS 是否支持某个 BIOS 功能调用,或者该计算机上调用参数的限制是什么。(对于某些无效的函数号,或具有无效键参数值的有效函数号(特别是对于早期的 IBM BIOS 版本),BIOS 可能不执行任何操作并且返回时没有错误代码;那么调用方的责任是避免这种情况,要么通过不进行此类调用来避免这种情况,要么积极测试调用的预期效果,而不是假设调用是有效的。由于 BIOS 在其历史中在许多步骤中都得到了广泛的发展,因此在某个特定供应商的一个 BIOS 版本中有效的功能可能在同一供应商的早期或不同的 BIOS 版本中无效,也可能在来自不同供应商的 BIOS 版本(任何相对年龄)中无效。

由于 BIOS 中断调用使用基于 CPU 寄存器的参数传递,因此调用面向从汇编语言进行,不能直接从大多数高级语言 (HLL) 进行。但是,高级语言可以提供包装器例程库,这些例程将参数从高级语言使用的形式(通常基于堆栈)转换为 BIOS 所需的基于寄存器的表单,然后在 BIOS 返回后返回 HLL 调用约定。在 C 的某些变体中,可以使用 C 模块中的内联汇编语言进行 BIOS 调用。(对内联汇编语言的支持不是 ANSI C 标准的一部分,而是一种语言扩展;因此,使用内联汇编语言的 C 模块不如纯 ANSI 标准 C 模块可移植。

调用中断

调用中断可以使用 INT x86 汇编语言指令来完成。例如,要使用 BIOS 中断0x10将字符打印到屏幕上,可以执行以下 x86 汇编语言指令:



 mov ah, 0x0e    ; function number = 0Eh : Display Character mov al, '!'     ; AL = code of character to display int 0x10        ; call INT 10h, BIOS video service


中断表

主条目:中断向量表

常见 BIOS 中断类的列表可在下面找到。请注意,某些 BIOS(尤其是旧 BIOS)没有实现所有这些中断类。

BIOS 还使用一些中断将硬件事件中断中继到选择接收它们或路由消息以供自己使用的程序。下表仅包括那些旨在由程序(使用“INT”汇编语言软件中断指令)调用以请求服务或信息的 BIOS 中断。

| 中断向量 | 描述 |

| ——– | —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- |

| 05h | 按下 Shift-Print 屏幕时以及指令检测到绑定故障时执行。BOUND |

| 08h | 这是实时时钟中断。它每秒发射 18.2 次。BIOS 在此中断期间递增时间计数器。 |

| 09h | 这是键盘中断。这通常是在按下键盘上的键时触发的。 |

| 10h | 视频服务AH描述00h设置视频模式01h设置光标形状02h设置光标位置03h获取光标位置和形状04h获取轻型笔位置05h设置显示页面06h清除/向上滚动屏幕07h向下清除/滚动屏幕08h在光标处读取字符和属性09h在光标处写入字符和属性0Ah在光标处写入字符0Bh设置边框颜色0Ch写入图形像素0Dh读取图形像素0Eh在 TTY 模式下写入字符0Fh获取视频模式10h设置调色板寄存器(EGA、VGA、SVGA)11h字符生成器(EGA,VGA,SVGA)12h备用选择功能(EGA、VGA、SVGA)13h写入字符串1Ah获取或设置显示组合代码(VGA、SVGA)1Bh获取功能信息(VGA、SVGA)1Ch保存或恢复视频状态(VGA、SVGA)4FhVESA BIOS 扩展函数 (SVGA) |

| 11h | 退货设备清单 |

| 12h | 返回常规内存大小 |

| 13h | 低级磁盘服务AH描述00h重置磁盘驱动器01h检查驱动器状态02h读取行业03h写入扇区04h验证扇区05h格式轨道08h获取驱动器参数09h初始化固定驱动器参数0Ch查找到指定轨道0Dh重置固定磁盘控制器15h获取驱动器类型16h获取软驱介质更改状态17h设置磁盘类型18h设置软驱介质类型41h扩展磁盘驱动器 (EDD) 安装检查42h扩展读取扇区43h扩展写入扇区44h扩展验证扇区45h锁定/解锁驱动器46h弹出介质47h扩展寻道48h扩展获取驱动器参数49h扩展获取媒体更改状态4Eh扩展集硬件配置 |

| 14h | Serial port servicesAHDescription00hSerial Port Initialization01hTransmit Character02hReceive Character03hStatus |

| 15h | 杂项系统服务AHAL描述00h打开盒式驱动电机(仅限 IBM PC/PCjr)01h关闭盒式驱动电机(仅限 IBM PC/PCjr)02h从盒式磁带读取数据块(仅限 IBM PC/PCjr)03h将数据块写入磁带(仅限 IBM PC/PCjr)4Fh键盘截距83h事件等待84h阅读操纵杆(从 1986 年开始的 BIOS)85h系统键标注86h等87h移动块88h获取扩展内存大小89h切换到保护模式C0h获取系统参数C1h获取扩展的 BIOS 数据区域段C2h定点设备功能C3h看门狗定时器功能 - 仅限 PS/2 系统C4h可编程选项选择 - 仅限 MCA 总线 PS/2 系统D8h艾萨系统功能 - 仅限 EISA 总线系统E8h01h获取扩展内存大小(自 1994 年以来的较新函数)。给出内存大小大于 64 Mb 的结果。E8h20h查询系统地址映射。从 E820 返回的信息取代从旧接口返回的信息。AX=E801hAH=88h |

| 16h | 键盘服务AH描述00h读取字符01h读取输入状态02h读取键盘移位状态05h将击键存储在键盘缓冲区中10h读取字符扩展11h读取输入状态扩展12h读取键盘移位状态扩展 |

| 17h | 打印机服务AH描述00h将字符打印到打印机01h初始化打印机02h检查打印机状态 |

| 18h | 执行盒式磁带 BASIC:在早期 PS/2 行之前的 IBM 机器上,此中断将启动 ROM 盒式磁带 BASIC。克隆没有此功能,如果执行 INT 18h,不同的计算机/BIOS 将执行各种不同的操作,最常见的是一条错误消息,指出不存在可引导磁盘。现代计算机将尝试通过此中断从网络引导。在现代机器上,BIOS 会将此中断视为来自引导加载程序的信号,表明它未能完成其任务。然后,BIOS 可以采取适当的后续步骤。^[3]^ |

| 19h | 开机自检后,BIOS 使用此中断来加载操作系统。程序可以调用此中断来重新启动计算机(但必须确保硬件中断或 DMA 操作在 BIOS 或启动过程重新初始化系统期间不会导致系统挂起或崩溃)。 |

| 1Ah | 实时时钟服务AH描述00h读取 RTC01h设置目录02h读取 RTC 时间03h设置实时时钟时间04h读取 RTC 日期05h设置 RTC 日期06h设置实时温度报警07h重置 RTC 报警 |

| 1Ah | PCI服务 - 由支持 PCI 2.0 或更高版本的 BIOS 实施AX描述B101hPCI 安装检查B102h查找 PCI 设备B103h查找 PCI 类代码B106hPCI 总线特定操作B108h读取配置字节B109h读取配置字B10Ah读取配置字B10Bh写入配置字节B10Ch编写配置字B10Dh写入配置字B10Eh获取 IRQ 常规信息B10Fh设置 PCI IRQ |

| 1Bh | Ctrl-Break 处理程序 - 在按下 Ctrl-Break 时调用 INT 09 |

| 1Ch | 计时器时钟周期处理程序 - 由 INT 08 |

| 1Dh | 不被召唤;只是一个指向 VPT(视频参数表)的指针,其中包含有关视频模式的数据 |

| 1Eh | 不被召唤;只是一个指向 DPT(软盘参数表)的指针,其中包含有关软盘驱动器的各种信息 |

| 1Fh | 不被召唤;只是一个指向 VGCT(视频图形字符表)的指针,其中包含 ASCII 字符的数据 80hFFh |

| 41h | 地址指针:FDPT = 固定磁盘参数表(第一个硬盘驱动器) |

| 46h | 地址指针:FDPT = 固定磁盘参数表(第二个硬盘驱动器) |

| 4Ah | 由 RTC 调用报警 |

INT 18h: 执行基本

INT 18h传统上跳转到存储在选项 ROM 中的盒式磁带 BASIC(由 Microsoft 提供)的实现。如果 BIOS 在启动时无法识别任何可引导磁盘卷,通常会调用此调用。

在5150年发布最初的IBM PC(IBM机器类型1981)时,ROM中的BASIC是一个关键功能。当代流行的个人电脑,如Commodore 64和Apple II系列,也在ROM中安装了Microsoft Cassette BASIC(尽管Commodore将其许可版本重命名为Commodore BASIC),因此在其目标市场的很大一部分中,IBM PC需要BASIC来竞争。与其他系统一样,IBM PC的ROM BASIC充当原始的无盘操作系统,允许用户加载,保存和运行程序,以及编写和优化它们。(最初的IBM PC也是IBM唯一一款PC型号,与上述两个竞争对手一样,包括盒式接口硬件。基本型号IBM PC只有16 KiB的RAM,没有磁盘驱动器[任何类型的],因此盒式磁带接口和ROM中的BASIC对于使基本型号可用至关重要。RAM 小于 32 KiB 的 IBM PC 无法从磁盘引导。在原始 IBM PC 中的五个 8 KiB ROM 芯片中,总计 40 KiB,四个包含 BASIC,只有一个包含 BIOS;当只安装了 16 KiB 的 RAM 时,ROM BASIC 占系统总内存的一半以上 [准确地说是 4/7]。

随着时间的流逝,BASIC不再在所有PC上提供,此中断将仅显示一条错误消息,指示未找到可启动卷(著名的“No ROM BASIC”,或更高BIOS版本中的更多解释性消息);在其他 BIOS 版本中,它会提示用户插入可引导卷并按一个键,然后在用户按下一个键后,它会循环回引导加载程序 (INT 19h) 以尝试再次引导。

Digital的Rainbow 100B曾经调用其BIOS与IBM BIOS不兼容。Turbo Pascal、Turbo C 和 Turbo C++将 INT 18 重新用于内存分配和分页。其他程序也出于自己的目的重用了这个向量。INT 18h

BIOS 挂钩

DOS

在 DOS 系统上,IO.SYS 或 IBMBIO.COM 挂钩 INT 13,用于软盘更改检测、跟踪格式化调用、更正 DMA 边界错误,以及解决 IBM ROM BIOS“01/10/84”中的问题,并在第一次调用之前使用型号代码0xFC。

绕过BIOS

许多现代操作系统(如Linux和Windows)在启动后根本不使用任何BIOS中断调用,而是选择直接与硬件接口。为此,它们依赖于作为操作系统内核本身的一部分、随操作系统一起提供或由硬件供应商提供的驱动程序。

这种做法有几个原因。最重要的是,现代操作系统在保护(或长)模式下运行处理器,而 BIOS 代码只能在实模式下执行。这意味着,如果在保护模式下运行的操作系统想要进行 BIOS 调用,则必须首先切换到实模式,然后执行调用并等待它返回,最后切换回保护模式。这将非常缓慢和低效。由于使用了 1 位分段内存寻址,因此在实模式(包括 BIOS)下运行的代码仅限于访问仅超过 16 MiB 的内存。此外,BIOS 通常不是执行任何特定任务的最快方法。事实上,即使在DOS时代,BIOS的速度限制也使得程序规避它以避免其性能限制变得很普遍,特别是对于视频图形显示和快速串行通信。

除了上述因素之外,BIOS 功能的问题还包括定义的功能范围的限制、不同计算机上支持的这些功能子集的不一致以及 BIOS 质量的差异(即一些 BIOS 是完整可靠的,而另一些则是删节和错误)。通过自己动手并避免依赖 BIOS,操作系统开发人员可以消除他们在编写和支持系统软件时面临的一些风险和复杂性。另一方面,通过这样做,这些开发人员负责为他们打算用于其操作系统的每个不同系统或外围设备提供“裸机”驱动程序软件(或诱导硬件生产商提供这些驱动程序)。

因此,很明显,在小预算下开发的紧凑型操作系统倾向于大量使用BIOS而由具有大量预算的大量软件工程师构建的大型操作系统更经常选择编写自己的驱动程序而不是使用BIOS,也就是说,即使不考虑BIOS和保护模式的兼容性问题。

参见

  • DOS 中断调用

  • 中断描述符表

  • 输入/输出基址

  • 拉尔夫·布朗的中断列表

注释

  1. **^**并非所有具有 BIOS 的计算机都与 IBM PC 兼容

参考资料

    1. “开机·Linux Inside”。0xax.gitbooks.io**。检索 **2020-11-10.

    2. ^“Grub2 引导过程”。摄于21年2016月<>日。

    3. ^* BIOS 引导规范版本 1.01 11 年 1996 月 <> 日附录 D

    4. x86 中断列表(又名 RBIL,Ralf Brown 的中断列表)

    5. 嵌入式 BIOS 用户手册

    6. 凤凰 BIOS 4.0 用户手册

    7. IBM 个人系统/2 和个人计算机 BIOS 接口技术参考,IBM,1988 年,OCLC “OCLC (identifier)”) 20737442

    8. IBM PC、Compatibles and EISA Computers的系统 BIOSPhoenix Technologies,1991 年,ISBN “ISBN (identifier)”) 0201577607

    9. AMIBIOS程序员指南美国大趋势,1993年,ISBN “ISBN (identifier)”) 0070015619

    10. The Programmer’s PC Sourcebook by Thom Hogan, Microsoft Press, 1991 ISBN “ISBN (identifier)”) 155615321X