【BIOS中断】磁盘与 INT 13H
INT 13h 是 x86 PC 架构中 BIOS 提供的磁盘服务中断,用于在实模式下对软盘、硬盘等存储设备进行底层读写操作。它是操作系统引导程序(如 MBR、bootloader)访问磁盘的唯一标准接口。
一、基本概念
(一)int 13H
- 中断号:
0x13(十进制 19) - 调用方式:
int 0x13 - 运行环境:实模式(Real Mode)
- 支持设备:软盘(Floppy)、硬盘(HDD)、早期 USB 存储(需 BIOS 支持)
- 寻址方式:
- 传统 CHS(柱面-磁头-扇区):最大 ~8.4 GB
- 扩展 LBA(逻辑块地址):通过
INT 13h Extensions(AH=42h)支持大容量磁盘
💡 BIOS 将
INT 13h的中断向量(地址)存放在内存0x0000:0x004C处。
(二)磁盘结构

(三)磁盘布局
磁盘的布局(Disk Layout)是指存储设备(如硬盘、SSD、软盘)上数据的物理或逻辑组织方式。不同层级(硬件、BIOS、操作系统)对磁盘布局的理解不同。以下是 x86 PC 启动过程中的关键结构。
1. 物理/传统布局(CHS 模型)
早期硬盘使用 CHS(Cylinder-Head-Sector) 模型:
- 柱面(Cylinder):所有盘片上相同半径的磁道集合
- 磁头(Head):每个盘面对应一个读写磁头
- 扇区(Sector):每个磁道被划分为多个扇区(通常 512 字节/扇区)
⚠️ 现代磁盘已不使用 CHS,但 BIOS 和 MBR 仍模拟此模型以保持兼容。
2. 逻辑布局(LBA 模型)
现代磁盘使用 LBA(Logical Block Addressing):
- 扇区编号从 0 开始连续编号
- LBA 0 = 第一个扇区
- LBA 1 = 第二个扇区
- ...
- 总容量 = (LBA 最大值 + 1) × 512 字节
✅ LBA 是操作系统和现代 BIOS 使用的标准。
二、PC 磁盘关键布局(启动相关)
(一)主引导记录(MBR)— LBA 0
| 偏移 | 大小 | 内容 |
|---|---|---|
0x000 | 446 字节 | 引导代码(Bootstrap Code) |
0x1BE | 64 字节 | 分区表(4 项 × 16 字节) |
0x1FE | 2 字节 | 签名(0x55AA) |
💡 MBR 总共 512 字节,是磁盘的第一个扇区。
分区表项结构(16 字节):
| 偏移 | 长度 | 含义 |
|---|---|---|
| 0 | 1 | 状态(0x80 = 可启动) |
| 1 | 3 | 起始 CHS(已废弃) |
| 4 | 1 | 分区类型(如 0x0B = FAT32, 0x83 = Linux) |
| 5 | 3 | 结束 CHS(已废弃) |
| 8 | 4 | 起始 LBA(关键!) |
| 12 | 4 | 分区总扇区数 |
✅ 现代系统只使用“起始 LBA”字段,忽略 CHS。
(二)分区布局(以主分区为例)
假设一个硬盘有 1 个主分区:
| LBA 地址 | 内容 |
|---|---|
| 0 | MBR |
| 1 ~ N-1 | 空闲(或第二阶段 bootloader) |
| N | 分区引导记录(PBR) / Volume Boot Record(VBR) |
| N+1 ~ ... | 文件系统数据(如 FAT 表、根目录、簇数据) |
💡 N = 分区起始 LBA(来自 MBR 分区表)
(三)典型文件系统布局(以 FAT32 为例)
在分区内部(从 PBR 开始):
| 偏移(相对分区起始) | 内容 |
|---|---|
0x000 | PBR(512 字节) • BPB(BIOS Parameter Block) • 引导代码 • 签名(0x55AA) |
0x00D | BPB:每扇区字节数(通常 512) |
0x00E | BPB:每簇扇区数 |
0x01C | BPB:FAT 表数量 |
0x024 | BPB:根目录起始簇 |
0x02C | BPB:总扇区数(32 位) |
0x036 | BPB:每个 FAT 表占用扇区数 |
| 紧随 PBR | FAT 表 1 |
| + FAT 大小 | FAT 表 2(备份) |
| + FAT 大小 | 根目录区 |
| 之后 | 数据区(文件内容) |
(四)Linux ext2/ext3/ext4 布局
| 偏移 | 内容 |
|---|---|
0x000 | 超级块(Superblock) • 文件系统元信息(块大小、inode 数等) |
0x400 | 块组描述符表(GDT) |
| 后续 | 块位图、inode 位图、inode 表、数据块 |
💡 ext 系列使用 块(Block) 而非扇区(通常 1K~4K/块)。
(五)启动过程中的磁盘访问流程
- BIOS 将 MBR(LBA 0) 加载到内存
0x7C00 - MBR 代码:
- 扫描分区表,找到活动分区(状态=0x80)
- 用
INT 13h读取该分区的 PBR(LBA = 分区起始 LBA) 到0x7E00
- PBR 代码:
- 解析 BPB,定位 FAT 表/根目录
- 读取 第二阶段 bootloader(如 GRUB 的
core.img或 DOS 的IO.SYS)
- 第二阶段:
- 加载内核(如
vmlinuz、KERNEL.SYS)
- 加载内核(如
三、通用寄存器约定
| 寄存器 | 用途 |
|---|---|
AH | 功能号(子功能选择) |
CF | 返回状态:CF=0 成功,CF=1 失败 |
AL / AX | 输入/输出参数(依功能而定) |
DL | 驱动器号(关键!) |
AH功能编码
| 00H —磁盘系统复位 0DH —硬盘系统复位 | 0EH —读扇区缓冲区 0FH —写扇区缓冲区 10H —读取驱动器状态 11H —校准驱动器 12H —控制器RAM诊断 13H —控制器驱动诊断 14H —控制器内部诊断 15H —读取磁盘类型 16H —读取磁盘变化状态 17H —设置磁盘类型 18H —设置格式化媒体类型 19H —磁头保护 1AH —格式化ESDI驱动器 |
驱动器号(DL)编码
| 值 | 设备 |
|---|---|
0x00 | 软驱 A: |
0x01 | 软驱 B: |
0x80 | 第一块硬盘(主盘) |
0x81 | 第二块硬盘 |
0xE0–0xFF | 可能用于 CD-ROM(需 El Torito) |
⚠️ 重要:当 BIOS 加载 MBR 时,会将启动驱动器号放入
DL,你的代码应直接使用它!
四、基础功能
(一)复位磁盘系统(AH = 00h)
mov ah, 0x00
mov dl, 0x80 ; 硬盘0
int 0x13
; CF=0: 成功;CF=1: 失败(AH=错误码)
- 重置控制器,清除错误状态
- 建议在读写前调用(提高兼容性)
(二)读取扇区(AH = 02h)✅ 最常用!
mov ah, 0x02 ; 读扇区
mov al, 1 ; 读 1 个扇区
mov ch, 0 ; 柱面低8位
mov cl, 2 ; 扇区号(1-63),位7-6为柱面高2位
mov dh, 0 ; 磁头号
mov dl, 0x80 ; 驱动器(硬盘0)
mov bx, 0x7E00 ; ES:BX = 目标缓冲区
int 0x13
jc error ; CF=1 表示错误
🔢CHS 地址说明:
- 扇区号从 1 开始(不是 0!)
CL的位结构:text
CL = [C9 C8 | S5 S4 S3 S2 S1 S0]
柱面高2位 扇区号(1-63)
🔄 LBA → CHS 转换(假设 255 磁头/63 扇区):
sector = (LBA % 63) + 1;
head = (LBA / 63) % 255;
cyl = (LBA / 63) / 255;
// CL = (cyl >> 2) | sector;
// CH = cyl & 0xFF;
(三)写入扇区(AH = 03h)
mov ah, 0x03 ; 写扇区
mov al, 1 ; 写 1 个扇区
; ... 其他参数同读 ...
mov bx, buffer ; ES:BX = 源数据
int 0x13
⚠️ 注意:很多 BIOS 禁止在 MBR 中写硬盘(安全限制)!
(四)获取驱动器参数(AH = 08h)
mov ah, 0x08
mov dl, 0x80 ; 查询硬盘0
int 0x13
; 返回:
; AL = 最后一个有效磁头号(0-based)
; CH = 最大柱面低8位
; CL = [C9 C8 | max_sector]
; DH = 最大磁头号(同 AL)
; DL = 驱动器数量(bit7=1表示硬盘)
- 用于动态探测磁盘几何结构
(五)检测驱动器就绪(AH = 15h)
mov ah, 0x15
mov dl, 0x80
int 0x13
; 返回:
; AH = 状态
; 00h: 不支持
; 01h: 无介质
; 02h: 可移动盘,有介质
; 03h: 固定盘(硬盘)
; CX:DX = 扇区总数(仅当 AH=03h 时有效)
- 可用于判断是否为硬盘
五、扩展功能
传统 CHS 无法访问 >8.4GB 磁盘。扩展 INT 13h(由 Enhanced Disk Drive Specification 定义)使用 LBA 寻址。
(一)读取扇区(AH = 42h)
1. 定义磁盘地址包(Disk Address Packet, DAP)
struct DAP {
uint8_t size; // = 0x10 (16 字节)
uint8_t reserved; // = 0
uint16_t count; // 要读取的扇区数
uint16_t offset; // 目标缓冲区偏移(ES:offset)
uint16_t segment; // 目标缓冲区段地址
uint64_t lba; // 起始 LBA(64 位)
};
2. 使用示例
; 定义 DAP(在数据段)
dap:
db 0x10 ; size
db 0 ; reserved
dw 1 ; 读 1 个扇区
dw 0x7E00 ; offset
dw 0x0000 ; segment
dq 1 ; LBA = 1
; 调用扩展读
mov ah, 0x42
mov dl, 0x80 ; 驱动器
mov si, dap ; DS:SI -> DAP
int 0x13
jc error
(二) 检测扩展支持
mov ah, 0x41
mov bx, 0x55AA ; magic
mov dl, 0x80
int 0x13
; 如果 CF=0 且 BX=0xAA55,则支持扩展
✅ 优势:支持 64 位 LBA,可访问超大磁盘(理论上 2^64 扇区)











