Intel X86 32位CPU内存管理----《Linux内核源码情景分析》笔记(一)
Intel X86 32位CPU内存管理
在X86系列中,8086和8088是16为处理器,而从80386开始为32为处理器,80286则是该系列从8088到80386,也就是16位处理器到32位处理器的一个过渡。
段式内存管理
Intel决定在16位CPU,也就是8086CPU,中使用1M的内存空间,地址总线的宽度也就为20位,但是CPU的ALU(算术逻辑单元)的宽度只有16位,因此采用了“分段”的设计方法。
Intel在8086CPU内置了四个段寄存器:CS,DS,SS和ES,分别用于可执行代码既指令、数据、堆栈和其它。每个段寄存器是16位的,对应于地址总线的高16位。在汇编语言中,访问一个内存的位置使用ES:AX这样的语句,实际访问的位置为 ES*2^4+AX处。这样完成了16位内部地址到20位实际地址的转换。
这种方式没有地址空间的把保护机制,用来改变段寄存器内容的指令不是什么”特权指令“,而就是MOV,因此进程可以随意修改段寄存器,从而访问整个内存空间的内容。这种缺乏对内存空间保护的内存寻址模式被称为 实模式,与保护模式对应。
针对8086的缺陷,Intel从80286开始实现保护模式。同时,不久之后32位的80386CPU也研发成功了。从80386之后Intel的CPU历经80486、Pentium、Pentium Ⅱ等型号,虽然速度提升,但是结构并无重大改变,因此统称i386CPU。下面介绍i386系列的保护模式。
Intel选择了再段寄存器的基础上构筑保护模式的构思,并且保留段寄存器为16位(这样才可以利用原来的四个寄存器),但是又增添了2个新的段寄存器FS和GS。基本思路为:在保护模式下改变段寄存器的功能,使其从一个单纯的基地址(变相的基地址)变成指向这样一个数据结构的指针。这样,当一条访问内存指令发出一个内存地址时,CPU就可以这样归纳出实际应放上总线的地址:
根据指令的性质来确定应该使用哪一个段寄存器,例如转移指令中的地址在代码段(CS),而取数指令中的代码在数据段(DS),这一点和实模式相同。
根据段寄存器的内容,找出相应的”地址段描述结构“。
从地址段描述结构中的到基地址。
将指令中发出的地址作为位移,与段描述结构中规定的长度相比,查看是否越界。(保护模式)
根据指令的性质和段描述结构中的访问权限来确定是否越权。
将指令中的地址作为位移,与基地相加得出实际的“物理地址”。
在80386CPU中增加了2个寄存器,全局性的段描述表寄存器GDTR,和局部性的段描述表寄存器LDTR。访问这两个寄存器的指令被设置为专有指令,起到了保护作用。段寄存器的高13为用作访问段描述表中具体描述结构的下标。

每个段描述表项的大小是8字节,每个描述表项含有段的基地址和段的大小,在加上其他的一些信息。

B31--B24表示基地址(base)的高8位,B23-B0表示基地址的地24位。因为在一开始的实际中,Intel是采用了24位地址线,后来又改为32位地址。L19--L16 和 L15--L0表示段长,DPL是个2位的位段,代表访问本段需要的特权。

在80386的段内存管理的基础上,如果把每个段寄存器都指向同一个描述项,而将该描述项的基地址设为0,并将段长度设为最大,这样便形成了从0开始覆盖整个32位地址空间的一个整段,此时物理地址与逻辑地址相同。因为32位CPU的寄存器也为32位,可以对整个32位内存寻址。
i386的页式内存管理机制
因为在之前的设计中保护模式依赖于段式管理,所以Intel决定在段式内存的机制之上实现页式内存管理。80386把线性地址空间划分为4K字节的页面,每个页面可以被映射为物理存储空间中任意一块4K字节大小的空间(边界必须与4K字节对齐)。
由于页式管理的引入,对32位线性地址有了新的解释(以前就是物理地址):

可以看出,在页面目录中共有$2^{10}=1024$个目录项,每个目录项指向一个页面表,而每个页面表又共有1024个页面描述项。类似于GDTR和LDTR,又增加了一个新的寄存器CR3作为指向当前页面目录的指针,这样,从线性地址到物理地址的映射为:
- 从CR3取得页面目录的基地址。
- 以线性地址中的dir位段(22-31)为下标,在目录中取得相应页面表的基地址。
- 以线性地址中的page(12-21)位段为下标,在所得到的页面表中取得相应的页面描述项。
- 将页面描述项中的基地址与线性地址中的offset段相加,获得物理地址。

