| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> 从根上理解操作系统(一) -> 正文阅读 |
|
[系统运维]从根上理解操作系统(一) |
目录 操作系统启动? ? ? ? 在了解操作系统之前要有一个意识,那就是计算机的运行过程就是取指执行,什么意思呢?即计算机会根据程序计数器的值获取代码指令然后执行它。 ? ? ? ? 大家有没有想过,点击电脑启动按钮的那一刻,计算机到底做了一些什么动作呢? ? ? ? ? 在计算机启动的过程中,主要有四个模块:BIOS-> boot -> setup -> system,这四段程序由前往后依次执行。 ? ? ? ? 这里以linux0.11为例。按开机的时候,首先启动的就是BIOS程序,这段程序是提前固化在内存中的。CS和IP分别是段寄存器和偏移寄存器,CS左移4位+IP 就是寻址地址,在开机时,CS被赋值了0xFFFF,IP被赋值了0x0000,所以计算机执行的第一条指令就是在0xFFFF0处的指令,而BIOS程序就是固化在这里的,所以说BIOS程序可以在开机时首先被执行。 1 BIOS执行的主要任务
? ? ? ? 接下来计算机就会从0x7c00处执行程序,而这段程序就是从引导扇区读入的代码 bootsect.s 2 bootsect代码的作用? ? ? ? bootsect程序是磁盘引导块程序,在磁盘的第一个扇区,主要的处理步骤如下:
3 setup完成OS启动前的设置? ? ? ? 磁盘第二个扇区开始的4个扇区为setup模块,会被加载到内存紧接着bootsect后面位置处。从名字上也可以看出来,这个模块是为了完成OS启动前的参数设置。setup的主要功能如下:
? ? ? ? 这里关键有一个“保护模式”。那么什么是保护模式,为什么需要保护模式?这里需要对其进行解释: ? ? ? ? 内存是指一组有序字节组成的数组,每个字节有唯一的内存地址,内存寻址则是指对存储在内存中的某个指定数据对象的地址进行定位。对于80x86CPU,一条指令主要由操作码和操作数构成,操作数可以位于一个寄存器中,也可以在内存中,若要定位内存中的操作数,就要进行内存寻址。 ????????早期的8086处理器寄存器宽度只有16位,16位的寄存器只能进行 64 KB 的寻址,而 8086 有 20 根地址线,按照地址线来计算可以进行 1 MB 的寻址,所以16 位宽度的寄存器是显然不能满足需求的,为了解决这个问题,聪明的程序员想出了用?段基址:段内偏移?的方式来扩展寻址空间。 ????????物理地址 = 段基址 << 4 + 段内偏移 ????????CPU在访问内存前,会先经过段部件,按照上面的换算公式,计算出物理地址,这样两个 16 位的寄存器合在一起,宽度便成了 20 位。 ? ? ? ? 这被称为”段“的寻址技术。这种寻址技术把内存分成了一个或多个称为段的线性区域,从而对内存中的对象的寻址就需要使用一个段的起始地址和段内偏移地址构成。 ? ? ? ? 此时的寻址方式还是实模式,那么实模式有什么缺陷呢?首先就是不安全,程序可以随意访问任何物理地址。 ????????为了不让某些内存数据被篡改,保护模式孕育而生! ????????cs左移4位+ip只有20位地址,只有1M的寻址空间,所以需要从16位机切换到32位机(保护模式)。保护模式用的是与实模式不同的一套电路,将cr0的PE位设置为1就切换到了保护模式。 ????????在保护模式下,很重要的一点就是段寄存器不是直接存放段基址了,而是存放着段选择子。 段选择子,大可以认为就是索引,用于索引段描述符。而段描述符,顾名思义,用来描述一个段的信息,长度为64位,其中有32位用来存放段基址,剩下32位存放着段界限等信息。那么段描述符存放在哪里呢?GDT,全局描述符表,全局描述符表会存放着所有的段描述符。每个段描述符的长度是8字节,含有3个主要字段:段基地址、段限长和段属性。 ????????那我把索引(段选择子)告诉CPU了,他怎么知道上哪找GDT 呢?当然你得提前告诉CPU GDT的地址:
????????只要执行了上面这个指令,CPU 便会记录下GDT的地址了,将其存到GDTR寄存器中。 ? ? ? ? 所以保护模式下寻址的过程如下所示 ? ? ? ?通过GDR寄存器找到GDT表的位置,然后通过段选择子找到对应的段描述符,而描述符里存的有段基址,所以通过段基址和偏移地址就可以定位到需要的内存地址。这里需要预告一个概念——分页。在未开启分页的情况下,段描述符中的段基址和偏移地址组合起来就是物理内存地址: ? ? ? ? ?其实除了寻址方式的变化,保护模式还增加了一个新名词:特权级。处理器的段保护机制可以识别0~3级共4级特权级,数值越大,特权越小。主流操作系统主要使用两个特权级0和3。0代表内核级,3代表用户级。由3>0,所以用户态的权限要小于内核态,也就是用户段的程序无法直接跳到内核段取指令执行程序,这样就起到了保护的作用。那么这个特权保护功能是怎么实现的呢? ? ? ? ? 我们通过上面段描述符的格式图里可以看到有一位被称作DPL——描述符特权级,这个代表了该描述符所关联的代码段的特权级。而当前段的特权级存储在段选择子的位0和位1中。 ? ? ? ? 假如有一个用户段A想跳转到内核段B执行,那么会首先判断A的CPL是否小于等于B的DPL,如果成立,则可以跳转,否则,不允许跳转。由于用户段的特权级为3,即CPL=3,内核段的特权级为0,即DPL=0,跳转条件不成立,所以不允许跳转。这样就起到了保护内核的作用。(这里还有个RPL的概念,跳转条件还需要满足DPL>=RPL,不再赘述) ? ? ? ? 总结从实模式到保护模式的步骤如下:
? ? ? ? 那么既然用户段程序无法跳转至内核段执行内核的代码,那么用户怎么使用操作系统提供的能力呢?这里就要提到IDT了,IDT是中断向量表,跟GDT表的结构很类似,通过int指令可以在IDT表中找到中断描述符,中断描述符里也有一个DPL,而这个DPL是3,所以用户段可以执行中断入口程序,而中断入口程序的CPL是0,所以中断入口程序可以执行内核段的代码,这样,用户就可以使用操作系统提供的能力了,并且使用什么能力是由中断入口程序决定的,从而起到了保护作用。 4 system 模块执行? ? ? ? system模块的执行主要分两步:head.s的执行,另一个是main.c的执行。 ? ? ? ? head.s程序在被编译生成目标文件后会与内核其他程序一起被链接成system模块,位于system模块的最前面开始部分,这也是为什么称其为头部程序的主要原因。 ?head.s:
? ? ? ? ?从0地址处开始就有了操作系统,并且有了初始化好的数据结构(GDT、IDT、mem_map等)。 main.c: ? ? ? ? 该程序首先利用前面setup.s程序取得的系统参数设置系统的根文件设备号以及一些内存全局变量。这些内存全局变量指明了主内存的开始地址、系统所拥有的内存容量和作为高速缓冲区内存的末端地址 ? ? ? ? 主内存区域的内存由内存管理模块mm通过分页机制进行管理分配。内核程序可以自由访问高速缓冲中的数据,但是需要通过mm才能使用分配到的内存页面。 ? ? ? ? ?mian函数开始就是进行了一系列的初始化,我们以mem_init()为例来说明一下初始化的过程: ? ? ? ? ?mem_init函数其实就是初始化了一个mem_map的数组,代表整个内存空间的页,0代表对应的页没有使用,USED代表已经使用。 参考: 《linux0.11完全剖析》 李治军《操作系统》课程 从linux0.11看一个进程的诞生 - 云+社区 - 腾讯云 真棒! 20 张图揭开内存管理的迷雾,瞬间豁然开朗 - SegmentFault 思否 32位机,CPU是如何利用段寄存器寻址的 - ggzone - 博客园 GDT,LDT,GDTR,LDTR 详解,包你理解透彻 | 技术部落 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 19:54:03- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |