Answers:
在32位架构上,用于寻址RAM的地址空间范围是:
0x00000000 - 0xffffffff
或4'294'967'295
(4 GB)。
linux内核将3/1(也可以是2/2,或1/3 1)分别划分为用户空间(高内存)和内核空间(低内存)。
用户空间范围:
0x00000000 - 0xbfffffff
每个新产生的用户进程都会在该区域内获得一个地址(范围)。用户进程通常是不受信任的,因此被禁止访问内核空间。此外,它们被认为是非紧急的,通常情况下,内核会尝试将内存分配推迟到那些进程。
内核空间范围:
0xc0000000 - 0xffffffff
内核进程在此处获取其地址(范围)。内核可以直接访问此1 GB地址(嗯,不是完整的1 GB地址,有128 MB保留用于高内存访问)。
内核空间中产生的进程是受信任的,紧急的并且假定没有错误,内存请求被即时处理。
每个内核进程也可以根据需要访问用户空间范围。为了实现这一点,内核将地址从用户空间(高内存)映射到其内核空间(低内存),上面提到的128 MB专门为此保留。
1拆分是3 / 1、2 / 2还是1/3,由CONFIG_VMSPLIT_...
选项控制;您可能可以在下面查看/boot/config*
以查看为内核选择了哪个选项。
首先要参考的是Linux设备驱动程序(可在线获得,也可以以书本形式获得),特别是第15章,其中有关于该主题的部分。
在理想的情况下,每个系统组件都将能够映射它需要访问的所有内存。Linux和大多数操作系统上的进程就是这种情况:32位进程只能访问少于2 ^ 32字节的虚拟内存(实际上,在典型的Linux 32位体系结构上约为3GB)。内核变得困难,内核需要能够映射正在执行其系统调用的进程的完整内存,整个物理内存以及任何其他内存映射的硬件设备。
因此,当32位内核需要映射超过4GB的内存时,必须在高内存支持下进行编译。高内存是指未永久映射到内核地址空间中的内存。(低内存是相反的:它总是被映射的,因此您只需在内核中取消引用指针就可以访问它。)
当您从内核代码访问高内存时,您需要kmap
首先进行调用,以从页面数据结构(struct page
)获取指针。kmap
无论页面是在高内存还是低内存中,调用均有效。还有一些kmap_atomic
增加了约束,但是在多处理器计算机上效率更高,因为它使用了更细粒度的锁定。通过获得的指针kmap
是一种资源:它占用了地址空间。完成后,您必须调用kunmap
(或kunmap_atomic
)释放该资源。则指针将不再有效,并且直到kmap
再次调用该页面的内容才能被访问。
这与Linux内核有关;我不确定任何Unix内核如何处理此问题。
高内存是用户空间程序可以寻址的内存段。它无法触摸内存不足。
低内存是Linux内核可以直接寻址的内存段。如果内核必须访问高级内存,则必须首先将其映射到其自己的地址空间。
最近引入了一个补丁,可让您控制段的位置。折衷方案是可以从用户空间中移走可寻址的内存,以便内核可以拥有更多的内存,在使用之前,这些内存不必映射。
其他资源:
HIGHMEM是内核内存空间的范围,但是它不是您访问的内存,而是您放置要访问的内容的地方。
典型的32位Linux虚拟内存映射如下:
0x00000000-0xbfffffff:用户进程(3GB)
0xc0000000-0xffffffff:内核空间(1GB)
(特定于CPU的向量以及此处忽略的所有内容)。
Linux将1GB内核空间分为LOWMEM和HIGHMEM两部分。拆分因安装而异。
如果安装为LOW和HIGH内存选择了512MB-512MB,则512MB LOWMEM(0xc0000000-0xdfffffff)在内核引导时静态映射;否则,该映射将自动生成。通常,物理内存的前几个字节用于此目的,因此该范围内的虚拟和物理地址的常量偏移量为0xc0000000。
另一方面,后者的512MB(HIGHMEM)没有静态映射(尽管您可以将页面半永久地保留在那里,但是您必须在驱动程序代码中明确地这样做)。相反,页面会在此处临时映射和取消映射,因此该范围内的虚拟和物理地址没有一致的映射。HIGHMEM的典型用途包括单次数据缓冲区。