pte.h

#definePTSHIFT PGBITS /*page table index的开始位:12*/
#define PTBITS 10 /*page table index的位长度*/
#define PTSPAN (1 << PTBITS << PGBITS) /*一个page table index指向一个page table,而一个page table大小是1KB*/
#define PTMASK BITMASK(PTSHIFT, PTBITS) /*掩码,即过滤其他位*/
static inline unsigned pt_no (const void *va) {
return ((uintptr_t) va & PTMASK) >> PTSHIFT;
}
va表示虚拟地址,即32位,先把page table index通过掩码过滤,然后把他移到低位。

一个page table index指向一个page table,而一个page table entry是一个虚拟地址。
一个PDE把物理地址抽取出来指向一个page table。如果PDE的present位是false,则忽略其他位。

31 12 11 0
+------------------------------------+------------------------+
| Physical Address | Flags |
+------------------------------------+------------------------+
12-31位是物理地址,我们指向一个page table之前必须要把他转化为虚拟地址。

#define PTE_FLAGS 0x00000fff /* Flag bits. */
#define PTE_ADDR 0xfffff000 /* Address bits. */
#define PTE_AVL 0x00000e00 /* Bits available for OS use. */
#define PTE_P 0x1 /* 1=present, 0=not present. */
#define PTE_W 0x2 /* 1=read/write, 0=read-only. */
#define PTE_U 0x4 /* 1=user/kernel, 0=kernel only. */
#define PTE_A 0x20 /* 1=accessed, 0=not acccessed. */
#define PTE_D 0x40 /* 1=dirty, 0=not dirty (PTEs only). */
以上是一群宏定义,他们的目的很像掩码,就是过滤其他位,把自己需要的位给抽取出来。
static inline uint32_t pde_create (uint32_t *pt) {
ASSERT (pg_ofs (pt) == 0);
return vtop (pt) | PTE_U | PTE_P | PTE_W;
}
pt为page table 的虚拟地址,我们前面讲到pde含有的是page table的物理地址,因此我们需要把va转换为pa,并且还要把标识位设置好。即用户进程能访问,并且present,并且能够可以写的。
static inline uint32_t *pde_get_pt (uint32_t pde) {
ASSERT (pde & PTE_P);
return ptov (pde & PTE_ADDR);
}
这个就和我上面讲的一样,已知pde地址,要求他指向的page table的地址,需要先用掩码把物理地址提取出来,再变成虚拟地址即可。
static inline uint32_t pte_create_kernel (void *page, bool writable) {
ASSERT (pg_ofs (page) == 0);
return vtop (page) | PTE_P | (writable ? PTE_W : 0);
}
这个是创建一个pte指向指定的page,就类似于pde指向pt。需要注意是这个只能被kernel所使用。

你可能感兴趣的:(OS)