| ページフォルト 発生要因 | 結果 |
|---|---|
| 不正な仮想アドレスへのアクセス | ユーザモードでページフォルトが発生していた場合は、該当スレッドを終了させる。カーネルモードでページフォルトが発生していた場合はシステム停止。 |
| 物理ページがまだ割り当てられていない仮想アドレス空間へのアクセス | 物理ページを割り当てて、PTEを設定する。 |
| プロテクション不正 | ユーザモードでページフォルトが発生していた場合は、該当スレッドを終了させる。カーネルモードでページフォルトが発生していた場合はシステム停止。 |
| プロテクション不正(COWのためにReadOnlyになっているページへの書込み) | COW(Copy On Write)処理を行なう。ページをコピーして書込み可能にする。 |
| Pageoutされているページへのアクセス | Pageinを行う。 |
vm_map_lookup_locked()
仮想アドレスに対応するvm_objectを取得する。
不正なアドレスへのアクセスでvm_objectがない場合はKERN_INVALID_ADDRESS。
プロテクション不正の場合はKERN_PROTECTION_FAILURE。
/*
* ページフォルト処理の高速処理
* 処理できない場合は諦めて(以下のwhileをbreak)
* 通常のフォルト処理を行なう。
*/
while (TRUE) { <-- shadowオブジェクトをたどる為にループさせている
m = vm_page_lookup(cur_object, cur_offset);
ページを取得
if (m != VM_PAGE_NULL) {
if (m->busy) {
既にPagein中などなんらかの処理中なので
スレッドをブロック
goto done;
}
:
if ((fault_type & VM_PROT_WRITE) == 0) {
/* ページへのリードかページ上のコードを
実行しようとしてフォルトした */
/* kmem_alloc()でメモリを確保した場合は、
物理ページのマップをここで作成する。
(fault_type:VM_PROT_NONEでページフォルトをシミュレートするため)
*/
FastPmapEnter:
PMAP_ENTER()でPTE設定
PAGE_WAKEUP_DONE(m) ページ待ちのスレッドがいたらWakeup
return KERN_SUCCESS;
}
/* ページへの書込みでフォルトが発生した場合 */
Copy On Writeの処理
vm_page_grab()で新しいページを取得し
vm_page_copy()でページをコピーする。
goto FastPmapEnter; pmap設定へ
} else {
/* ページがない場合 */
if (cur_object->pager_created) {
/* Pagerがある場合はあきらめる。
* PageOutされていた場合など。
*/
break;
}
/*
* kmem_alloc_pageable()で仮想アドレス空間のみ割り当てて、
* 物理ページが存在しない場合はなどは、ここでページが確保&
* 割り当てられる。
*/
if (cur_object->shadow == VM_OBJECT_NULL) {
ページの割り当て処理
vm_page_alloc() ページを取得してvm_objectにつなげる
if (!map->no_zero_fill) {
ページを0で初期化
}
goto FastPmapEnter;
}
/* shadowオブジェクトがある */
shadowをたどる
continue;
}
}
kr = vm_fault_page() 仮想アドレスに対応した物理ページを取得する
PageInの処理もこのなかで行われる。
PMAP_ENTER()