Chinaunix首页 | 论坛 | 博客
  • 博客访问: 24155
  • 博文数量: 13
  • 博客积分: 109
  • 博客等级: 民兵
  • 技术积分: 105
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-18 03:24
文章分类

全部博文(13)

文章存档

2012年(3)

2011年(10)

我的朋友

分类: LINUX

2011-09-02 12:07:32

(本文主要参考Linux 内核设计的艺术 针对0.11版本

从开机到main函数执行分三步完成:

第一步,启动 BIOS,准备实模式下的中断向量表和中断服务程序;

从硬件角度看,Intel 80x86 系列的 CPU 可以分别在 16 位实模式和 32 位保护模式下运行。 为了兼容, 也为了解决最开始的启动问题,Intel 将所有 80x86 系列的 CPU( 包括最新型号的 CPU)的硬件都设计为加电即进入 16 位实模式状态运行。同时,还有一点非常关键,即将 CPU 硬件逻辑设计为加电瞬间强行将 CS 的值置为 0xFFFF,IP 的值置为 0x0000, 这样 CS:IP 就指向 0xFFFF0 这个地址位置。

BIOS 程序在内存最开始的位置(: 0x00000)1KB 的内存空间(0x00000 ~ 0x003FF)构建 中断向量表,并在紧挨着它的位置用 256 字节的内存空间构建 BIOS 数据区(0x00400 ~ 0x004FF) , 在大约 56KB 以后的位置(0x0E05B) 加载了 8KB 左右的与中断向量表相应的若干中断服务程序

第二步,从启动盘加载操作系统程序到内存,加载操作系统程序的工作就是利用第一步中准备的中断服务程序实现的 ;

对于 Linux 0.11 操作系统而言, 计算机将分三批逐次加载操作系统的内核代码。 第一批由 BIOS 中断 int 0x19h 把第一扇区 bootsect 的内容加载到内存 ; 第二批和第三批在 bootsect 的指挥下,分别把其后的四个扇区和随后的 240 个扇区的内容加载至内存。

加载第一部分代码—引导程序(bootsect)

0x07C00, 然后复制到 0x90000

加载第二部分代码—setup

0x90200

加载第三部分代码—system 模块


第三步,开始向 32 位模式转变,main 函数的调用做准备 。(setup开始执行执行)

1.关中断并将 system 移动到内存地址起始位置 0x00000

这个准备工作先要关闭中断, 即将 CPU 的标志寄存器(EFLAGS) 中的中 断允许标志(IF)0。这意味着,在接下来的执行过程中,无论是否发生中断,系统都不再响 应此中断,直到 main 函数中能够适应保护模式中断服务体系被重建完毕才会 打开中断,那时候响应中断的服务程序将不再是 BIOS 提供的中断服务程序,取而代之的是由 系统自身提供的中断服务程序

system 模块复制到 0x00000 这个动作废除了 BIOS 的中断向量表, 也就是废除了 16 位的中断机制。 操作系统是不能没有中断的, 对外设的使用、 系统调用、 进程调度都离不开中断。Linux 操作系统是 32 位的现代操作系统,16 位的中断机制 对 32 位的操作系统而言显然是不合适的, 这也是废除 16 位中断机制的根本原因。

2.设置中断描述符表和全局描述符表

GDT(Global Descriptor Table, 全局描述符表 )

GDTR(Global Descriptor Table Register,GDT 基地址寄存器 )

IDT(Interrupt Descriptor Table,中断描述符表)

IDTR(Interrupt Descriptor Table Register,IDT 基地址寄存器)

32 位的中断机制和 16 位的中断机制在原理上有比较大的差别, 最明显的是 16 位的中断机

制用的是中断向量表, 中断向量表的起始位置在 0x00000 , 这个位置是固定的。32 位的中断

机制用的是中断描述符表 IDT,位置是不固定的,可以由操作系统的设计者根据设计要求灵活安

,IDTR 寄存器来锁定其位置。

创建这两个表的过程可理解为是分两步进行的 :

(1)在设计内核代码时,已经将两个表写好,并且把需要的数据也写好。

(2)将专用寄存器(IDTR GDTR)指向表。

3.打开 A20,实现 32 位寻址(A20即第20根地址线,具体做法不讲了)。

4.为在保护模式下执行 head.s 做准备

为了建立保护模式下的中断机制,setup 程序将对可编程中断控制器 8259A 进行重新编程。

在保护模式下,int 0x00 ~ int 0x1F Intel 保留作为内部(不可屏蔽)中断和异常中断。如 果不对 8259A 进行重新编程,int 0x00 ~ int 0x1F 中断将被覆盖。例如,IRQ0(时钟中断)8 (int 0x08) 中断, 但在保护模式下此中断号是 Intel 保留的“Double Fault( 双重故障 )。 因 此,必须通过 8259A 编程将原来的 IRQ0x00 ~ IRQ0x0F 对应的中断号重新分布,即在保护模式 下,IRQ0x00 ~ IRQ0x0F 的中断号是 int 0x20 ~ 0x2F

CR0 寄存器的第 0 (PE)1,即设定处理器的工作方式为保护模式。(CR0 寄 存 器 : 32 位 控 制 寄 存 器, 存 放 系 统 控 制 标 志。 第 0 位 为 PE(Protected Mode Enable,保护模式使能 ) 标志,1 CPU 工作在保护模式下,0 时为实模式。)

5. head.s 开始执行

head程序在system模块最前面。也就是说,system 模块里面,既有内核程序,又有 head 程序,两者是 紧挨着的。所以实际上, head 程序就在 0x00000 这个位置。

具体head.s的内容可以查看linux内核完全剖析和Linux 内核设计的艺术 。

从这里开始,内核完全都是在保护模式下运行了。

head完成的工作主要有设置 IDTGDT、页目录表、页表,以及机器系统数据 等。

head 程序执行完后 即跳入 main 函数程序执行。  

阅读(537) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~