本文主要介绍linux内存寻址的切分机制,有助于linux内核的编程和开发。





一、前言

在Linux内核的研究,读内存寻址的Linux内核的深刻理解篇章。我以为我已经了解的分段分页机制,发现是一个半知识的结果。因此,大量的信息被发现,与记忆解决知识终于理顺了。现在,我记录我的理解,我希望核心的学习者有一定的帮助,同时也希望你指出错误的地方。

两。到底发生了什么事

我相信谁都知道了操作系统课程的分段分页,但奇怪的是,这本书没有提及如何分段分页应运而生,这使我们知道,接下来,我们首先挑选机制的历史。

实模式的诞生(16位处理器和寻址)

在8086处理器的诞生,内存寻址方式是直接访问物理地址。8086处理器扩展地址总线为20位,地址1M的内存空间。然而,一个尴尬的问题出现,ALU仅是16位的,是无法计算的,ALU的20位地址。为了解决这一问题,分段机制引入历史舞台。

支持分割,8086处理器设置四段寄存器CS,DS,SS,和ES。每段登记为16位,并在指令内存地址也是16。然而,在地址总线发送到地址总线,CPU首先将其添加到某段登记的价值。这里要注意:段登记价值相当于16个20位地址总线,所以当和实际上除了高12和段寄存器16位的内存总线,而低4位保持不变,从而形成一个实际的地址20,将实现从16位到20位的内存地址转换为物理地址的映射,或;。

保护模式的诞生(32位处理器和寻址)

80286处理器的地址总线为24位,地址空间是16M,而保护模式介绍(这个内存段的访问是有限的)。

80386处理器是32位处理器的ALU和地址总线都是32位,地址空间是4G。也就是说,它可以直接没有分割机制访问4G的内存空间,虽然它是新时代的小王子,它超越了无数的前辈,然而,它需要承担家族的使命,就是,前者处理器兼容。也就是说,它必须支持真正的保护模式。因此,80386段的登记的基础上,构建了保护模式,而16位登记保留。

因为处理器80386后,结构基本相似,统称为IA32(32位英特尔架构)。

三、IA32存储器寻址机制

可寻址硬件

在8086的实模式下,段寄存器移到4位,然后添加到内存总线直接与地址addr。可寻址的地址是存储单元的物理地址,在程序的地址称为逻辑地址(或虚拟地址)。在IA32保护模式下,逻辑地址是不能直接送到内存总线,但送到内存管理单元(MMU),内存管理是由一个或一组芯片功能映射逻辑地址到物理地址,即地址转换,如图所示。


三种地址调用

逻辑地址:机器语言指令仍然使用这个地址来指定一个操作数或一条指令的地址的一个地址,寻址方式在英特尔的分段结构,特别是具体的,它允许MS-DOS或Windows程序员把程序划分成若干段,每一个逻辑地址由段地址和偏移。

线性地址:线性地址是一个32位无符号整数,可以表达为232个地址(4GB),线性地址通常是16进制表示,它的范围是从0x00000000到0xffffffff。

物理地址:用于存储芯片级存储器单元的存储器单元的实际地址。物理地址也用32位无符号整数表示。

MMU的地址变换过程

MMU的硬件电路,它由两部分组成,一是分段部件和其他的分页组件。在这里,我们分别将它们称为分段机制和分页机制,从逻辑的角度来理解硬件的实现机制,分割机制将逻辑地址转换为线性地址,然后分页机制将线性地址转换为物理地址。


mmu_translate
调用段登记

有六个16位寄存器调用:CS,DS,SS,ES,FS,GS。不像8086段登记,登记不再是一个段的基地址,而是选择某段。

四,分段机制的实现。

该段是虚拟地址空间的基本单元,分割机制必须将虚拟地址空间的地址转换成线性地址空间的线性地址。

要实现这种映射,仅使用段寄存器来确定基本地址是不够的,至少要描述段的长度,还需要段的其他信息,如访问权限等。因此,这里需要的是一个数据结构,包括三个方面:

1的基址。段(基地址):线性地址空间中段的起始地址。

2。段限制(限制):可在虚拟地址空间中的段中使用的最大偏移量。

3。段保护属性(属性):表示段的特征。例如,片段是否可以被读或写,或者段是否被作为程序执行,以及段的特权,等等。

上面的数据结构称为段描述符,由多个段描述符组成的表称为段描述符表。

段描述符

一个描述符(描述)是一个8字节的存储单元,描述了一个段的属性。在实模式下,段的财产无非是代码段,堆栈段,数据段的段地址开始,线段长度,等等,但它是更复杂的保护mode.ia32结合多个8字节,称为描述符。


