文章目录
页操作常用宏
include/linux/pgtable.h
include
pgd_offset
mm的pgd + pgd_index
static inline pgd_t *pgd_offset_pgd(pgd_t *pgd, unsigned long address)
{return (pgd + pgd_index(address));};
mm->pgd是指针,这个动作含义是指针偏移pgd_index位
pgd_offset = pgdp = mm->pgd[pgd]
(pgd是地址的第40~48位
pud_offset
调用p4d_pgtable + pud_index
p4d_pgtable调用p4d_page_paddr
p4d_page_paddr调用__p4d_to_phys
__p4d_to_phys实际上是 __pte_to_phys宏的变形
static inline pud_t *p4d_pgtable(p4d_t p4d)
{ return (pud_t *)__va(p4d_page_paddr(p4d));}
static inline phys_addr_t p4d_page_paddr(p4d_t p4d)
{ return __p4d_to_phys(p4d);}
#define __p4d_to_phys(p4d) __pte_to_phys(p4d_pte(p4d))
static inline pte_t p4d_pte(p4d_t p4d)
{ return __pte(p4d_val(p4d));}
#define __pte_to_phys(pte) (pte_val(pte) & PTE_ADDR_MASK)
static inline pte_t pgd_pte(pgd_t pgd)
{ return __pte(pgd_val(pgd));}
----------
static inline unsigned long pud_index(unsigned long address)
{return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);}
p4d_pgtable(p4d_t p4d)
(pud_t *)__va(p4d_page_paddr(p4d))
p4d_page_paddr(p4d_t p4d)
__p4d_to_phys(p4d_t p4d)
__pte_to_phys(p4d_pte(p4d))
(pte_val(p4d_pte(p4d)) & PTE_ADDR_MASK)
(pte_val(__pte(p4d_val(p4d)))) & PTE_ADDR_MASK)
解释:对一个p4d_t获取p4dval_t,再强转成pte_t,再获取pteval_t,再&上PTE_ADDR_MASK (12-48位),再用__va宏取虚拟地址,再转成pud_t类型返回
概况:对传入的p4d(pgdp指向的值),&上0xffff-ffff-f000(13-48位),然后把得到的值用va宏获取地址
(为什么返回pud_t而底层调用的是pte类型?我感觉所因为操作方法,pud pmd pte类型其实都一样都是u64,直接使用通用的pte类型了)
通过全局pgd偏移pgd位的方式得到pgdp
pgdp指向的是,目标地址所在的pud的地址,(二级页目录入口 pud-entry
pud-entry = pgdp = mm->pgd[pgd]
pmd-entry = pudp = pud-entry[pud]
pte-entry = pmdp = pmd-entry[pmd]
ptep = pte-entry[pte]
addr = ptep[page] (低12位
pmd_offset
(流程和pud_offset一样)
调用pud_pgtable + pmd_index
pud_pgtable调用pud_page_paddr
pud_page_paddr调用__pud_to_phys
__pud_to_phys实际上是 __pte_to_phys宏的变形
static inline pmd_t *pud_pgtable(pud_t pud)
{return (pmd_t *)__va(pud_page_paddr(pud));}
static inline phys_addr_t pud_page_paddr(pud_t pud)
{return __pud_to_phys(pud);}
#define __pud_to_phys(pud) __pte_to_phys(pud_pte(pud))
static inline pte_t pud_pte(pud_t pud)
{return __pte(pud_val(pud));}
----------
static inline unsigned long pmd_index(unsigned long address)
{return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);}
pte_offset_kernel
(流程和pmd_offset有些许差别)
调用pmd_page_vaddr + pte_index (而非pmd_pgtable)
pmd_page_vaddr调用pmd_page_paddr (va->pa)
pmd_page_paddr调用__pmd_to_phys
__pmd_to_phys实际上是 __pte_to_phys宏的变形
static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address)
{return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(address);}
static inline unsigned long pmd_page_vaddr(pmd_t pmd)
{return (unsigned long)__va(pmd_page_paddr(pmd));}
static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
{return __pmd_to_phys(pmd);}
#define __pmd_to_phys(pmd) __pte_to_phys(pmd_pte(pmd))
pte_valid
#define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
// PTE_VALID宏见下一节的bit位
这个宏是用pte的值和1相与
set_pte_bit 和 clear_pte_bit
arm64 pgtable-types.h
typedef struct { pteval_t pte; } pte_t;
#define pte_val(x) ((x).pte)
#define __pte(x) ((pte_t) { (x) } )
typedef struct { pteval_t pgprot; } pgprot_t;
#define pgprot_val(x) ((x).pgprot)
#define __pgprot(x) ((pgprot_t) { (x) } )
pgprot_val是取一个pteval_t类型的的值(类型转换而已,实际上就是一个u64类型的pte)
pgprot_t看样子像是pgd pud pmd pte之类的通用类型
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
{
pte_val(pte) &= ~pgprot_val(prot);
return pte;
}
static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
{
pte_val(pte) |= pgprot_val(prot);
return pte;
}
READ_ONCE 和 WRITE_ONCE
READ_ONCE,arm64实现这个有点复杂,可以先看下通用的理解下
#define READ_ONCE(x) \
({ \
compiletime_assert_rwonce_type(x); \
__READ_ONCE(x); \
})
// include/asm-genernic/rwonce.h
#ifndef __READ_ONCE
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
#endif
// arch/arm64/include/asm/rwonce.h
#define __READ_ONCE(x) \
({ \
typeof(&(x)) __x = &(x); \
int atomic = 1; \
union { __unqual_scalar_typeof(*__x) __val; char __c[1]; } __u; \
switch (sizeof(x)) { \
case 1: \
asm volatile(__LOAD_RCPC(b, %w0, %1) \
: "=r" (*(__u8 *)__u.__c) \
: "Q" (*__x) : "memory"); \
break; \
case 2: \
asm volatile(__LOAD_RCPC(h, %w0, %1) \
: "=r" (*(__u16 *)__u.__c) \
: "Q" (*__x) : "memory"); \
break; \
case 4: \
asm volatile(__LOAD_RCPC(, %w0, %1) \
: "=r" (*(__u32 *)__u.__c) \
: "Q" (*__x) : "memory"); \
break; \
case 8: \
asm volatile(__LOAD_RCPC(, %0, %1) \
: "=r" (*(__u64 *)__u.__c) \
: "Q" (*__x) : "memory"); \
break; \
default: \
atomic = 0; \
} \
atomic ? (typeof(*__x))__u.__val : (*(volatile typeof(__x))__x);\
})
#define WRITE_ONCE(x, val) \
do { \
compiletime_assert_rwonce_type(x); \
__WRITE_ONCE(x, val); \
} while (0)
#define __WRITE_ONCE(x, val) \
do { \
*(volatile typeof(x) *)&(x) = (val); \
} while (0)
// e.g
int x = 1;
*(volatile int *) &(x) = 2;
// x被赋值为2
// val先取地址,再用(int*)修饰成int* 类型的指针,再用*解引用,然后赋值
// 所以WRITE_ONCE就是对变量x赋值,而已
页表相关标志位
pte的位
arch/arm64/include/asm/pgtable-prot.h
#define PTE_WRITE (PTE_DBM) /* same as DBM (51) */
#define PTE_SWP_EXCLUSIVE (_AT(pteval_t, 1) << 2) /* only for swp ptes */
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
#define PTE_SPECIAL (_AT(pteval_t, 1) << 56)
#define PTE_DEVMAP (_AT(pteval_t, 1) << 57)
#define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
arch/arm64/include/asm/pgtable-hwdef.h
#define PTE_VALID (_AT(pteval_t, 1) << 0)
#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0)
#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1)
#define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */
#define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */
#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
#define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */
#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */
#define PTE_GP (_AT(pteval_t, 1) << 50) /* BTI guarded */
#define PTE_DBM (_AT(pteval_t, 1) << 51) /* Dirty Bit Management */
#define PTE_CONT (_AT(pteval_t, 1) << 52) /* Contiguous range */
#define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */
#define PTE_UXN (_AT(pteval_t, 1) << 54) /* User XN */
arch/arm64/include/asm/pgtable.h
#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
#define pte_young(pte) (!!(pte_val(pte) & PTE_AF))
#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL))
#define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE))
#define pte_rdonly(pte) (!!(pte_val(pte) & PTE_RDONLY))
#define pte_user(pte) (!!(pte_val(pte) & PTE_USER))
#define pte_user_exec(pte) (!(pte_val(pte) & PTE_UXN))
#define pte_cont(pte) (!!(pte_val(pte) & PTE_CONT))
#define pte_devmap(pte) (!!(pte_val(pte) & PTE_DEVMAP))
#define pte_tagged(pte) ((pte_val(pte) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED))
static inline pte_t pte_mkwrite_novma(pte_t pte)
{
pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
return pte;
}
设置pte可写,可以调用pte_mkwrite_novma,也可以直接调用的set/clear_pte_bit
pmd的位
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
#define pmd_valid(pmd) pte_valid(pmd_pte(pmd))
#define pmd_user(pmd) pte_user(pmd_pte(pmd))
#define pmd_user_exec(pmd) pte_user_exec(pmd_pte(pmd))
#define pmd_cont(pmd) pte_cont(pmd_pte(pmd))
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
#define pmd_mkwrite_novma(pmd) pte_pmd(pte_mkwrite_novma(pmd_pte(pmd)))
#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
观察这些宏可见,pmd的相关动作都是把pmd转成pte,然后操作pte的bit位
比如pmd_mkwrite_novma,就是把pmd类型转换成pte之后直接调用pte_mkwrite_novma
不难看出,pmd和pte的bit位功能实际上一致

被折叠的 条评论
为什么被折叠?



