vm.c void freevm(pde_t *pgdir)

トップページ
jupiteroak.hatenablog.com


vm.c
https://github.com/mit-pdos/xv6-public/blob/master/vm.c#L283

void freevm(pde_t *pgdir)
{
  uint i;

  if(pgdir == 0)
    panic("freevm: no pgdir");
  deallocuvm(pgdir, KERNBASE, 0);
  for(i = 0; i < NPDENTRIES; i++){
    if(pgdir[i] & PTE_P){
      char * v = P2V(PTE_ADDR(pgdir[i]));
      kfree(v);
    }
  }
  kfree((char*)pgdir);
}

ユーザー空間に関わる、ページディレクトリのメモリ領域、全てのページテーブルのメモリ領域、全てのページフレーム(4KBのメモリ領域)を解放します。

引数 pde_t *pgdir
ページディレクトリを指定する先頭アドレスです。


処理の内容

ページディレクトリがない場合はメッセージを出力する

if(pgdir == 0)
    panic("freevm: no pgdir");

引数pgdirがページディレクトリを指定していない場合は、panic関数を呼び出してメッセージを出力します。

ユーザー空間にマッピングされている全てのページフレームを解放する

deallocuvm(pgdir, KERNBASE, 0);

deallocuvm関数を呼び出して、ユーザー空間にマッピングされている全てのページフレーム(仮想アドレス0から仮想アドレスKERNBASE(#define KERNBASE 0x8000 0000)未満の範囲にマッピングされている全ての4KBのメモリ領域)を解放します。

全てのページテーブルに割り当てられているメモリ領域を解放する

for(i = 0; i < NPDENTRIES; i++){
    if(pgdir[i] & PTE_P){
      char * v = P2V(PTE_ADDR(pgdir[i]));
      kfree(v);
    }
  }

for文を使って、全て(#define NPDENTRIES 1024)のページディレクトリエントリpgdir[i]にアクセスします。
if文の条件では、pgdir[i]の値(32bit)をPTE_P(#define PTE_P 0x001)でマスク処理することにより、pgdir[i]のbit0(ページディレクトリエントリのPフラグ)を取り出しています。pgdir[i] & PTE_Pが真となる場合→pgdir[i]のbit0(ページディレクトリエントリのPフラグ)が1となる場合→pgdir[i](ページディレクトリエントリ)が参照しているページテーブルが存在する場合は、ページディレクトリエントリpgdir[i]が参照しているページテーブルに割り当てられているメモリ領域を解放します。
PTE_ADDRマクロを使うことで、ページディレクトリエントリpgdir[i]からページテーブルの先頭アドレスを取得しています。
取得したページテーブルの先頭アドレスは物理アドレスなので、P2Vマクロを使って物理アドレスPTE_ADDR(pgdir[i])を仮想アドレスvに変換しています。

ページディレクトリに割り当てられているメモリ領域を解放する

kfree((char*)pgdir);

最後に、ページディレクトリに割り当てられている4KBのメモリ領域を解放します。