现在的位置: 首页 > 综合 > 正文

今天晚上,学习了地址管理的一点小总结

2013年09月04日 ⁄ 综合 ⁄ 共 2992字 ⁄ 字号 评论关闭

  最近几天,一直在看一个DD的source。发现,不理解一下地址的管理是不行了。晚上搜了一晚上,看了不少的文章,发现还是一知半解的。睡觉前,先把今天的领悟写出来吧:

  首先,逻辑地址。

  逻辑地址是段式管理相关的那个地址。什么代码段了,数据段了,的那个。

  其次,虚拟地址或线性地址。

  虚拟地址,是那个连续的2^32(32位机器)的那个地址。最终会通过分页管理,映射成物理地址。

  最后,物理地址。

  物理地址是与地址总线相关的那个地址。CPU用的就是这个地址。

  再总结一句,逻辑地址,是段式管理转换前的那个地址。逻辑地址或线性地址,是段式管理后,利用MMU进行页地址转换前的地址。物理地址,就是进行页地址转换后的地址了。

  ##########################################################################################

/* 下面是我觉得不错的一篇文章 */

  我们都知道,内核把线性地址(大多数情况也叫虚拟地址)分为三个部分:物理内存映射区,VMALLOC映射区以及固定映射地址区。这里主要讨论前两种。
所谓的物理内存映射区是指与物理内存一一映射的区域。举个例子来说,如果系统有物理内存512M,那么从0xc0000000至0xc00000000+512M的线性地址就属于物理内存映射区。这块线性地址在系统初始化时就与物理内存建立起一一对应的关系。这里的一一映射是指物理地址和线性地址就差一个偏移量0xc0000000,函数__pa()就是直接把线性地址减去0xc0000000得到物理地址。所以该函数应用范围也就局限于物理地址映射区。对另两个地址区进行__pa()是错误的。道理很简单,物理地址都没那么大。
VMALLOC映射区的特点是连续的线性地址,其物理地址不一定连续。这种映射特点和用户地址空间的映射方式是一样的。而前面讲的物理内存映射区,线性地址和物理地址显然都是连续的。
当然了,最后的映射肯定是指线性地址和物理地址之间的映射。所以这部分的线性地址最终也需映射到物理内存中。这就会和物理内存映射区产生冲突:因为所有的物理内存在物理内存映射区已经有了一个线性地址了。但是我们知道,物理内存并不是每时每刻都在使用的,也就是说虽然它已经映射了,但是还没有人使用它。那么我们可以在VMALLOC映射区中先映射到那些没使用的内存并锁住。这样这些内存就不会再被分配作为其他用途。所以虽然映射有冲突,但是没有两个线性地址在同时使用。
 因为VMALLOC映射区的线性地址和物理地址没有固定的映射关系,我们只能通过查找页表来找到对应的物理页框。值得一提的是,物理页框(struct page结构体)的vitual字段仍然存放的是物理内存映射区的线性地址,也就是说如果对该物理地址进行__page_to_vir()运算后,所得的线性地址不是VMALLOC映射区的线性地址
/* end */
###########################################################################

#################################################################################
/* 另一篇 */

1)凡是通过MMU页表访问的地址都叫虚拟地址,而一旦启用了MMU,那CPU发出的所有地址都是虚拟地址

内核用到的地址范围是3G-4G(不是很精确,与CPU体系有关吧),这当然就称为内核虚拟地址了(这跟用户态的0-3G的用户虚拟地址相对应),在3G-4G这段范围内,有段子集3G到3G+main_memory_size,这段主存大小的虚拟地址空间,由于在MMU页表映射时是采用的是平坦的线性映射,在LDD里所以又给她起个专门称呼,叫内核逻辑地址

2) 用不同名字分开叫的原因,与所有的名字的作用一样,是为了方便称呼,方便描述,因此可以说,在内核代码里,对于内核逻辑地址,你可以通过简单的偏移(3G),获晓对应的物理地址,而不是内核逻辑地址的那部分内核虚拟地址,是不能获晓物理地址的

就是假设你的物理主存是256M,总线地址为0-0x10000000(256M),那么虚拟地址就是0xC0000000(3G)-0xD0000000(3G+256M),换句话说,内核逻辑地址0xC0000000对应物理主存地址0,内核逻辑地址0xD0000000对应物理地址256M,那么从内核逻辑地址,就可以直接减去偏移量PHYS_OFFSET,比如为0xC0000000,就可以得到物理主存地址了,这种映射就叫做平坦的线性映射

/* end */
#####################################################################################

上面找的这两篇小文章中,都以内存256M为例来说明的(我严重怀疑这两篇有借鉴的嫌疑^_^),但是假设我有2G的内存或4G的内存呢?那内核怎么影射啊?这就是高端内存和低端内存的问题了。

#######################################################################################
/* copy from somewhere */

低端内存:存在逻辑地址的内存。(是指内核逻辑地址码?)

高端内存:是指那些不存在逻辑地址的内存。

在装有大量内存的32位系统中,内核逻辑地址和内核虚拟地址的不同将非常突出。由于使用32位地址最多同时能在4GB内存中寻址,因此直到最近,32位系统的linux仍被限制使用少于4GB的内存。

内核将4GB的虚拟地址空间分割为用户空间和内核空间,在二者的上下文中使用同样的映射。一个典型的分割是将3GB分配给用户空间,1GB分配给内核空间。内核代码和数据结构必需与这样的空间相匹配,但是占用内核地址空间最大的部分是物理内存的虚拟映射。内核无法直接操作没有映射到内核地址空间的内存。换句话说,内核对任何内存的访问,都需要使用自己的虚拟地址(内核仅有1GB地址空间)。因此许多年来,由内核所能处理的最大物理内存数量,就是将映射至虚拟地址内核部分的大小(1GB),再减去内核代码自身所占用的空间。因此,基于x86的linux系统所能使用的最大物理内存,会比1GB小一点。

为了使32位的处理器可以在大于4GB的物理空间寻址,处理器增添了“地址扩展”特性。然而有多少内存可以直接映射到逻辑地址的限制依然存在。只有内存的低端部分拥有逻辑地址,剩余部分(高端内存)没有逻辑地址。因此在访问特定的高端内存页前,内核必需建立明确的虚拟映射,使该页可在内核地址空间中被访问。因此许多内核数据结构必须被放置在低端内存中;而高端内存更趋向于为用户空间进程页所保留

/* end copy */
##########################################################################

地址到了这里,我感觉比起今天下午来,我的理解深了不少。
另外,还有总线地址,BCU等,还不是很清楚。这地方水真深啊。有时间,再去研究研究!

抱歉!评论已关闭.