189 8069 5689

二、内存寻址(分页)-创新互联

硬件中的分页二、内存寻址(分页)

分页单元把线性地址转换成物理地址。把所请求的访问类型与线性地址的访问权限相比较,如果这次访问是无效的就产生一个缺页异常。

为昂昂溪等地区用户提供了全套网页设计制作服务,及昂昂溪网站建设行业解决方案。主营业务为网站设计制作、成都做网站、昂昂溪网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!

线性地址被分为固定长度的单位的组,成为页。页内部连续的线性地址被分映射到连续的物理地址中。内核可以指定一个页的物理地址和存取权限,而不用为每个地址指定存取权限。

分页单元把所有的RAM分成固定长度的页框,每个页框包含一个页,页框的长度与页的长度一致。页框是主存的一部分,因此也是一个存储区域,页是其中的数据块可以存放在任何页框或磁盘中。

把线性地址映射到物理地址的数据结构成为页表,页表存放在主存中,并在启用分页单元之前必须由内核对页表进行适当的初始化。

通过设置cr0寄存器PG标志启用PG=0时,线性地址被解释成物理地址。

常规分页

32位的线性地址被分成3个域:Directory 高10位;Table 中间10位;Offset 低12位;

使用这种二级模式的目的在于减少每个进程页表所需的RAM的数量。如果简单1级页表,则需要2^20个页表。二级模式通过只为进程实际使用的哪些虚拟内存区请求页表来减少内存使用量。每个活动进程必须有一个分配给它的页目录,只有在进程实际需要一个页表时才给该页表分配RAM会更有效率。

页目录项和页表项有同样的结构:

Present标志:表示该页是否存在于主存中。

Filed:包含该页框物理地址高20位字段。

Accessed:每当分页单元对相应页框进行寻址时就设置这个标志(操作系统完成)

Dirty:每当对一个页框写操作时设置。

Read/Write:页或页表的存取权限

User/Supervisor:特权级别

PCD和PWT:控制硬件高速缓存处理页或页表的方式

PAGE Size:之应用于也目录项,设置为1表示页目录指的是2m或4m的页框

GLobal:只用页表,防止页从TLB告诉缓存中刷出去

扩展分页

允许页框大小为4M而不是4kb,扩展分页用于将大段连续线性地址转换为对应的物理地址,内核可以不用中间页进行地址转换,从而节省内存并保留TLB项。

通过设置PAGE Size标志启用扩展分页:Directory 10 Offset 22

通过设置cr4寄存器的PSE标志能使扩展分页与常规分页共存。

硬件保护方案

由User、Supervisor标志孔子。若标志为0,处理器位于内核态才能访问;标志为1,总能对页寻址。

物理地址扩展(PAE)分页机制

处理器所支持的RAM容量受限于连接到地址总线上的地址管脚数。由于用户进程线性地址空间的需哟,内核不能直接对1G以上的RAM进行寻址。

64位系统中的分页

硬件高速缓存为了缩小CPU与RAM之间的速度不匹配,引入了硬件高速缓存

转换后援缓冲器(TLB) 用于加快线性地址转换。当一个线性地址第一次使用时,通过慢速访问RAM中的页表计算出相应的物理地址。同时物理地址被存放在TLB表项中,以便以后对同一地址进行再次访问。

Linux中的分页

从2.6.11开始,采用了四级分页模型

1、页全局目录(PGD)

2、页上级目录(PUD)

3、页中间目录(PMD)

4、页表(PT)

对于没有启用物理地址扩展的32位系统,两级页表已经足够了。Linux通过使PUD和PMD全为0,取消了页上级目录和页中间目录。不过他们在指针序列中的位置被保留,以便同样的代码在32位系统和64位系统下都能使用。内核为页上级目录和页中间目录保留了一个位置,通过把他们的目录项数目设置为1,并把这两个目录项映射到全局目录的一个适当的目录项而实现的。

启用了物理地址扩展的32位系统使用了3级页表。Linux的页全局目录对应页目录指针表(PDPT),取消了页上级目录,页中间目录对应80x86的页目录,Linux页表对应80x86的页表。

64位系统使用3级还是4级分页取决于硬件对线性地址位的划分。

