第1章 从开机加电到main函数之前的过程
主要讲解了80x86cpu在启动的时候时bios如何工作,以及如何最终转换到保护模式。
1.1 启动bios
80x86作为冯诺依曼结构下的cpu,工作模式也是取指执行,即cpu根据cs:ip寄存器的值‘计算’出一个真正的物理地址,在8086实模式的情况下这个地址是20位的,然后通过20位的地址线去寻址。20位的地址线对应1MB可寻址空间,这里特意使用了可寻址空间而不是我一直以为的内存空间,言下之意1MB的寻址空间包括内存(RAM)也包括一些其他的存储介质,而bios就放在这些其他的存储介质上,具体来说就是主板上的ROM里,ROM里的代码是厂家生产CPU时候就烧进去的,固定的。
现在回到计算机启动的问题上,计算机在加电的时候,没有操作系统,内存里空空如也,谁来设置第一条指令的地址?第一条指令的设定是通过硬件来实现的,为了解决CPU启动的问题Intel工程师把所有80x86系列的cpu设置为在启动的时候工作在实模式,然后cs寄存器的值设置为0xf000,IP寄存器的值设置为0xfff0,这样第一条指令的位置就是0xFFFF0。cpu从这条指令开始,开始了它循环往复的取值执行的一生,直至断电。
这张表是实模式下1MB的内存布局,从0xF0000到0XFFFFF都是rom的空间,开机时候跳转到的地址为0xFFFF0,CPU要从这个地址开始执行指令,然后自增ip取下一条指令。根据这个表可以看出来从0xFFFF0开始到地址空间的末尾只有16位的内容,显然是不够写BIOS的代码的,所以这里的代码是一个无条件跳转指令,跳转到ROM里的另一个地方即0xF000:E05B处,从这里开始才是真正的BIOS开始的地方。
1.2 BIOS干了什么
在召唤出操作系统之前的所有对硬件的管理工作都是由BIOS完成的。
1.2.1 自检、设置中断向量表
首先对硬件进行自检,包括内存、显卡等外设信息,然后开始在0x00000的位置开始用1KB的存储空间建立中断向量表,然后在紧挨着中断向量表后面用256个字节建立BIOS的数据区,然后再接着后面是与中断向量表相关的中断服务程序。结合上面实模式下的内存布局,可以看到这里的内容都是建立在内存里(RAM)而不是ROM里。
中断向量表的空间大小是1KB,所谓中断向量就是一个指向中断服务例程的地址,CS:IP,CSIP都是两个字节,加一起是四个字节,所以一共有256个中断向量,操作系统从指定的存储设备加载到内存里就离不开中断向量表。
1.2.1 真正的加载开始了!
开始了真正的从存储设备上加载操作系统,以从软盘上加载操作系统为例,当然启动顺序要在BIOS里设置好启动顺序。在BIOS完成自检和中断向量表的设置之后,CPU会收到一个int 0x19中断,既然是中断就得有人给cpu发出中断,我猜测这个中断就是BIOS程序发出的。不管如何,CPU在收到这个中断的时候回查中断向量表找到中断向量进一步找到中断服务程序的地址,然后CPU开始执行int 0x19的中断响应程序,该程序的功能是找到软盘的第一扇区并加载到内存的指定的位置。从这里可以看到,这段的执行过程和操作系统无关,无论软盘里放的什么操作系统,到CPU都是简单的把他加载进来,CPU做的就是找到第一扇区,然后读进来。
第一扇区的内容被称为启动扇区(bootsector),它被读到了 0X07C00处,这个扇区的内容就被称为bootsect,到了这里才有了Linux内核的代码,bootsect的内容是和操作系统相关的,不同的操作系统bootsect不一样,bootsect负责后续的linux内核代码的加载。
bootsect在加载后续代码之前,做的第一件事情是对整个内存区域做一个划分,防止后续的内容相互覆盖,然后把bootsect的内容从0x7C000处复制到0x90000处。
然后bootsect开始从软盘里读取后续的操作系统的代码。这次读取代码是通过int 0x13中断完成,该中断的相应例程也是从软盘上读取数据到内存里,相较于读取bootsect的int0x19,int 0x13从软盘读取数据的位置和读到内存的位置是可以设置的,这个设置的动作就是bootsect完成的。总之通过int0x13中断bootsect召唤了setup,setup的在内存的位置是有bootsect设计好的。在加载完setup之后同样适用int0x13中断从软盘上加载system,system在内存的位置同样是设计好的。至此bootsect的历史使命基本完成了,在他离开之前还要完成最后一个任务即确定根设备号,剩下的操作是由setup和system完成。
setup做的第一件事情就是加载机器系统数据,这一加载过程也是通过中断完成的,一如加载bootsect setup system。
1.3 走向保护模式
1.3.1 什么是保护模式
保护模式保护的是内存,在实模式下所有内存空间对所有进程都是敞开怀抱的,操作系统和用户进程属于同一特权级别。因为实模式下访问地址的方式是段基址加上偏移地址,段基址和偏移地址可以所以修改。保护模式是80286以上的CPU才有的概念,8086只有16位的所谓的实模式,实际上只有32位的CPU才区分保护模式和实模式。
32位的CPU里的寄存器在实模式下都是16位的,到了32位的保护模式会对寄存器进行一定的扩展,除了段寄存器之外的寄存器都被扩展到了32位。
保护模式下寻址还是段基址加偏移地址的模式,和实模式和保护模式最大的区别是对段基址的“翻译”不同,不是简单的左移4位和偏移地址相加,而是经过一个相对复杂的映射程序然后再和偏移地址相加。在这种复杂的映射模式下,段寄存器保存的16为的数据不再被称为段基址,因为他不是“内存里一个段的基址”,而被称为段选择符。
1.3.2 GDT LDT 与寻址
实模式下段寄存器里的16位的数据不再是段基址,它可以分为三个部分如下所示。根据TI标志位选择使用GDT还是LDT,然后从寄存器里找到GDT或者LDT的地址,用3~15位的数据在该表里找到段描述符,段描述符的地位类似于实模式下的段基址,段描述符里保存段的起始地址。
段描述符是8个字节,存储的内容不仅仅是段的起始地址,也包括该段基址对应段的控制信息,例如是否可写,代码段还是数据段。至此16位的段寄存器里的内容被翻译成32位的段基址并获得了相应的控制信息,这个复杂的翻译过程就是实模式下的段基址左移4位的过程。
1.3.3 打开保护模式
首先关中断,然后把system内容复制到内存的起始位置,之前内存的起始位置放的是BIOS的中断表,被system覆盖后将无法响应中断,所以这里要关中断。所谓关中断就是执行cli指令,cli指令把CPU的中断允许标志位置0,是一个硬件层面的操作。
然后初始化GDTR和IDTR,前者是用于保护模式下寻址,后者是保护模式下中断服务表。此时内存里的IDT是一张空表因为现在CPU屏蔽了中断也不会响应任何中断。
接着打开A20标志位,允许cpu用32位的地址线寻址。
对IDT表初始化,这样CPU有了再保护模式下响应中断的能力,最后打开CPU相应的标志位开启CPU的保护模式。
第1章 从开机加电到main函数之前的过程的更多相关文章
- linux内核剖析(零)linux系统启动过程详解-开机加电后发生了什么
本文参考了如下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详解linux系统的启动过程及系统初 ...
- linux系统启动过程具体解释-开机加电后发生了什么 --linux内核剖析(零)
本文參考了例如以下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详细解释linux系统的启动过程 ...
- 《Linux内核设计的艺术》学习笔记(一)从开机加电到加载三个汇编源码
实验内核版本:0.11 ◆ 从开机到main函数的三步: ① 启动BIOS,准备实模式下的中断向量表和中断服务程序: ② 从启动盘加载OS程序到内存中,加载OS程序的工作就是利用第一步中的中断服务 ...
- Linux0.11从开机到准备执行main函数的启动学习
最近一直在看操作系统以及内核设计的东西,不确定自己有能力会参与到类似的开发之中,但是争取能自己改造这内核玩一下,然后按照Linux From Scratch那样的把改造后的系统编译运行就心满意足了.正 ...
- 计算机从加电到系统(Linux)启动完成
0x0 背景 在我参加的面试和我面试别人.或者参加别人对别人的面试的事后经常遇到的一个问题就是:请从计算机加电开始描述一下计算机启动到操作系统正式启动起来的全过程.这是一个考验对计算机体系结构和基本知 ...
- centos7启动流程(从加电开始)
图片来自于https://blog.csdn.net/qq_27754983/article/details/75212666 1. UEFI或BIOS启动 服务器加电后,CPU 自动重置成初始状态, ...
- 从cpu加电到加载OS内核的详细过程(清华大学ucore-lab1总结一)
结合最近学习清华的OS课,先用“人话”来高度抽象的描述一下我自己的理解.CPU在系统加电也就是我们按下电源开关后,开始初始化他的寄存器,主要是cs和eip(本文基于x86架构),然后在ROM中找到一个 ...
- Android开发艺术探索》读书笔记 (12) 第12章 Bitmap的加载和Cache
第12章 Bitmap的加载和Cache 12.1 Bitmap的高速加载 (1)Bitmap是如何加载的?BitmapFactory类提供了四类方法:decodeFile.decodeResourc ...
- 告别加载dll 出错开机加载项大揭秘
提到开机加载(load)项,大家不要以为就是系统启动(run)项.最简单的例子是,杀毒软件或者用户手动删除病毒文件后,注册表中的自动加载信息仍在,登陆系统时就会提示"加载*dll出错,系统找 ...
随机推荐
- Navicat Premium for Mac 破解版地址
找了好几个都不能使用 试了一下这个 可以使用 放地址:http://www.orsoon.com/Mac/85386.html
- 五. Redis持久化
Redis是一个支持可持久化的内存数据库,也就是说Redis可以将数据保存到硬盘当中. 目前Redis支持两种持久化方式: 1. snapshotting 快照方式(默认方式). 2. append- ...
- winsock 编程(简单客户&服务端通信实现)
winsock 编程(简单客户&服务端通信实现) 双向通信:Client send message to Server, and if Server receive the message, ...
- Android 官方DEMO - ActionBarCompat-Basic
ActionBarCompat-Basic Demo下载地址:https://github.com/googlesamples/android-ActionBarCompat-Basic/#readm ...
- backup是个相对论
工作互备,是很多团队领导者都关注的事情.显然,当一项任务由两个(甚至两个以上的人)来完成,当任务交付使用后出现问题时,不会因为其中某一个成员的缺席而导致问题一时处理不了.如果某个任务只是由一个人来担当 ...
- [20190312]视图v$datafile字段OFFLINE_CHANGE#, ONLINE_CHANGE#.txt
[20190312]视图v$datafile字段OFFLINE_CHANGE#, ONLINE_CHANGE#.txt --//视图v$datafile存在2个字段OFFLINE_CHANGE#, O ...
- SQL Server 2012 手动安装帮助文档+排错
逆天SQL Server 2012装的不要不要的,最后发现...竟然没帮助文档...汗啊!原来它跟vs一样要自己装帮助文档...好吧,官网一下载,妹的...报错...然后就让我们还原这个安装过程以及逆 ...
- Windows Server 2016-Active Directory复制概念(二)
本章继续补充有关Active Directory复制概念,具体内容如下: 连接对象: 连接对象是一个Active Directory对象,表示从源域控制器到目标域控制器的复制连接.域控制器是单个站点的 ...
- 在Unity中对Lua进行调试
前言 接我之前的文章,讲到使用IntelliJ IDEA(做为Lua的编辑器)+EmmlyLua(插件),当然EmmlyLua也提供调试功能的. Lua代码提示和方法跳转 在Lua中提示UnityEn ...
- python字符串处理以及字符串格式化
一.python字符串处理 目录: 1.算长度(len),某个元素出现的次数(count) 2.切片 [ ],repr:把不可见字符显示出来 3.查找 #find,rfind从右边查找 4.字符串 ...