采用目录加页表的双层机制是处于节省空间的考虑。这样,我们只需留出必要的1024个目录项的空间,而没有被下使用的页表可以不创建。而如果采用单层记录,则需要留出必要的1024*1024个页表的空间,因为目录和页表都是基于偏移量来寻址的,必须留出整个数组的空间。
如前所述,目录项中含有一个指向页表的指针,而页表项中含有指向一个页面其实地址的指针。由于页面表和页面的起始位置总是在4K的边界上,所以低12位一定为0。这样,目录项和页表项中只要用20为用于指针就可以了。

Intel X86 32位CPU内存管理----《Linux内核源码情景分析》笔记(一)的更多相关文章
- Linux 内核源码情景分析 chap 2 存储管理 (四)
物理页面的使用和周转 1. 几个术语 1.1 虚存页面 指虚拟地址空间中一个固定大小, 边界与页面大小 4KB 对齐的区间及其内容 1.2 物理页面 与虚存页面相对的, 须要映射到某种物理存储介质上面 ...
- Linux内核源码情景分析-wait()、schedule()
父进程执行wait4,并调用schedule切换到子进程: wait4(child, NULL, 0, NULL); 像其它系统调用一样.wait4()在内核中的入口是sys_wait4().代码例如 ...
- Linux内核源码情景分析-系统调用
一.系统调用初始化 void __init trap_init(void) { ...... set_system_gate(SYSCALL_VECTOR,&system_call);//0x ...
- Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- 【转】Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- Linux内核源码分析方法_转
Linux内核源码分析方法 转自:http://www.cnblogs.com/fanzhidongyzby/archive/2013/03/20/2970624.html 一.内核源码之我见 Lin ...
- Linux内核源码分析 day01——内存寻址
前言 Linux内核源码分析 Antz系统编写已经开始了内核部分了,在编写时同时也参考学习一点Linux内核知识. 自制Antz操作系统 一个自制的操作系统,Antz .半图形化半命令式系统,同时嵌入 ...
- Linux内核源码特殊用法
崇拜并且转载的: http://ilinuxkernel.com/files/5/Linux_Kernel_Source_Code.htm Linux内核源码特殊用法 1 前言 Linux内核源码主要 ...
- linux内核源码注解
轻松学习Linux操作系统内核源码的方法 针对好多Linux 爱好者对内核很有兴趣却无从下口,本文旨在介绍一种解读linux内核源码的入门方法,而不是解说linux复杂的内核机制:一.核心源程序的文件 ...
随机推荐
- 用多个分隔符切分字符串---re.split()
问题/需求: 需要将字符串切分,但是分隔符在整个字符串中并不一致 (即:需要用多个分隔符切分字符串) str.split()方法不可行: 只支持单一分隔符,不支持正则及多个切割符号,不感知空格的数量 ...
- IntelliJ IDEA + Maven + Jetty + Jersey搭建RESTful服务
这次参考的是这个博客,完全按照这个我这里会出一些问题,一会再说就是了. https://www.cnblogs.com/puyangsky/p/5368132.html 一.首先新建一个项目,选择Ja ...
- springmvc原理详解(手写springmvc)
最近在复习框架 在快看小说网搜了写资料 和原理 今天总结一下 希望能加深点映像 不足之处请大家指出 我就不画流程图了 直接通过代码来了解springmvc的运行机制和原理 回想用springmvc用 ...
- getpost请求案例
public class MainActivity extends AppCompatActivity { private ListView lv; @Override protected void ...
- String与new String()的区别
JVM为了提升性能和减少内存开销,避免字符串的重复创建,维护了一块特殊的内存空间——字符串实例池. String赋值的两种方式. 1.String str = "test"; 以这 ...
- 记忆化搜索模板题---leetcode 1155. 掷骰子的N种方法
1155. 掷骰子的N种方法 这里有 d 个一样的骰子,每个骰子上都有 f 个面,分别标号为 1, 2, ..., f. 我们约定:掷骰子的得到总点数为各骰子面朝上的数字的总和. 如果需要掷出的总点数 ...
- 如何在onCreate中获取View的高度和宽度
如何在onCreate中获取View的高度和宽度 原文链接:http://mp.weixin.qq.com/s?__biz=MzAwODE1NTI2MQ==&mid=2247483676&am ...
- .NET Core下操作Git,自动提交代码到 GitHub
.NET Core 3.0 预览版发布已经好些时日了,博客园也已将其用于生产环境中,可见 .NET Core 日趋成熟 回归正题,你想盖大楼吗?想 GitHub 首页一片绿吗?今天拿她玩玩自动化提交代 ...
- 番茄日志发布1.0.3版本-增加Kafka支持
番茄日志(TomatoLog)能做什么 可能你是第一次听说TomatoLog,没关系,我可以从头告诉你,通过了解番茄日志,希望能帮助有需要的朋友,番茄日志处理将大大降低你采集.分析.处理日志的过程. ...
- pringboot pom文件引入本地jar包和对其打jar包
maven引入本地jar包需要在pom文件中天剑如下配置: <dependency> <groupId>com.baidu</groupId> <artifa ...