Page Table

Page Table #

Paging Hardware #

通常 ISA 操作的是虛擬記憶體,無論是 kernel space 或 user space,因此我們需要一個硬體對應實體記憶體,現代的內存管理單元 (Memory Mangement Unit aka. MMU) 多存在處理器中,

flowchart LR CPU --"發出 VA (Virtual Address) "--> 硬體轉換電路 --"發出 MVA (Modified Virtual Address)" --> MMU--"發出 PA (Physical Address)"-->物理內存

Kernel address space #

圖的左邊是 xv6 的內核虛擬記憶體分佈,RWX 分別對應著 PTE (page table entry) 的讀、寫和執行標誌。可以看到 kernel 在實體與虛擬記憶體中同時座落在 KERNBASE=0x80000000 ,會有這樣直接映射的設計是因為 kernel 中許多位置會頻繁被調用,直接映射可以減少轉換的成本。

Physical memory allocation #

在執行 runtime 時,實體記憶體需要分配給 page table, user memory, kernel stacks, pipe buffers 空間,例如我們寫 c 語言時常會用到的 malloc,實際上會先返回虛擬記憶體給使用者,等到需要用到時才查詢分頁表為空,透過引發 page fault 在缺頁異常中處理實體記憶體分配空間。xv6 的分配空間位於 PHYSTOP=0x86400000 至 kernel 之間,每次空間分配與釋放都是以 page 為單位 (PGSIZE=4096 bytes),xv6 透過維護一個 linked list 來確認 page 是否可用。

struct run {
  struct run *next;
};

struct {
  struct spinlock lock;
  struct run *freelist;
} kmem;

為了維護一個 freelist,kernel 有兩個方法對應到配置與釋放空間:

  • kalloc:將 page 移除 linked list
void *
kalloc(void)
{
  struct run *r;

  acquire(&kmem.lock);
  r = kmem.freelist;
  if(r)
    kmem.freelist = r->next;
  release(&kmem.lock);

  if(r)
    memset((char*)r, 5, PGSIZE); // fill with junk
  return (void*)r;
}
  • kfree:將 page 加入 linked list
void
kfree(void *pa)
{
  struct run *r;

  if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
    panic("kfree");

  // Fill with junk to catch dangling refs.
  memset(pa, 1, PGSIZE);

  r = (struct run*)pa;

  acquire(&kmem.lock);
  r->next = kmem.freelist;
  kmem.freelist = r;
  release(&kmem.lock);
}

Reference #