linux进程页表_Linux页框分配器

最近在学习内核模块的框架,这里做个总结,知识太多了。

分段和分页

先看一幅图

6e4a155601f5891783fb3f1256b0f3dc.png

也就是我们实际中编码时遇到的内存地址并不是对应于实际内存上的地址,我们编码中使用的地址是一个逻辑地址,会通过分段和分页这两个机制把它转为物理地址。而由于linux使用的分段机制有限,可以认为,linux下的逻辑地址=线性地址。也就是,我们编码使用的是线性地址,之后只需要经过一个分页机制就可以把这个地址转为物理地址了。所以我们更重要的可能是去说明一下linux的分页模型。

系统会将整个物理内存分为多个页框,每个页框大小一般是4K(硬件允许的扩展分页(PSE)情况下也可设置为4M,不过linux并不使用PSE,而可能使用PAE),也就是如果我们有1GB的物理内存,系统就会将这个物理内存分为262144个页框。当我们提供一个线性地址时,系统就会通过分页机制将这个线性地址转换为对应于某个物理页中的某个内存地址。下图是linux的分页模型

7aee35fa8650513ee19f20df3faf95cd.png

linux采用四级分页模型,这四种页表是:页全局目录(PGD)、页上级目录(PUD)、页中间目录(PMD)、页表(PTE)。这里的所有页全局目录、页上级目录、页中间目录、页表,它们的大小都是一个页。linux下各个硬件上并不一定都是使用四级目录的,当使用于没有启动物理地址扩展(PAE)的32位系统上时,只使用二级页表,linux会把页上级目录和页中间目录置空。而在启用了物理地址扩展的32位系统上时,linux使用的是三级页表,页上级目录被置空。而在64位系统上,linux根据硬件的情况会选择三级页表或者四级页表。这个整个由线性地址转换到物理地址的过程,是由CPU自动进行的。

每个进程都有它自己的页全局目录,当进程运行时,系统会将该进程的页全局目录基地址保存到cr3寄存器中;而当进程被换出时,会将这个cr3保存的页全局目录地址保存到进程描述符中。之后我们还会介绍一个cr2寄存器,用于缺页异常处理的。当进程运行时,它使用的是它自己的一套页表,当它通过系统调用或陷入内核态时,使用的是内核页表,实际上,对于所有的进程页表来说,它们的线性地址0xC0000000以上所涉及到的页表都是主内核页全局目录(保存在init_mm.pgd),它们的内容等于主内核页全局目录的相应表项,这样就实现了所有进程的进程空间相互隔离,但是内核空间相互共享的情况。当某个进程修改了内核页表的一些映射情况后,系统只会相应的修改主内核页全局目录中的表项(只能修改高端内存中非连续内存区的映射),当其他进程访问这些线性地址时,会出现缺页异常,然后修改该进程的页表项重新映射该地址。

因为说到每个进程都有它自己的页全局目录,如果有100个进程,内存中就要保存100个进程的整个页表集,看起来会耗费相当多的内存。实际上,只有进程使用到的情况下系统才会分配给进程一条路径,比如我们要求访问一个线性地址,但是这个地址可能对应的页上级目录、页中间目录、页表和页都不存在的,这时系统会产生一个缺页异常,在缺页异常处理中再给进程的这个线性地址分配页上级目录、页中间目录、页表和页所需的物理页框。

地址空间

一个线性地址经过分页机制转为一个对应的物理地址,我们称之为映射,比如我们的一个线性地址0x00000001经过分页机制处理后,对应的物理地址可能是0xffffff01。

在linux系统中分两个地址空间,一个是进程地址空间,一个是内核地址空间。对于每个进程来说,他们都有自己的大小为3G的进程地址空间,这些进程地址空间是相互隔离的,也就是进程A的0x00000001线性地址和进程B的0x00000001线性地址并不是同一个地址,进程A也不能通过自己的进程空间直接访问进程B的进程地址空间。而当线性地址大于3G时(也就是0xC0000000),这里的线性地址属于内核空间,内核地址空间的大小为1G,地址从0xC0000000到0xFFFFFFFF。在内核地址空间中,内核会把前896MB的线性地址直接与物理地址的前896MB进行映射,也就是说,内核地址空间的线性地址0xC0000001所对应的物理地址为0x00000001,它们之间相差一个0xC0000000。

linux内核会将物理内存分为3个管理区,分别是:

  • ZONE_DMA:包含0MB~16MB之间的内存页框,可以由老式基于ISA的设备通过DMA使用,直接映射到内核的地址空间。
  • ZONE_NORMAL:包含16MB~896MB之间的内存页框,常规页框,直接映射到内核的地址空间。
  • ZONE_HIGHMEM:包含896MB以上的内存页框,不进行直接映射,可以通过永久映射和临时映射进行这部分内存页框的访问。

整个结构如下图

e58299852d696b8be920b05f1ee6efae.png

对于ZONE_DMA和ZONE_NORMAL这两个管理区,内核地址都是进行直接映射,只有ZONE_HIGHMEM管理区系统在默认情况下是不进行直接映射的,只有在需要使用的时候进行映射(临时映射或者永久映射)。

结点和管理区描述符

为了用于NUMA架构,使用了node用来描述一个地方的内存。对于我们PC来说,一台PC就是一个node。node用struct pglist_data结构表示:

/* 内存结点描述符,所有的结点描述符保存在 struct pglist_data *node_data[MAX_NUMNODES] 中 */typedef struct pglist_data { /* 管理区描述符的数组 */ struct zone node_zones[MAX_NR_ZONES];  /* 页分配器使用的zonelist数据结构的数组,将所有结点的管理区按一定的关联链接成一个链表,分配内存时会按照此链表的顺序进行分配 */ struct zonelist node_zonelists[MAX_ZONELISTS]; /* 结点中管理区的个数 */ int nr_zones;#ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */ /* 结点中页描述符的数组,包含了此结点中所有页框描述符,实际分配是是一个指针数组 */ struct page *nod
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值