図面には、いくつかの重要な前提がありません。
カーネルは、ユーザ空間のメモリにアクセスするためにmmap()
を必要としません。ユーザープロセスがメモリを持っている場合、それは既に定義によってアドレス空間にマップされています。その意味では、メモリはすでにユーザーとカーネルの間で共有されています。
mmap()
は、ユーザーの仮想アドレス空間に新しい領域を作成します。そのため、後でアクセスされた場合に物理領域がアドレス領域に取り込まれる可能性があります。メモリの実際の割り当てとページテーブルエントリの変更は、カーネルによって行われます。
mmap()
は、仮想アドレス空間のユーザー半分を管理するためにのみ意味があります。アドレス空間のカーネル半分は完全に異なった形で管理されます。
また、kernel-halfは、システム内のすべてのプロセスで共有されます。各プロセスには専用の仮想アドレス空間がありますが、カーネル半分のページテーブルエントリがすべてのプロセスでまったく同じになるようにページテーブルがプログラムされています。
また、カーネルはユーザ空間のメモリにアクセスするためにmmap()
を使用しません。 mmap()
は、むしろユーザの仮想アドレス空間における現在のマッピングを変更するためにカーネルによってユーザに提供されるサービスである。
ところで、実際にカーネルには、必要に応じてユーザーメモリにアクセスする方法がいくつかあります。
まず、カーネルは、存在する物理メモリの全体を連続してマッピングする(カーネル空間の一部として)カーネルアドレス空間の専用領域を持っています。 (これはすべての64ビットシステムに当てはまります.32ビットシステムではカーネルはこれを達成するためにオンザフライで '再マップ'しなければなりません)。
第2に、カーネルがシステムコールまたは例外ハードウェア割り込みではなく、有効なプロセスコンテキストを持っているので、カーネルはユーザースペースポインタを直接参照解除して正しい値を得ることができます。
第3に、カーネルが割り込みハンドラなどの借用されたコンテキストで実行中にプロセスのユーザスペースポインタを尊重したい場合、カーネルはvm_area_struct
ツリーを通過してページテーブルを参照することによってプロセスの仮想アドレスをトレースできます。実際の物理ページフレームを見つける。
はい。それは基本的に正しいです。私は右に指している重い黒い矢でそれを描くだろう。つまり、同じ物理ページを共有しています。カーネルと同じ仮想アドレスを取得せず、何らかの形でカーネルデータ領域を「指す」こともありません。代わりに、それは同じ物理メモリページへのそれ自身の独立したマッピングを得る。 –
多くの場合、Linuxのすべてのスレッドが1GBのカーネルと3GBのユーザースペースに分割された独自の仮想メモリ領域を取得することがあります。この場合:カーネルモジュールのいくつかの部分は、ユーザー空間アプリケーションのカーネル空間部分の中にありますか? – Alex44
はい。そのモデルでは、カーネルの仮想アドレス空間はトップ1GB(x86 32ビットの場合)です。ユーザーモードのスペースは、最下部の3GBです。したがって、彼らは4GBの仮想アドレス空間を共有します。コンテキストスイッチがある場合、新しいページテーブルがインストールされます。上位1GBでは同じマッピングが行われますが、新しいプロセスのユーザーモードでは新しいマッピングがあります。しかし、ユーザモードはトップ1GBにアクセスすることはできません(つまり、メモリにアクセスしようとすると、ページテーブルのアクセス制限のために 'SIGSEGV 'を受信します)。カーネルモード*は技術的にユーザーモード空間に直接アクセスできますが、一般的にはAPI経由で行われます。 –