9章プロセスアドレス空間 20151121Linux Kernel 勉強会 #13
詳細Linuxカーネルの9章のプロセスアドレス空間を読んだメモ。
9章 プロセスアドレス空間
ー>カーネルがプロセスから依頼されてメモリ確保の規則
・ユーザモードプロセスへの動的メモリ割り当ては遅延させる
・ユーザモードのプロセスはアドレスバグがあるため、
アドレッシングエラーを補足する
9.1 プロセスのアドレス空間
=プロセスが使用できるすべてのリニアアドレス
カーネルはメモリリージョンをプロセスに付与
+先頭リニアアドレス 4kB単位
+大きさ・サイズ 4KB単位
+アクセス権
カーネルはページフォルト要因を2つに識別
・プログラミングエラーにより発生した
・ページが存在しないために発生した
(カーネルがプロセスに渡したリニアアドレスのページ割当をしていなかった場合?)
9.2 メモリディスクリプタ
=プロセスアドレス空間に関する情報
(持ち主はプロセス?)
メモリディスクリプタの構造体:mm_struct
(プロセスディスクリプタ mmから参照する)
mm_users : mm_struct データを共有する軽量プロセス数
mm_count : メモリディスクリプタ参照数
*カーネルがプロセスのメモリディスクリプタを参照するときには、いずれかのメンバ1加える
9.3 メモリリージョン
vm_area_struct構造体(メモリリ0ジョンディスクリプタ)でメモリリージョンを管理
カーネル側がメモリリージョンをどうやって管理しているか?
9.4 ページフォルト例外ハンドラ
割り込みのハンドラはページフォルト例外発生のアドレスが、
プロセス空間かつメモリリージョンに割当済みであれば、ページ割当を実施。
それ以外はプロセス/カーネル異常とする。
ページフォルト例外ハンドラの”do_page_falut()”を以下で確認していく。
・エラー発生時のリニアアドレスを取得する。
Intelのx86の場合はCR2に格納されている。
unsigned long address = read_cr2(); /* Get the faulting address */
・__do_page_falut()をコールする
割り込み処理中であることを宣言してコール
引数は、pt_regs 構造体のアドレス regs/例外発生時のErrorCode/リニアアドレス(address)
・以下ページフォルトの実体 __do_page_falut
if (unlikely(fault_in_kernel_space(address))) { /* リニアアドレスがカーネル空間でではないことを確認*/ /* address > 0xc0000000 */ if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) { /* ErrorCodeにbit0,2,3にエラーがない場合)*/ if (vmalloc_fault(address) >= 0) /*アドレスがvmalloc空間の場合はメモリ確保? return; if (kmemcheck_fault(regs, address, error_code)) /*?????? */ return; } /* ErrorCodeにbit1にエラーがある場合 */ /* Can handle a stale RO->RW TLB: */ if (spurious_fault(error_code, address)) /* 擬似的なページフォルト*/ return; /* Write時/プレフィチェ時のページレベル違反以外はページ割当を実施*/ /* kprobes don't want to hook the spurious faults: */ if (kprobes_fault(regs)) return; /* * Don't take the mm semaphore here. If we fixup a prefetch * fault we could otherwise deadlock: */ bad_area_nosemaphore(regs, error_code, address); return; }