linux内核探索之内存管理(四):对页表和页表项的操作

接上一节,主要参考《深入Linux内核架构》(3.3节),即linux-3.18.3

1. 对PTE的操作

    最后一级页表中的项不仅包含了指向页的内存位置的指针,还在上述的多于比特位包含了与页有关的附加信息。尽管这些数据是特定于CPU的,它们至少提供了有关页访问控制的一些信息。下列位在linux内核支持的大多数CPU中都可以找到。

    
arch/x86/include/asm/pgtable_types.h 

#define _PAGE_BIT_PRESENT       0       /* is present */
#define _PAGE_BIT_RW            1       /* writeable */
#define _PAGE_BIT_USER          2       /* userspace addressable */
#define _PAGE_BIT_PWT           3       /* page write through */
#define _PAGE_BIT_PCD           4       /* page cache disabled */
#define _PAGE_BIT_ACCESSED      5       /* was accessed (raised by CPU) */
#define _PAGE_BIT_DIRTY         6       /* was written to (raised by CPU) */
#define _PAGE_BIT_PSE           7       /* 4 MB (or 2MB) page */
#define _PAGE_BIT_PAT           7       /* on 4KB pages */
#define _PAGE_BIT_GLOBAL        8       /* Global TLB entry PPro+ */
#define _PAGE_BIT_SOFTW1        9       /* available for programmer */
#define _PAGE_BIT_SOFTW2        10      /* " */
#define _PAGE_BIT_SOFTW3        11      /* " */
#define _PAGE_BIT_PAT_LARGE     12      /* On 2MB or 1GB pages */
#define _PAGE_BIT_SPECIAL       _PAGE_BIT_SOFTW1
#define _PAGE_BIT_CPA_TEST      _PAGE_BIT_SOFTW1
#define _PAGE_BIT_SPLITTING     _PAGE_BIT_SOFTW2 /* only valid on a PSE pmd */
#define _PAGE_BIT_HIDDEN        _PAGE_BIT_SOFTW3 /* hidden by kmemcheck */
#define _PAGE_BIT_SOFT_DIRTY    _PAGE_BIT_SOFTW3 /* software dirty tracking */
#define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
#define _PAGE_BIT_NUMA          (_PAGE_BIT_GLOBAL+1)
#define _PAGE_BIT_PROTNONE      _PAGE_BIT_GLOBAL
#define _PAGE_BIT_FILE          _PAGE_BIT_DIRTY

#define _PAGE_PRESENT   (_AT(pteval_t, 1) << _PAGE_BIT_PRESENT)
#define _PAGE_RW        (_AT(pteval_t, 1) << _PAGE_BIT_RW)
#define _PAGE_USER      (_AT(pteval_t, 1) << _PAGE_BIT_USER)
#define _PAGE_PWT       (_AT(pteval_t, 1) << _PAGE_BIT_PWT)
#define _PAGE_PCD       (_AT(pteval_t, 1) << _PAGE_BIT_PCD)
#define _PAGE_ACCESSED  (_AT(pteval_t, 1) << _PAGE_BIT_ACCESSED)
#define _PAGE_DIRTY     (_AT(pteval_t, 1) << _PAGE_BIT_DIRTY)
#define _PAGE_PSE       (_AT(pteval_t, 1) << _PAGE_BIT_PSE)
#define _PAGE_GLOBAL    (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
#define _PAGE_SOFTW1    (_AT(pteval_t, 1) << _PAGE_BIT_SOFTW1)
#define _PAGE_SOFTW2    (_AT(pteval_t, 1) << _PAGE_BIT_SOFTW2)
#define _PAGE_PAT       (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
#define _PAGE_SPECIAL   (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
#define _PAGE_CPA_TEST  (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
#define _PAGE_SPLITTING (_AT(pteval_t, 1) << _PAGE_BIT_SPLITTING)

_PAGE_PRESENT:指定了虚拟内存页是否存在于内存中。页可能换出到交换区。

_PAGE_ACCESSEDCPU每次访问页时,会自动设置_PAGE_ACCESSED。内核会定期检查该比特位,以确认页使用的活跃程度。不经常使用的页更适合换出。在读写访问之后设置该比特位。

_PAGE_DIRTY表示该页是否是“脏的”,即页的内容是否已经修改过。

_PAGE_FILE的数值与_PAGE_DIRTY相同,但用于不同的上下文,即页不在内存中的时候。不存在的页不可能是脏的,因此可以重新解释该比特位。如果没有设置,则该项指向一个换出页的位置。如果该项属于非线性文件映射,则需要设置_PAGE_FILE

_PAGE_USER:是否允许用户空间代码访问。不设置只能在内核态访问。

_PAGE_READ_PAGE_WRITE_PAGE_EXECUTE指定了普通的用户进程是否允许读取、写入、执行该页中的及其代码。

内核内存中的页必须防止用户进程写入。但即使属于用户进程的页,页无法保证可以写入。对于访问权限粒度没有那么细的体系结构而言,如果没有进一步的准则可区分读写访问权限,则会定义_PAGE_RW常数,用于同事允许或禁止读写访问。

每种体系结构都必须提供使得内存管理子系统能够修改pte_t项中的额外的比特位,即保存额为的比特位的__pgprot数据类型,以及修改这些比特位的pte_modify函数。内核还定义了各种函数,用于查询和设置内存页与体系结构相关的状态。如下是常用的设置内存页的函数。

 

函数

描述

pte_present

页是否在内存中

pte_read

从用户空间是否可读

pte_write

是否可以写入到该页

Pte_exec

该页中的数据是否可以作为二进制执行

Pte_dirty

页是否是脏的,其内容是否修改过

Pte_file

该页表项属于非线性映射吗

Pte_young

访问位设置好了没有(_PAGE_ACCESSED

Pte_rdprotect

清除该页的读权限

Pte_wrprotect

清除该页的写权限

Pte_exprotect

清除执行该页中二进制数据的权限

Pte_mkread

设置读权限

Pte_mkwrite

设置写权限

Pte_mkexec

允许执行页的内容

Pte_mkdirty

将页标记为脏

Pte_mkclean

“清除”页,通常是指消除_PAGE_DIRTY

Pte_mkyoung

设置访问位,在大多数体系结构上是_PAGE_ACCESSED

Pte_mkold

清除访问位

 这些函数经常31组,分别用于设置、删除、查询某个特定的属性。内核假定页面数据的访问可以按3种不同的方式控制,即读、写和执行权限。


2. 页表项的创建和操作

函数

描述

Mk_pte

创建一个页表项。必须将page实例和所需的页访问控制权限作为参数传递

Pte_page

获得页表项描述的页对应的page实例地址

Pgd_alloc

分配并初始化可容纳一个完整页表的内存

Pud_alloc

Pmd_alloc

Pte_alloc

Pgd_free

释放页表占据的内存

Pud_free

Pmd_free

Pte_free

Set_pgd

设置页表中某项的值

Set_pud

Set_pmd

Set_pte

 


你可能感兴趣的:(linux内核探索之内存管理(四):对页表和页表项的操作)