Linux内核内存管理
内核逻辑地址:开始于0xC000_0000(3G,在编译时指定,即PAGE_OFFSET=3G)处,是物理地址的线性映射,所以如此配置的32位CPU的可控内存最大值即为1GB。由于物理内存的低地址和高地址会留作他用,所以一般可用内存大小只有大约950MB。如果物理内存超过950MB,则在编译时要指定CONFIG_HIGHMEM4G和CONFIG_HIGHMEM64G。由于物理内存本身也是有页式内存管理,所以并不冲突。其线性地址仍然由页表来对应到具体的内存单元。
内核虚拟地址:是指整个1G的内核空间,其中包含了上面的内核逻辑地址以及超过内核逻辑地址空间的高端内存。这一块内存是为数量大于896MB的物理内存准备的,需要由kmap将内存映射到该区域上来使用,用完再用kunmap来释放。
逻辑地址应当是一种特殊的虚拟地址,他应该和段式内存管理对应起来。
内存转换: 逻辑地址 -> 线性地址 -> 物理地址
逻辑地址: = 段标识符 + 段内偏移量。为了兼容,将远古时代的段式内存管理方式保留了下来。
CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址,再利用其页式内存管理单元,转换为最终物理地址。 (http://bbs.chinaunix.net/thread-2083672-1-1.html)所谓的段式管理,就是把所有内存空间分为:数据段,代码段,系统段等等(可参考UBOOT里面的lds链接脚本)。每个段有一个描述符,称为段描述符。而段描述符又分为全局的(GDT, 用于系统或内核级),局部的(LDT, 用于进程级)。不同的内存空间的逻辑地址会取到不同 的段描述符,再从段描述符中取到段基地址,然后得到线性地址。linux的段式管理做了一定的简化,对于用户空间和内核空间来说,可以从代码看出,其基地址均为0,所以一个逻辑地址其实就=线性地址,因为线性地址=基地址(0)+offset=逻辑地址