线性地址到物理地址的转换使得下面的设计目标可行:

1、给每一个进程分配一块不同的物理地址空间,防止寻址错误。

2、区别页和页框的不同,页指数据块,页框指主存中的物理地址。允许存放在某个页框中的一个页,然后保存到磁盘上,以后重新装入这同一页时又可以被装在不同的页框中。这就是虚拟内存机制的基本要素。

每一个进程有他自己的页全局目录和页表集。当发生进程切换时,Linux把cr3控制寄存器的内容保存在前一个执行过程的描述符中,然后把下一而要执行的进程描述符装入cr3寄存器中。因此当新进程重新开始在cpu上执行时,分页单元指向一组正确的页表。

线性地址字段

PAGE_SHIFT 指定offset字段的位数。当用于80x86处理器时,值为12

PMD_SHIFT 指定线性地址的Offset字段和table字段的总位数,页中间目录可以映射的区域大小的对数。当PAE被禁用时,PMD_SHIFT值为22,当PAE被激活时,值为21

PUD_SHIFt 确定页上级目录能映射区域大小的位数。在80x86处理器上,PUD_SHIFT中时等价于PMD_SHIFT,PUD_SIZE则等于4m或2m

PGDIR_SHIFT 确定全局目录能映射的大小的对数。PGDIR_SIZE宏用于计算页全局目录中一个单独表项所能映射区域的大小。当PAE被禁止时,PGDIR_SHIFT等于22,PGDIR_SIZE为2^22或4m;PAE激活时,PGD_SHIFT产生的值为30,PGD_SIZE值为1g

PTRS_PER_PTE,PTRS_PER_PMD,PTRS_PER_PUD,PTRS_PER_PGD 用于计算页表项、页中间目录项、页上级目录项、页全局目录项中表项的个数。当PAE被禁止时,分别为1024,1,1,1024;当PAE激活时,值分别为512,512,1,4

页表处理

物理内存布局

在初始化阶段,内核必须建立一个物理地址映射来指定哪些物理地址范围对内核可用而哪些不可用(或者因为他们映射硬件设备I/O的共享内存,或者因为他们相应的页框还有BIOS数据)。

内核将下列页框标记为保留:

1、在不可用的物理地址范围内的页框

2、含有内核代码和已初始化的数据结构的页框

保留页框中的页决不能被动态分配或交换到磁盘上。

为什么内核没有安装在RAM第一个MB开始的地方?因为pc体系结构几个独特的地方必须考虑到:

1、页框0由BIOS使用,存放加电自检期间检查到的系统硬件配置。因此,很多膝上型电脑的BIOS甚至在系统初始化后还将数据写到该页框。

2、物理地址从0x000a0000到0x000fffff的范围通常留给BIOS例程,并且映射ISA图形卡上的内部内存:640k到1m之间著名的洞:物理地址存在但被保留,对应的页框不能被操作系统使用。

3、第一个m内的其他页框可能由特定计算机模型暴露。例如IBM Thinkpnd把0xa0页框映射到0x9f页框。

在启动过程的早期阶段,内核通过BIOS了解物理内存的大小,在新近的计算机中内核也调用BIOS过程建立一组物理地址范围和其对应的内存类型。随后内核执行machine_specific_memory_setup()函数,该函数建立物理地址映射。

内核可能不会见到BIOS报告的所有物理内存:例如,如果未使用PAE支持来编译,即使有更大的物理内存可供使用,内核也只能寻址4GB大小的RAM。setup_memory()函数在machine_specific_memory_setup()函数执行后被调用:它分析物理内存区域表并初始化一些变量来描述内核的物理内存布局。

为了避免把内核装入一组不连续的页框里,linux更愿跳过ram的第一个m。明确的说,linux用pc体系结构未保留的页框来动态存放所分配的页。

进程页表

进程的线性地址空间分成两部分:

1、从0x00000000到0xbffffff,无论进程运行在用户态还是内核态都可以寻址

2、从0xc0000000到0xffffffff的线性地址,只有内核态的进程才能寻址

