<<深入理解linux内核>>读书笔记 (一): 内存寻址

来源:互联网 发布:excel标注重复数据 编辑:程序博客网 时间:2024/05/16 11:47

最近开始找工作了,看着一个封封简历石沉大海,人也变得浮躁起来,很久都没有看书了,这样还是不好的,我相信明天依然是明亮、绚丽的,哈哈,不能散失信心。。。

今天我将说下关于内存寻址方面的东西,因为我是学软件的,硬件知识很欠缺,这里也只能说说我的理解,有什么不对希望大家斧正哈。。

内存寻址

对于内存寻址我们先知道相应的几个概念:
物理地址:对于我们对硬件不是很懂的童鞋,这个我们就简单的理解为和内存条上的地址一一对应。其实他们之间是会有转化的,但这不是我们所关心的
逻辑辑地址:其实这个东西是和段式内存相对应的。在80X86 按段式内存的系统,其中很知名的MS-DOS和Windows 他们都是将程序分成多个段。而逻辑地址是由段地址和偏移地址组成;
线性地址: 对于这个概念,我觉得有很多人有不同的看法,我觉得其实呢?其中有说这个是和页式存储有关,对于这个观点我想通过下面两张图来说明我的观点:

图1:从逻辑地址到物理地址过程总览



图2:从逻辑地址到线性地址详细情况


对于第一张图在比较宏观的层面上表示的是逻辑地址通过段处理单元转化为线性地址(如果不支持分页技术,则线性地址就是物理地址),而线性地址又通过相应的页处理单元转化为物理地址。
对于图二:则是比较详细的讲解了从逻辑地址到线性地址的过程,至于图中详细介绍请往下继续:


硬件分段技术:



大家都知道逻辑地址由段地址和偏移量组成的。而这个段地址就是段选择描述符,由16位组成。其中段选择描述符结构如下:

图3:段选择器结构

那么为了能够快速检索到对应段的数据,系统提供了6中段寄存器,他们的唯一作用就是保存相应的段选择描述符。有一个例外就是cs段寄存器还有一个作用就是指定当前当前特权级别(CPL)。
要讲解图3结构,我们不得不说段描述符。
段描述符又8个字节组成,结构如下:

图4:段描述符结构

在这个数据结构体中,办厂了很多信息,但是呢,我们在这里只关心base这个字段,它表示了一个段开始位置的线性地址,看图2。
那请问段选择描述符怎么指向它所对应的段描述符的呢?
在这里我有必要解释下图3中结构的详细情况:
  1. 对于index域指定的是对应的在GDT(globle  descriptor table)中或者是在LDT( local descriptor table)中对应项,而GDT的地址是存放在gdtr控制寄存器中,而LDT则是存放在ldtr控制寄存器中。
  2. TI:如果TI被设置为0,那么说明段描述符在GDT中,反之说明在LDT中。
  3. RPL:指定当载入段选择描述符后,对应的cpu特权等级。
我相信到这一步,大家应该能够理解图2了吧。如果还不理解欢迎交流哈。。

Linux中的分段:

并不是所有时候发挥出硬件的能力,就会好过软实现。

在linux中就是这样,为了可移植性(因为很多其他非80X86芯片对分段并没有很好支持)和简化内存管理,linux 设计的时候对于分段是很有限制的,但是为了适应cpu架构,它还是用了段来满足相应的芯片要求,但是这种实现只是骗一骗cpu而已。。。。

在linux中划分了四个段:分别是用户代码段,用户数据段,内核代码段,内核数据段,而这些段的段描述符中的base字段都是指向同一个地方,那就是0x0000000。其实就是说linux中所有的地址都在一个段里面。

那么就说明了linux中逻辑地址和线性地址在数值上是一样大的。


硬件分页技术:

为了效率,一般将线性地址空间划分为固定大小(4K)我们称之为页。
而页处理模块将RAM划分为和页大小一致的存储空间叫做页框。注意和页的区别。
注意哦,可以在控制寄存器cr0中设置是否支持分页技术。
首先让大家看一张图,大家对将要将的东西有一个印象吧:


图5:分页寻址

接下来,我将要围绕这张图进行讲解。
对于图5,其实是对应的普通的分页寻址过程。
在图中,我们将线性地址分解为以下几部分:目录,表和偏移量,他们分别占有10位,10位和12位。、
寻址过程我在这里简单说一下:
  1. 从控制寄存器cr3中早到对应页目录所在页首地址
  2. 将线性的地址的22-31位乘以2^5 那么就对应到了目录中对应项。该项指定了页表。
  3. 如2所述,找到相应的页所在页框的地址
  4. 在该页上的对应offset上就找到了相应数据的物理地址。
对于目录和表在都具有相同的数据结构包括:
  1. Present 标记: 指示对应指向的页是否存在内存之中。
  2. 20位长度的区域指定:指定对应的页框的物理地址
  3. Accessed、Dirty。。。有需要找google
随着我们科技的进步,4G内存已经是不能满足我们的需要了,那么要扩大内存,首先需要的是增大地址寻址的范围。Intel公司顺势就提出了新的硬件支持用cpu36个引脚代替原来的32位引脚,这样的话,就可以将cpu的寻址范围从4G增大到64G的空间。
为了使用36个地址总线的空间,为了利用这写提升的空间,只能通过不同的分页机制来将32-bit的线性地址,转化为36-bit的物理地址。在奔腾pro处理器,intel提供了一种叫做Physical address extension(PAE)。PAE 可以在cr4控制寄存器设置是否有效,在page 目录entry有一个Page Size 的标志页面大小(当PAE有效则2MB每页)。


图6:PAE的分页模式


为了支持PAE,分页机制进行如下修改(结合着图6):
  1. 64G的内存被划分为2^24的页框,那么前面提到的目录和页表都含有12个标志位(在前面只是列举了几项哈),在加上现在寻址到唯一页框需要24位,那么总共需要36位,那么每一个页项由32位扩大到64位了,那么相应的在一个页框中只能存放512个页项而不是以前的1024个。
  2. 一个新的结构出现,PDPT(page directory pointer table)对应于线性地址的31,30位(如图),并且该结构又控制寄存器指向。
  3. 由于每页中的页项变长后,只能存放2^9个,那么对应的目录和页表只能对应于9位的线性地址了
对于他们的寻址运算过程:和普通的分页过程很类似,这里不讲了。

其实在这个地方我遇到了一个很迷惑的地方,就是线性地址是32位,没有改变,这样这个线性地址最多能够寻址4G的空间。那么PAE到底怎么样才能够寻址到64G的空间呢?
在网上找了半天后,在这个网站上知道http://en.wikipedia.org/wiki/Physical_Address_Extension,其实这个PAE是需要操作提供合作的,感觉是对于相应进程的,就是说一个进程只能占有相应的4G的线性地址空间。这只是一家之言哈。

Linux分页:

在linux中将线性地址分解为更多层次,包括:
  1. 全局目录
  2. 高级目录
  3. 中级目录
  4. 页表
这个几个层次。首先还是看图:

图7:linux分页

相信大家看到这张图的时候是不是感觉很亲切呢。原理和前面都是一样的,这里我就不再赘述了。


参考资料:
<<深入理解linux内核>>
原创粉丝点击