Linux 0.11 源码探秘:setup.s 里那些 BIOS 中断调用,到底在给内核准备什么‘见面礼’?
Linux 0.11 启动探案录BIOS 中断如何为内核铺路当按下电源键的那一刻一台 x86 计算机的启动过程就像一场精心策划的接力赛。BIOS 完成自检后将接力棒交给 bootsect.s再由 setup.s 接手——这个不到 512 字节的汇编程序却在 Linux 0.11 启动过程中扮演着关键情报官的角色。今天我们就化身计算机侦探解密 setup.s 中那些神秘的 BIOS 中断调用看看它们究竟为即将登场的内核准备了哪些关键见面礼。1. 犯罪现场实模式下的硬件侦察在保护模式这个高级社会到来之前内核必须依靠实模式下 BIOS 提供的线人网络来收集硬件情报。setup.s 开场就是一连串的 BIOS 中断调用每个中断都像一位特定领域的线人提供着不可或缺的硬件信息。1.1 光标位置控制台的第一个坐标mov ah,#0x03 ; 读取光标位置功能号 xor bh,bh ; 页号清零 int 0x10 ; 调用BIOS显示中断 mov [0],dx ; 将结果存入0x90000这段看似简单的代码隐藏着几个关键细节int 0x10是 BIOS 的显示服务中断当 AH0x03 时专门用于获取光标位置返回的 DX 寄存器中DH 存储行号DL 存储列号典型的 80x25 文本模式存储位置 0x90000DS:0000将在后续控制台初始化时被内核读取提示在实模式下[0] 表示 DS:0000而 setup.s 开始时已将 DS 设为 0x9000因此实际物理地址是 0x90000。1.2 内存探测规划未来的疆域mov ah,#0x88 ; 获取扩展内存大小 int 0x15 ; 调用BIOS内存服务 mov [2],ax ; 结果存入0x90002这个调用返回的是 1MB 以上的扩展内存大小单位 KB存储在 AX 寄存器中。值得注意的是该值将被用于初始化内存管理数据结构在早期的 80286 系统上最大只能检测到 16MB 内存结果存储在 0x90002 处与光标位置相邻内存布局在此时开始成形内存地址存储内容用途0x90000光标位置DX控制台初始化0x90002扩展内存大小AX内存管理初始化2. 硬件档案建立设备数据库除了基本的内存和显示信息setup.s 还收集了各类硬件设备的详细参数这些数据将成为内核驱动初始化的基础。2.1 显示系统显卡的身份证明mov ah,#0x0f ; 获取当前显示模式 int 0x10 mov [4],bx ; BH显示页号存入0x90004 mov [6],ax ; AL显示模式,AH字符列数存入0x90006后续还有更详细的 EGA/VGA 检测mov ah,#0x12 ; 获取EGA/VGA信息 mov bl,#0x10 int 0x10 mov [8],ax ; 视频参数存入0x90008 mov [10],bx ; 视频配置存入0x9000A mov [12],cx ; 视频配置存入0x9000C这些信息对内核至关重要确定文本模式还是图形模式了解屏幕分辨率和色彩深度为帧缓冲区分配正确的内存区域2.2 存储设备硬盘的解剖图最复杂的要数硬盘参数获取; 获取第一硬盘参数表 mov ax,#0x0000 mov ds,ax lds si,[4*0x41] ; 从中断向量表获取硬盘1参数表地址 mov ax,#INITSEG mov es,ax mov di,#0x0080 mov cx,#0x10 rep movsb ; 复制16字节到0x90080同样方法获取第二硬盘参数从中断向量 0x46 处。这些参数包括柱面数、磁头数、每磁道扇区数写预补偿、磁头着陆区控制字节等这些精确的物理参数是后续磁盘驱动初始化的基础没有它们内核甚至无法找到自己的根文件系统。3. 情报处理为内核搬家做准备收集完所有硬件信息后setup.s 开始执行一项关键任务将系统代码从 0x10000 移动到 0x0000。这是一次精妙的内存搬运操作。3.1 关闭中断行动前的静默cli ; 禁止中断这个简单的指令却至关重要移动内存时会覆盖 BIOS 的中断向量表任何中断都会导致不可预测的结果直到新的保护模式中断描述符表IDT就位前中断必须保持关闭3.2 内存搬运系统代码的迁徙mov ax,#0x0000 cld ; 清除方向标志确保正向移动 do_move: mov es,ax ; 目标段地址 add ax,#0x1000 cmp ax,#0x9000 jz end_move mov ds,ax ; 源段地址 sub di,di ; 目标偏移清零 sub si,si ; 源偏移清零 mov cx,#0x8000 rep movsw ; 移动64KB数据 jmp do_move end_move:这段代码实现了将 0x10000-0x8ffff 的内容移动到 0x0000-0x7ffff每次移动 64KB0x8000 字使用 rep movsw 高效搬运数据移动后的内存布局将变成------------------ 0x00000 | 系统代码 | | (原在0x10000) | ------------------ 0x80000 | 空闲 | ------------------ 0x90000 | 硬件参数存储区 | ------------------ 0x90200 | setup.s代码 | ------------------4. 交接准备保护模式的入场券在完成所有准备工作后setup.s 最后也是最重要的任务是为进入保护模式铺路。这包括4.1 加载全局描述符表GDTend_move: lidt idt_48 ; 加载空IDT lgdt gdt_48 ; 加载GDTGDT 是保护模式的基石定义了内存段的权限和属性。Linux 0.11 的初始 GDT 包含空描述符必须代码段描述符基址 0界限 16MB数据段描述符基址 0界限 16MB4.2 开启保护模式的最后步骤打开 A20 地址线突破 1MB 内存限制设置 CR0 寄存器的 PE 位切换到保护模式执行远跳转刷新指令队列mov ax,#0x0001 ; 保护模式PE位 lmsw ax ; 加载机器状态字 jmpi 0,8 ; 跳转到保护模式代码段这个跳转中的 8 是代码段选择子指向 GDT 中的代码段描述符。从此CPU 进入 32 位保护模式内核正式接管系统。回顾整个 setup.s 的工作它就像一位尽职的管家在主人内核到来前调查清楚所有硬件情况内存、显示、磁盘把系统文件搬到合适的位置准备好保护模式所需的所有文档GDT、IDT最后优雅地交出控制权没有这些精心准备的见面礼内核将如同盲人摸象无法有效管理系统资源。这也是为什么三十多年后我们仍然要研究这些启动代码——它们展现了计算机从物理硬件到智能系统的神奇一跃。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2568638.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!