在开始阅读系统引导启动部分的内核代码之前,需要对以下内容进行了解:

  • Linux 中断机制
  • Linux 内核源码目录结构
  • 磁盘结构及 INT 0x13

PS. 这个系列的文章将会对 Linux 0.11 版本的源码进行分析,资源在文末


中断机制

硬件原理

微型计算机通常包括 I/O(输入输出) 设备,处理器向设备提供服务的方式有两种

  • 主动:处理器挨个地去询问系统中的设备是否需要服务,这种方式称为 轮询,缺点是太耗费系统资源
  • 被动:当设备需要服务时,向处理器提出请求,处理器响应提出的请求为其提供服务

当设备向处理器提出请求,处理器在执行完当前的一条指令后立刻响应设备请求,并转到相应的服务程序去执行。执行完服务程序后,又返回到之前被打断的位置继续执行,这就是 中断(Interrupt),设备向处理器发出的服务请求称为 中断请求(IRQ)

处理器有一个 INT 引脚专门用来接收中断请求,但设备繁多,如果每个设备的中断请求直接给到处理器,当有多个请求同时到达时,处理器不知道该优先为谁提供服务

因此,需要有个大哥来管理这些设备的中断请求,这个大哥名叫 可编程中断控制器(PIC),PIC 会连接到处理器的 INT 引脚。设备的中断请求都会先给到 PIC,由 PIC 来筛选优先级高的中断请求递交给 CPU,如果 CPU 正在为一个设备提供中断服务,PIC 还会将选出的请求与正在执行的服务程序的优先级进行比较,以确定是否嵌套中断

当 PIC 向 INT 引脚发出中断信号后,处理器立即停下手头的工作,询问需要执行什么中断服务,PIC 通过数据总线发送与中断请求对应的 中断号,处理器拿着中断号去中断向量表(或 32 位保护模式下的中断描述符表)中查询服务程序的入口,进而跳去执行服务程序

中断同样可以由软件通过使用 int 指令来调用中断服务程序,PC/AT 系列微机提供 256 个中断的支持,大部分为软件中断或异常,异常 是处理器在处理过程中检测到错误而产生的中断


中断子系统

80X86 组成的微机系统中采用编号为 8259A 的 PIC 芯片,每个芯片可以管理 8 个中断源,通过多片级联的方式可以最多管理 64(8*8) 个中断向量的系统

PC/AT 系列兼容机中使用了两片 8259A 级联,管理 15 级中断向量,结构如图:

中断机制

左边两片分别为 8259A 的主片和从片,从片通过自己的 INT 引脚连接到主片的 IR2 引脚。使用 IRQ2 引脚的设备又作为从片 IR1 引脚的输入,表示将使用 IRQ2 的设备的 IRQ2 引脚重定向到 IRQ9 引脚上。同时,主片的端口基址在 0x20,从片在 0xA0

8259A 芯片可分为编程状态和操作状态

  • 编程状态下,由处理器使用 IN 或 OUT 指令对其进行初始化编程
  • 操作状态下,响应设备中断请求,选出最高优先级中断,并通知处理器外中断的到来,处理器响应后,中断号由数据总线 D7-D0 送出,处理器由此获取中断向量值,执行中断服务程序

中断向量表

当 80X86 微机启动时,BIOS 中的程序会在物理内存起始处(0)初始化中断向量表,该表包含两个 8259A 芯片支持的 16 个硬件中断向量和 BIOS 提供的中断号为 0x10 ~ 0x1F 的中断调用功能向量,每个表项占 4 字节。对于没有使用的向量则填入临时的哑中断服务程序的地址

对于 Linux 而言,除了在开机时加载引导扇区(bootsect.s)及保存重要信息(setup.s)所用到的 BIOS 中断功能,之后 Linux 会在 setup.s 程序中重新初始化 8259A 芯片,并在 head.s 中重新构建一张中断描述符表,将 BIOS 提供的中断向量表覆盖


内核源码目录结构

一切尽在图中:

内核源码目录结构


磁盘结构

关于磁盘,主要弄清楚几个概念:

  • 磁头(head)
  • 磁道(track)
  • 扇区(sector)
  • 柱面(cylinder)

如图,这是一个容量为 1.44 MB 的软盘:

磁盘结构

一个磁盘面分正反两面,所以读取用的 磁头 也需要两个。从图中可以看到,盘面中一圈圈灰色同心圆为一条条 磁道,从圆心向外画射线,可以将磁道划分为若干个弧段,每个磁道上一个弧段称为一个 扇区。一个 柱面 包含了所有具有相同编号的磁道(从外向内编号,起始为 0)

一张这样的软盘有 2 个磁头,80 个柱面,每个柱面包含18 个扇区(每个扇区 512 字节),所以它的容量为:

2 * 80 * 18 * 512 = 1, 474, 560 Bytes = 1, 440 KB = 1.44 MB

系统启动时的引导扇区就位于 C0-H0-S1(柱面 0,磁头 0,扇区 1)

若想读写相邻两个磁道的数据,顺序为先读写第一个磁道磁头为 0(正面) 的所有扇区,再读写第一个磁道磁头为 1(反面) 的所有扇区,接着转去第二个磁道按照同样的顺序读写


INT 0X13 指令

该指令使用 BIOS 提供的磁盘操作功能,通过几个通用寄存器来传递参数

功能号:

  • AH = 0x02:读盘
  • AH = 0x03:写盘
  • AH = 0x04:校验
  • AH = 0x08:取磁盘参数
  • AH = 0x0c:寻道
  • AH = 0x15:取磁盘类型

AH 为 2 时:

  • 参数:

    • AL = 读出的扇区数(只能同时处理连续的扇区)
    • CH = 磁道号低八位
    • CL = 起始扇区号(0 ~ 5 位),磁道号高两位(6 ~ 7 位)
    • DH = 磁头号
    • DL = 驱动器号
    • ES:BX = 缓冲地址(校验及寻道时不使用)
  • 返回值:

    • FLAGS.CF = 0:处理时没有发生错误,AH = 0
    • FLAGS.CF = 1:发生了错误,错误号存在 AH 中

AH 为 8 时:

  • 参数:
    • DL = 驱动器号
  • 返回值:
    • FLAGS.CF = 0:处理时没有发生错误,AH = 0
    • FLAGS.CF = 1:发生了错误,错误号存在 AH 中
    • AL = 0
    • BL = 驱动器类型(AT / PS2)
    • CH = 最大磁道号的低8位
    • CL = 每磁道最大扇区数(0-5bit),最大磁道号高2位(6-7bit)
    • DH = 最大磁头数
    • DL = 驱动器数量
    • ES:DI:软驱磁盘参数表

AH 为 0x15 时:

  • 参数:
    • DL = 驱动器号
      • 0x80 指第一个硬盘
      • 0x81 指第二个硬盘
  • 返回值:
    • AH = 类型码
      • 0:没有这个盘,CF 置位
      • 1:软驱,没有 change-line 支持
      • 2:软驱(或其他可移动设备),有 change-line 支持
      • 3:硬盘

资源

链接:Linux 0.11 源码

提取码:sgd1