标签:any linu http vol 位置 chm 内核 png evel
? Linux内核的设计要考虑在各种不同的CPU上的实现,还要考虑64位CPU,所以不能仅仅针对i386结构来设计它的映射机制,要以一种假象的、虚拟的CPU和MMU(内存管理单元)为基础,设计出一种通用模型。在32位的内存空间下,两层映射系统比较有效,但是在64位内存空间下,两层映射会降低内存空间的效率。因此,Linux内核的映射机制设置为三层,在页面目录和页面表之间加入了一层“中间目录”。PGD、PMD、PT均为数组。相应的,在逻辑上也把线性地址从高到低划分为4个位段,分别用作目录PGD中下标、中间目录PMD中的下标、页面表中的下标、以及物理页面内的位移。
? 但是,这个虚拟的映射模型必须落实到具体的CPU和MMU物理映射机制。这里主要介绍了32位地址的二层映射:
#define PGDIR_SHIFT 22 //线性地址中PGD下标的起始位置,PGD位于线性地址的最高字段,因此PGD位22位到31位,一共10位。
#define PTRS_PER_PGD 1024 //PGD表中指针的个数位1024个,2的10次方。在32位系统中指针大小为4字节,因此PGD表大小4KB
/*
* The i386 is two-level,so wo don't really have any
* PMD direcotary physically.
*/
#define PMD_SHIFT 22 //PMD下标起始位置也为22,表示PMD长度为0。每个PMD表项的大小和PGD是一样的。
#define PTRS_PER_PMD 1 //每个PMD表中只有一个PMD表项,只有一个PT表指针。
#define PTRS_PER_PTE 1024
? 这样,上述的4步映射过程对于内核(软件)和i386MMU就成为:
? 32位地址意味着4G字节的虚拟空间,Linux内核将最高的1G(虚地址 0xC0000000~0xFFFFFFFF)用于内核本身,称为“系统空间”,剩下的3G的空间(虚地址 0x0~0xBFFFFFFF)用作各个进程的“用户空间”。
? 虽然系统空间占据了最高的1G空间,但是物理的内存总是从最低的地址开始。因此,对于内核来说,其地址的映射是简单的线性映射:
#define __PAGE_OFFSET (0xC0000000)
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
? 每个进程都有自己的页面目录表PGD,在切换进程时也要将进程的PGD加载到CR3寄存器中,而内核记录的是PGD的虚拟地址,CR3需要的是物理地址,这时候就要用到__pa()了:
asm volatile("movl %0,%%cr3": :"r"(__pa(next->pgd)));//next->pgd 表示下一个进程的页面目录起始地址。
《Linux源码情景分析》--2.1 Linux内存管理的基本框架
标签:any linu http vol 位置 chm 内核 png evel
原文地址:https://www.cnblogs.com/LiShiZhen/p/11494448.html