标签:
接上一节,主要参考《深入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_ACCESSED:CPU每次访问页时,会自动设置_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
清除访问位
这些函数经常3个1组,分别用于设置、删除、查询某个特定的属性。内核假定页面数据的访问可以按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
标签: