Linux 0.11启动探秘:setup.s中BIOS中断调用的数据采集艺术
当计算机按下电源键的那一刻,一段精妙的硬件探测交响曲便开始演奏。在Linux 0.11的setup.s阶段,BIOS中断调用如同一位经验丰富的侦察兵,悄然收集着系统硬件的关键情报。这些看似简单的int指令背后,隐藏着操作系统与硬件初次对话的完整逻辑。
1. BIOS中断:早期硬件探测的桥梁
在保护模式尚未建立的实模式下,BIOS中断是操作系统获取硬件信息的唯一窗口。setup.s通过精心设计的寄存器配置,向BIOS发出精确的数据请求:
mov ah,#0x03 ; 功能号:读取光标位置 xor bh,bh ; 页号清零 int 0x10 ; 调用视频服务中断 mov [0],dx ; 保存到0x90000偏移处这段经典代码揭示了三个关键技术细节:
- 功能选择艺术:AH寄存器存储的0x03对应BIOS视频服务的"读取光标位置"子功能
- 参数清理技巧:XOR指令确保BH寄存器(显示页码)为0,避免脏数据干扰
- 数据存储策略:返回的光标坐标(DX寄存器)被保存在0x90000起始的内存区域
实模式下的内存访问需要结合段基址计算,DS寄存器在此被预设为0x9000,因此[0]实际对应物理地址0x90000
2. 硬件信息采集清单
setup.s通过不同的BIOS中断号,系统性地收集了六类关键硬件参数:
| 内存地址偏移 | 数据类型 | 采集方式 | 后续用途 |
|---|---|---|---|
| 0x0000 | 光标位置 | int 0x10 (AH=0x03) | 控制台初始化 |
| 0x0002 | 扩展内存大小(KB) | int 0x15 (AH=0x88) | 内存管理初始化 |
| 0x0004 | 显卡参数 | int 0x10 (AH=0x0F) | 显示模式设置 |
| 0x0008 | EGA/VGA配置 | int 0x10 (AH=0x12) | 高级图形功能检测 |
| 0x0080 | 第一硬盘参数表 | 从中断向量0x41处拷贝 | 块设备驱动初始化 |
| 0x0090 | 第二硬盘参数表 | 从中断向量0x46处拷贝 | 多硬盘支持 |
特别值得注意的是硬盘参数的获取方式——并非直接调用中断,而是从中断向量表提取参数表指针:
mov ax,#0x0000 mov ds,ax lds si,[4*0x41] ; 从0x0000:0x0104加载hd0参数表指针 mov di,#0x0080 mov cx,#0x10 rep movsb ; 复制16字节参数表3. 内存布局的终极调整
完成硬件探测后,setup.s执行了启动过程中最关键的内存搬运操作:
- 关闭中断响应:
cli指令确保内存搬运过程不被中断打断 - 分段搬运机制:通过ES/DS寄存器组合,以64KB为单位移动内存
- 搬运范围:将0x10000-0x8FFFF的内容复制到0x00000-0x7FFFF
do_move: mov es,ax ; 目标段地址 add ax,#0x1000 ; 每次递增64KB cmp ax,#0x9000 jz end_move mov ds,ax ; 源段地址 mov cx,#0x8000 ; 32K次字移动(64KB) rep movsw jmp do_move这段代码的独特之处在于:
- 使用
cld明确方向标志,确保movsw正向移动 - 通过
rep movsw实现高效批量传输(每次2字节) - 循环控制采用段地址比较而非计数器,更符合内存布局特性
4. 数据采集背后的设计哲学
Linux 0.11的硬件探测过程体现了三个核心设计原则:
最小化依赖原则
- 仅依赖BIOS提供的最基础服务
- 尽早获取独立运行所需的所有硬件参数
- 避免后续内核初始化时反复查询硬件
数据集中管理
- 所有硬件参数统一存储在0x90000-0x901FF区域
- 采用固定偏移量的结构化存储
- 便于内核初始化时一次性读取
防御性编程
- 关键操作前禁用中断(
cli) - 寄存器状态显式清理(
xor bh,bh) - 数据传输使用明确的方向标志(
cld)
在早期的IBM PC兼容机上,这些BIOS调用实际上构成了硬件抽象层的雏形。通过分析setup.s的代码,我们可以发现Linus Torvalds对硬件兼容性的精妙处理——既充分利用BIOS提供的标准化接口,又为后续自定义驱动留出扩展空间。