从图中可以看到,段描述符指出了段的32位和20位边界(即段的长度)。这里我们只关注基本地址和段边界,而其他属性则跳过。

1。段描述符表

用户各种描述符和系统描述符放在相应的全局描述符表,局部描述符表和中断描述符表,描述符表(即一段表)定义了IA32系统的所有段,描述符表占据一个字节的内存空间8。空间的大小是8字节(包括至少一个描述符)64K字节(最多8K)描述符。

2。全局描述符表(GDT)

全局描述符表GDT(全局描述符表),除了任务门,中断门和活板门描述符,包含那些段系统中的所有任务共享描述符。它的第一个8字节的位置是没有用的。

三.中断描述表IDT(中断描述符表)

中断描述符表IDT(中断描述符表),其中包含256门descriptors.idt只能包含任务门,中断门和活板门描述符。虽然长的IDT表也可以64K字节,它只能访问描述符在2K字节,即256个描述符,这是兼容8086。

局部描述符表(LDT)

局部描述符表,LDT(局部描述符表),包含一个给定的任务相关的描述符,每个都有一个LDT,LDT,给定任务的代码和数据可以从其他任务中分离出来。每个任务的局部描述符表LDT也是由描述符代表。它被称为LDT描述符,其中包含局部描述符表信息和放在全局描述符表GDT。

总结

内存寻址机制调用完成了从逻辑地址mdash,线性地址和物理地址的转换等等,其中,逻辑地址段寄存器中的段描述符提供的价值,然后得到段基址和段边界的段描述符,然后添加偏移对逻辑地址,得到线性地址,通过分页机制把线性地址的物理地址。

首先,我们要明确分割机制是寻址方式由IA32,这是硬件水平。也就是说,无论你是Windows或Linux,只要你使用IA32 CPU访问内存,你必须通过MMU转换过程中得到的物理地址,也就是说,你必须通过逻辑地址mdash,线性地址和物理地址的转换等等。

五和Linux中分段的实现

事实上有关于分割机制,实施了这么多,没有鸡蛋的Linux版本。因为Linux不使用分段机制,或Linux分割机制的设计必须的硬件兼容IA32。

英特尔的微处理器市场机制提出了8086,当了段机制来解决从16位地址CPU内部的20位真实地址。为了保持这种兼容性,386仍然使用段机制,但远比以前更复杂。因此,Linux内核的设计不完全采用英特尔提供的分割方案,只有少数的分割机制用于在有限的程度上,这不仅简化了Linux内核的设计,而且对Linux移植到其他平台创造了条件,因为许多RISC处理器不支持段机制。然而,理解的市场机制的知识是唯一进入Linux内核的方法。

从2.2版,Linux允许所有进程(或任务)使用相同的逻辑地址空间,所以没有必要使用局部描述符表LDT。但公司也用在内核,只能运行在vm86模式的酒,因为那是说,它是用来在Linux上运行Windows软件或DOS程序。

在IA32任何地址是虚拟地址,即通过任何地址方式:选择:偏移这是段机制访问模式的基本特征,所以它是不可能避免的设计在IA32操作系统时使用段机制。一个虚拟地址最终将通过转化为一个线性地址,段基地址+偏移。然而,因为大多数的硬件平台不支持分段机制和分页机制的支持,为了使Linux具有更好的可移植性,我们需要删除段机制和使用分页机制只。不幸的是,IA32规定段机制是不禁止的,所以这是不可能绕过它直接给出了线性地址空间的地址。无奈之下,Linux的设计者让段的基地址是0,而该段的限制是4GB。当一个偏移量是给定的,方程是0 +偏移量=线性地址,偏移=线性地址此外,由于部分机制;< 4gb偏移;偏移,所以从不同ffffffff小时范围,这正是线性地址空间,也就是说虚拟地址直接映射到线性地址、虚拟地址在我们未来的提及和线性地址指向同一个地址。看来,Linux巧妙地通过一段段机制机制的缺失。

此外,由于IA32段机制还规定,我们必须为代码段和数据段创建不同的段,Linux必须创建一个0的基地址和代码段和数据段的段的段描述符分别为4GB。不仅如此,由于Linux内核上运行的特权级0,与用户程序在3级权限运行,根据保护机制的部分IA32规定,程序不能访问特权级3特权级0段,所以Linux内核代码必须创建用户程序和数据段,这意味着Linux必须创建4段描述符mdash;mdash;代码段和数据段权限级别0、代码段和权限级别3的数据段的ENT。

六。总结

分段机制是IA32架构CPU的特点,而不是操作系统寻址模式的必然选择。为了跨平台,Linux是巧妙的绕过段机制,主要使用分页机制来解决。