操作系统的启动
操作系统的启动是个很令人好奇的话题,从按下计算机电源的那一刻,计算机从裸机开始呈现一个丰富的系统界面,这个从只有硬件逻辑到软件逻辑的过程是如何完成的?这里我们将从硬盘分区,三方协议,grub引导启动程序进行讲述,首先介绍硬盘MBR分区形式,然后介绍CPU,BIOS,系统的三方协议,讲述从CPU的硬件逻辑最终运行内核的软件逻辑的过程,最后介绍一下引导启动程序的发展,在grub这些引导启动程序中如何继续遵守三方协议。
1, MBR硬盘分区
MBR(Master Boot Record)即主引导记录分区表。它由三个部分组成:主引导记录,硬盘分区表和有效标志,共512字节,位于硬盘的0柱面、0磁头、1扇区。其中主引导记录占前446字节,硬盘分区表(DPT)占64字节,分区表里有4个表项,每个表项占16字节,最后是2字节的结束标志(固定为0x55AA)。在MBR分区中,第一个扇区的内容是十分关键的,它是主引导记录,如果操作系统需要按照MBR分区形式安装在这个硬盘中,那么需要在主引导记录里填入引导系统启动的代码。MBR分区在硬盘上的组织形式大致如下:
2, 三方协议
想要把操作系统启动起来,是需要多方按照一定的协议进行协作才能完成的,以Linux0.11,BIOS+MBR分区,Intel80x86CPU为例,首先电源加电后,主板会将BIOS从ROM里读取并放入内存RAM里,其在内存的位置是0xFE000~0xFFFF0,共计8KB,此时CPU加电后会进入16位实模式,通过硬件逻辑强行把自己的CS的值设置为0xF0000,IP的值设置为0xFFF0,这样CS:IP寻址就会指向内存的0xFFFF0,也就是BIOS的起始位置,那么BIOS程序就开始执行了,此时完成了CPU与BIOS的协同,彼此间的协议就是内存地址0xFFFF0!那么BIOS执行后,需要从硬盘或其他地方读取内核的代码,让内核执行起来,这如何做到呢?首先BIOS在开始执行时会把子机的中断向量表和BIOS数据放到内存的某个区域,中断向量表在0x00000~0x003FF,共计1KB,BIOS数据区在随后的0x00400~0x004FF,共计256B,建立好中断向量表以及其他操作后,BIOS会触发一个int0x19中断,CPU接收到这个中断后,会去内存的BIOS中断向量表里找到int0x19这个中断的中断服务程序(内存位置在0x0E6F2),这个中断服务程序的功能就是把磁盘里的第一个扇区(512B)读取到内存0x07C00(BOOTSEG)处,并开始执行它。此时内存第一次有了操作系统的代码,第一个扇区的内容其实就是linux/boot/bootsect.s的内容,其主要功能就是把第二批第三批代码加载到内存中规划好的位置。
bootsect.s的内存规划如下:
SETUPLEN = 4 ! nr of setup-sectors
BOOTSEG = 0x07c0 ! original address of boot-sector
INITSEG = 0x9000 ! we move boot here - out of the way
SETUPSEG = 0x9020 ! setup starts here
SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
经过调整boosect自身在内存的位置之后,boosect开始把setup程序加载到内存中,此时使用的另一个中断向量int0x13,此中断向量可以指定扇区和内存位置,将指定扇区的内容读取的指定的内存位置。在bootsect中,读取的是从第二个扇区开始的4个扇区,加载到0x90200(SETUPSEG)处,这些内容对应linux/boot/setup.s这个文件。加载进来后,setup会再次调整内存规划,然后会使用int0x13中断向量继续加载240个扇区的内容,也就是system模块。setup还会做一些设置,例如关中断,设置中断描述符表和全局描述符表,打开A20实现32位寻址,对编程中断控制器8259A进行重编程,建立保护模式下的中断机制等等,为内核main函数的调用做准备。此时内存的视图如下:
所以,我们可以知道,当BIOS运行后,会通过int0x19中断读取第一扇区的内容,BIOS并不管这个扇区里是否有内容。如果我们系统安装在硬盘上,就得保证第一扇区是我们的bootsect,这样才可以通过int0x13读取其他扇区的setup和system,从而最终完成内核的启动。所以这个第一扇区是至关重要的,是BIOS与系统的协议。
3, grub
经过多年的发展,引导程序已经由最初像Linux0.11的bootsect.s,setup.s等发展为grub,grub2之类的启动引导程序,第一扇区(主引导记录)也从bootsect.s变成了stage1,boot.img这些形式的内容,这类引导程序可以引导多个操作系统,多种操作系统的启动,拥有配置文件和简单的命令行界面,功能变得十分强大。不过grub跟最初的引导程序一样,也是遵循BIOS+MBR的规则的。gurb对系统的引导也是分为三个阶段,步骤1(stage1)的内容存放在主引导记录里,其功能主要是加载步骤1.5(stage1.5)的内容,也就是grub到内存中,步骤1.5会加载步骤2的内容,步骤2启动后,将会呈现一个选择启动的操作系统的界面。grub2是grub的升级版,在硬盘分区的内容与grub类似,只是stage1变成了boot.img,stage1.5变成core.img。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android实现顶部悬浮效果
- Linux基础:性能监控
- pstack 跟踪进程栈
- android实现左右侧滑菜单效果
- 排查守候在零点两分的 bug
- Android中TextView实现部分文字可点击跳转
- Android viewpager自动轮播和小圆点联动效果
- 用Redis构建缓存集群的最佳实践有哪些?
- Android实现IP地址输入框的方法示例代码
- Node.js 搭建 HTTPS 服务器
- Android布局之表格布局TableLayout详解
- 简单实现Android倒计时效果
- Android实现单页面浮层可拖动view的一种方法
- 排查 Node.js 服务内存泄漏,没想到竟是它?
- Android判断网络状态的代码