当进程运行在用户态时,它产生的线性地址小于0xc0000000;当进程运行在内核态时,它执行内核代码,所产生的地址大于等于0xc0000000,但是,在某些情况下,内核为了检索或者存放数据必须访问用户态线性地址空间。

页全局目录的第一部分表项映射的线性地址小于0xc0000000(在PAE未启用时是前768项,PAE启用时是前3项),具体大小依赖于特定进程。在0xc0000000之后的表项对所有进程来说都应该是相同的,他们等于主内核页全局目录的相应表项。

内核页表

内核维持着一组自己使用的页表,驻留在所谓的主内核页全局目录中。主内核页全局目录的高目录项部分作为参考模型,为系统中每个普通进程对应的页全局目录项提供参考模型。

内核初始化自己的页表分为两个阶段:

1、内核创建一个有限的地址空间,包括内核的代码段、数据段、初始页表和用于存放动态数据结构的一共128k大小的空间这个最小限度的地址空间仅能够将内核装入ram和对其初始化的核心数据结构。

2、内核充分利用剩余的ram并适当的建立分页表。

临时内和页表

临时内核页全局目录实在内核编译过程中静态初始化的,而临时页表是有startup_32()汇编语言函数初始化的。

临时页全局目录放在swapper_pg_dir变量中。临时页表在pg0变量处开始存放,紧接在内核未初始化的数据段后面。

分页的第一个阶段的目标是允许在实模式下和保护模式下都能很容易得对内核寻址,假定是8m。

startup_32()函数通过向cr3控制寄存器张茹swapper_pg_dir的地址及设置cr0控制寄存器的PG标志启用分页单元。

当RAM小于896m时的最终内核页表

由内核页表所提供的最终映射必须把从0xc00000000开始的线性地址转化为从0开始的物理地址。宏__pa用于把从PAGE_OFFSET开始的线性地址转换成相应的物理地址,宏__va做相反的转化。

主内核页全局目录仍然保存在swapper_pg_dir变量中由paging_init()函数初始化。

由startup_32()函数创建的物理内存前8m的恒等映射用来完成内核的初始化阶段,当这种映射不再必要时,内核调用zap_low_mappings()函数来清除对应的页表项。

当RAM大小在896MB和4096MB之间的最终内核页表

linux在初始化阶段可以做的最好的事就是把一个具有896m的RAM窗口映射到内核线性地址空间。如果一个程序需要对现有的RAM的其余部分寻址,那就必须把某些其他的线性地址间隔映射到所需的RAM,即剩余的RAM留着不映射由动态映射来处理。

当RAM大于4096MB时的最终内核页表

页全局目录中的前三项与用户线性地址空间相对应,内核用一个空页的地址对这三项进行初始化。第四项用页中间目录的地址初始化,该页中间目录是通过调用alloc_bootmen_low_pages()分配的。页中间目录的前448项用RAM前896m的物理地址填充。

然后页全局目录的第四项被拷贝到第一项中,这样好为线性地址的前896m中的低物理内存映射做镜像。为了完成SMP系统的初始化,这个映射是必须的:当这个映射不再必要时,内核通过调用zap_low_mappings()来清除对应的页表项。

固定映射的线性地址

内核线性地址第四个GB的初始部分映射系统的物理内存,但是至少128m的线性地址总是留作他用,因为内核使用这些线性地址实现非连续内存分配和固定映射的线性地址。

固定映射线性地址可以映射任何物理地址,而由第4gb初始部分的线性地址所建立的映射是线性的(线性地址X映射物理地址X-PAGE_OFFSET)。

就指针变量而言,固定映射的线性地址更有效。间接引用一个指针变量比间接引用一个立即常量地址要多一次内存访问。此外,不需要像引用指针变量一样对值进行检查。

处理硬件高速缓存和TLB

为了使高速缓存的命中率达到最优化,内核在下列决策中考虑体系结构:

1、一个数据结构中最常用字段放在该数据结构内的低偏移部分,以便他们能够处于高速缓存中的同一行。

2、当为一大组数据结构分配空间时,内核试图把他们都放在内存中,以便所有高速缓存行按同一方式使用。


新闻标题:二、内存寻址(分页)-创新互联
网站链接:http://jkwzsj.com/article/pjisd.html

其他资讯