vm.c int deallocuvm(pde_t *pgdir, uint oldsz, uint newsz)
トップページ
jupiteroak.hatenablog.com
vm.c
https://github.com/mit-pdos/xv6-public/blob/master/vm.c#L255
int deallocuvm(pde_t *pgdir, uint oldsz, uint newsz) { pte_t *pte; uint a, pa; if(newsz >= oldsz) return oldsz; a = PGROUNDUP(newsz); for(; a < oldsz; a += PGSIZE){ pte = walkpgdir(pgdir, (char*)a, 0); if(!pte) a = PGADDR(PDX(a) + 1, 0, 0) - PGSIZE; else if((*pte & PTE_P) != 0){ pa = PTE_ADDR(*pte); if(pa == 0) panic("kfree"); char *v = P2V(pa); kfree(v); *pte = 0; } } return newsz; }
deallocuvm関数は、仮想アドレスnewszから仮想アドレス未満oldszの範囲にマッピングされている全てのページフレームを解放します(全ての4KBのメモリ領域を未使用状態にします)。
引数 pde_t *pgdir
ページディレクトリの先頭アドレスです。
引数 uint oldsz
解放対象となるページフレームに関連した仮想アドレスの範囲における、終端アドレスです。
引数 uint newsz
解放対象となるページフレームに関連した仮想アドレスの範囲における、先頭アドレスです。
戻り値 int newsz または int oldsz
全てのページフレームを解放した場合は、newszが戻り値となります。
全てのページフレームを解放しなかった場合は、oldszが戻り値とまります。
処理の内容
- アドレスnewszが下位側・アドレスoldszが上位側にあることを確認する
- アドレスnewszを4KB境界に切り上げる
- 仮想アドレスnewszから仮想アドレスoldsz未満の範囲にマッピングされている全てのページフレームを解放する
- newszを戻り値としてリターンする
アドレスnewszが下位側・アドレスoldszが上位側にあることを確認する
if(newsz >= oldsz) return oldsz;
newsz >= oldszが真となる場合→アドレスnewszが下位側・アドレスoldszが上位ではない場合は、oldszを戻り値として処理を終了します。
アドレスnewszを4KB境界に切り上げる
a = PGROUNDUP(newsz);
PGROUNDUPマクロを使って、アドレスnewszを4KB境界のアドレス値(0x1000倍のアドレス値)に切り上げます。
仮想アドレスnewszから仮想アドレスoldsz未満の範囲にマッピングされている全てのページフレームを解放する
for(; a < oldsz; a += PGSIZE){ pte = walkpgdir(pgdir, (char*)a, 0); if(!pte) a = PGADDR(PDX(a) + 1, 0, 0) - PGSIZE; else if((*pte & PTE_P) != 0){ pa = PTE_ADDR(*pte); if(pa == 0) panic("kfree"); char *v = P2V(pa); kfree(v); *pte = 0; } }
仮想アドレスnewszから仮想アドレス未満oldszの範囲において、PTE(ページテーブルエントリ)を取得し、そのPTE(ページテーブルエントリ)が参照しているページフレーム(4KBのメモリ領域)を解放していきます。
PTE(ページテーブルエントリ)を取得する
pte = walkpgdir(pgdir, (char*)a, 0);
walkpgdir関数を呼び出して、仮想アドレスaに対応しているpte(ページテーブルエントリ)を取得します。
ページテーブルが存在していなかった場合
if(!pte) a = PGADDR(PDX(a) + 1, 0, 0) - PGSIZE;
!pteが真となる場合→pteが0の場合→仮想アドレスaに対応しているページテーブルが存在していなかった場合は、PDE(ページディレクトリエントリ)のインデックス値(仮想アドレスaのbit31-22)をインクリメントすることで参照先のページテーブルを変更してから、次のループへ進みます。
PDE(ページディレクトリエントリ)のインデックス値(仮想アドレスaのbit31-22)をインクリメントした仮想アドレスを取得するために、PGADDRマクロの第一引数にPDX(a) + 1を指定しています。
また、次のループに進んだ際の再設定式で、不必要にPGSIZE(#define PGSIZE 4096)が加算されるので、あらかじめPGSIZE(#define PGSIZE 4096)分減算しています。
ページテーブルがページフレームを参照している場合
else if((*pte & PTE_P) != 0){ pa = PTE_ADDR(*pte); if(pa == 0) panic("kfree"); char *v = P2V(pa); kfree(v); *pte = 0; }
newszを戻り値としてリターンする
return newsz;