Linux page与addr分析

本文介绍了计算机体系架构中各种地址的概念,如物理地址、虚拟地址、逻辑地址和线性地址,以及它们在32位和64位系统中的差异。文章特别强调了MMU在地址转换中的作用,以及页表和多级页表如何节省空间。此外,还提到了总线地址在DMA操作中的重要性及其与物理地址的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

对于刚开始接触计算机体系架构的同学,各种地址很难分辨清楚,本文总结在操作系统中常用的各种地址,以及他们之间的转换关系,供以后复习使用

二、各种地址总结

物理地址Physical Addr

物理地址内核空间表示为phy_addr_t

  • 作用
    内存在总线上的实际地址,未开启MMU的CPU,或者MMU可以通过物理地址访问内存。
    地址总线设置为物理地址,数据总线便能够访问到物理地址对应的内存空间。

虚拟地址Virtual Addr

内核空间直接用(void *)表示,是一个unsigned long的数
用户空间的虚拟地址空间,在内核中表示为struct vm_area_struct

  • 作用
    开启MMU之后的CPU,使用的均是虚拟地址。
    CPU地址总线访问的虚拟地址,将传输到MMU,MMU查找页表,将其转换成为物理地址,间接访问实际的内存空间。
  • 32位虚拟地址的位含义
    虚拟地址在32位系统中,共32位,从高到底分为四层含义PGDPMDPTEOFFSET
    PGD:占10bit,表示当前页表寄存器(CR3)指向的地址,含有1024个pgd_t
    PMD:占0bit,表示pgd_t中仅含有1个pmd_t
    PTE:占10bit,表示pmd_t中含有1024个pte_t
    OFFSET:占12bit,表示一个pte_t大小为4096 bits。
    可以看出,寻址过程总是利用上级目录提供一个表,再利用虚拟地址中的地址,查询到下级目录表的物理地址,并进行递归。
  • 64位虚拟地址
    64位虚拟地址与32位类似,但是支持更多的位,也就支持更大的内存空间。
    并且还有部分bits处于未定义的状态,为未来的系统发展预留空间。

逻辑地址

程序编译出来时,所有的段segement,地址都是从零开始的,这个地址称为逻辑地址

线性地址

程序最终链接时,所有的逻辑地址,都需要加上自己所在的段偏移地址,便得到线性地址,这个线性地址在Linux中也就是虚拟地址
值得注意的是,逻辑地址与线性地址,都是X86-32中独有的说法,其他很多体系架构并没有这两个东西,Linux只关心虚拟地址。

总线地址

总线地址在内核空间表示为dma_addr_t,相当于DMA设备眼中的物理地址。
深入理解Linux内核中,有这样一句话

在PC体系结构中,总线地址和物理地址是一致的,但是在其他的体系结构中,这两种地址可能是不同的。

DMA操作中,数据不需要CPU的参与,I/O设备与DMAC直接驱动数据总线,因此内核开始DMA操作时,必须把所涉及的内存缓冲区总线地址写入DMAC适当的I/O端口,或者写入I/O设备适当的I/O端口。

在Linux内核中,表示总线地址的就是dma_addr_t。尽管dma_addr_t很多时候和物理地址相同。

页表Page Table

我们通常意义上的一级页表,就是指数据结构pte_t

页表的具体实现,与计算机体系架构有关,这里我们列出一个比较典型的3级页表的例子

/* include/asm-generic/page.h */
/* pte_t --> Page Table Entry,页表项 */
typedef struct {
	unsigned long pte;
} pte_t;
/* pmd_t --> Page Middle Entry, 页中间目录项 */
typedef struct {
	unsigned long pmd[16];
} pmd_t;
/* pgt_t --> Page Global Entry, 页全局目录项 */
typedef struct {
	unsigned long pgd;
} pgd_t;
/* 用于表示页表属性flag的数据结构,仅低12bits有效,对应pte_t的低12位,仅仅是方便编程 */
typedef struct {
	unsigned long pgprot;
} pgprot_t;
typedef struct page *pgtable_t;
  • 作用
    MMU读取并查询,以便将虚拟地址,转换为物理地址。
    页表由CPU写,由MMU读,存放在内存RAM中。
  • pte_t格式
    从数据结构可以看出,页表pte_t也就是一个unsigned long,在32bits系统中也就是32位;
    它的高20bits代表页面号,页面号左移12位,再加上一个偏移值,就可以得到页面的物理地址。
    它的低12bits是一些页面标志,如我们常见的读、写、执行权限等。
  • 缺页异常
    pte_t低12位的标志位中,包括一个bit-PTE_V,用于指示页表是否存在,当MMU解析虚拟地址时,如果PTE_V指示页表不存在,则MMU会向CPU发出page_fault异常。
  • pgd_tpmd_t格式
    pte_t类似,pgd_tpmd_t两者的高20bits都是一个物理页面号,低12bits表示标志位。
    pgd_t中的页面号,指向了一个pmd_t表所在的物理页面。
    pmd_t中的页面号,指向了一个pte_t表所在的物理页面。
  • 四级页表
    额外增加一层页表PUD,位于PGDPMD之间,原理类似,不多言。
  • 为什么多级页表可以节省空间?
    因为一个进程,大多数页面通常是不使用的。
    比如1024个pte_t,就要占1024个字节。
    如果采用了pmd_t,那么1024个不使用的pte_t,可以归纳为1个不使用的pmd_t,仅占一个字节。由于pmd_t是不使用的,因此pmd_t下面可以暂时不分配pte_t数据结构,也就起到了节约空间的作用。
    值得注意的是,如果1024个pte_t都是被使用的,那么pmd_t就无法起到节省空间的作用了,相反,还会增加pmd_t本身1个字节的开销。

page

/* include/linux/mm_types.h */
struct page {
	/* 内容较多,仅列部分 */
};
  • 作用
    管理每个物理页状态以及其他属性,一页的大小为4096 Bytes。
  • 存放位置
    存放在内存中。根据体系结构够不同,存放的具体位置也不同。
    最简单的FLATMEM中,所有的page存放在一个全局变量struct page *mem_map中。
    mem_map数组,存放在内存的线性映射区,只需要加上地址偏移,便可直接得到物理地址。
  • 和各种地址的关系
    page是用来管理物理的的数据结构,内核使用伙伴系统分配的,就是这个数据结构。与各种地址没有直接关系。

三、总结

本文梳理了各项计算机术语种出现的地址,分析了他们与页表之间的关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值