タダノキロク

日々の考えたことの記録 主に無駄なこと

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()”を以下で確認していく。

・エラー発生時のリニアアドレスを取得する。
Intelx86の場合は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;
	}