《深入理解Linux内核》学习笔记——第二章(未完待续)
第二章 内存寻址
1.三种地址:在使用80x86处理器时(注意这是硬件!!!)一定要区分这三个地址,即逻辑地址(logical address)线性地址(linear address)也叫虚拟地址(virtual address),最后一个是物理地址(physical address)。依次解释下这三个地址:
逻辑地址:在机器语言指令中用来指定一个操作数或一条指令的地址。(这里的地址已经是机器语言指令的地址了!已经经过硬件MMU的转化了)每个逻辑地址都是由一个段和一个偏移量组成的!
线性地址:是一个用来表达高达4GB的地址,由16进制数字来表示,值得范围从0x00000000到0xffffffff,注意不管实际物理地址多大,都能得到一个4GB的地址,这样就为操作系统使用内存带来了方便。
物理地址:既是从微处理器地址引脚发送到内存总线上的电信号相对应。
2.这里要强调下:不同的处理器的MMU是不同的!!我们这里研究的是X86架构的处理器,该处理器的MMU是由分段分页两个单元组成的,但是譬如ARM处理器只有分页单元。所以我们在研究内存分配时要关注处理器的类型!!!!
3.硬件MMU,通过分段单元的硬件电路把一个逻辑地址转换成线性地址,再通过分页单元把线性地址转换成物理地址。要注意两点:一.所有的转化都是通过硬件电路实现的!!!二.对于操作系统来说这个转化是已经成功的,不需要过问的。
4.Intel X86处理器有两种方式执行地址转换,分别称为实模式(real mode)和保护模式(protected mode),我们主要探讨保护模式下的地址转化!!
5.接下来就要说硬件MMU是如何将逻辑地址转换成线性地址的。首先我们必须要知道我们的对象,再复习下,逻辑地址时由段和偏移量组成,而线性地址是一个4GB大小的空间。我们通过硬件分段单元来实现这一变化!接下来我们就要对准我们的对象,也就是逻辑地址。逻辑地址的前半部分我们称为段选择符(由于地址空间很庞大,我们不可能直接将地址空间的值写进去,于是我们给空间先标上号,再通过偏移来找到我们所需要的空间),段选择符帮我们找到段,再加上偏移量,就可以编程线性地址了。
6.我们把段选择符存放在段寄存器中,包括代码段寄存器cs,栈段寄存器ss,数据段寄存器ds,其中cs寄存器有个很重要的功能,就是表示当前CPU的特权级,0为最高优先级,3为最低优先级,Linux就用0和3来代表内核态和用户态!!!这里给出段选择符的结构:
前13位为索引号,TI代表访问的是GDT(全局描述符表)还是LDT(局部描述符表)
7.由上图可知,我们要想把逻辑地址转换成线性地址只用段选择符是不够的,我们还需要段描述符!!段描述符存放在全局描述符表(GDT)或局部描述符表(LDT)中,通常只定义一个GDT,而每个进程还需创建附加的段,就可以有自己的LDT。GDT存放在gdtr寄存器,正在被使用的LDT存放在ldtr寄存器。具体的段描述符的机构,贴一张图,但不仔细介绍了。
为了实现快速访问段描述符,我们采用了一种新的机制!!每当一个段选择符被装入段寄存器中,相应的段描述符就由内存装入到对应的非编程CPU寄存器。这样我们就不需要重复访问GDT/ LDT来获取段描述符。只有当段寄存器(也就是段选择符)发生变化时,我们才会重新访问GDT/LDT!!!!