カーネルモードビット

カーネルモードビット

私はガルビンの本「オペレーティングシステムと概念」で以下を読みました

「モード ビットと呼ばれるビットがコンピューターのハードウェアに追加され、現在のモード (カーネル (0) またはユーザー (1)) を示します。モード ビットを使用すると、オペレーティング システムに代わって実行されるタスクとユーザーに代わって実行されるタスクを区別できます。」

マルチプロセッサ システムの場合、プロセスがシステム コールを実行し、モード ビットを 1 から 0 に変更するとします。

マルチプロセッサ システムであるため、ユーザー モードで並行して実行されている他のプロセスが存在する可能性がありますが、モード ビットはカーネル モードを示す 0 に設定されており、不整合が発生します。

それで、レジスタの数(モード ビットを格納するために必要なもの)はプロセッサの数に依存しますか?

答え1

あなたの本は物事を単純化しすぎています。実際には、モードがどのように設定されるかは CPU によって異なり、必ずしも「ビット」である必要はなく、モードが 2 つだけである必要もありません。

質問の目的上、Linux、Intel x86、マルチコアを想定します。

マルチタスクは、Linux ではソフトウェア ベースのコンテキスト スイッチで実装されます。コンテキスト スイッチは、プロセッサ (コアまたは CPU) が実行している処理を停止し、その状態を RAM に保存して、別のコンテキストに置き換えます。

x86 は、プロセス レベルの実行が発生する前に各プロセッサに設定できる保護リングを実装します。Linux カーネルは、メモリ空間で実行を開始する前にプロセスをリング 3 (非特権) に設定することでこれを処理します。前述のコンテキスト スイッチの実装により、カーネルは特定のスレッド (Intel ではコアごとに 2 つのスレッド) で実行されるプロセスの概念を維持します。これは、プログラム コードが実行されているときは常に、プロセッサが 1 秒間に何度もコンテキスト スイッチが発生しているのを認識しているにもかかわらず、カーネルがリングを常に 3 に設定し直し、同じコアで多くのプロセスが実行されるためです。これは、1 つまたは複数のコアで基本的に同じ方法で実行できます。

x86 の Linux では、スレッドがリング 3 からリング 0 (スーパーバイザー) に切り替える場合、ソフトウェア割り込みでのみこれを行うことができます。リング 1 と 2 では、特別な命令でも可能ですが、Linux ではこれを実装していません。Linux はソフトウェア割り込みハンドラーを制御するため、スレッドがリング 0 にある場合でも、ユーザー空間コードを実行していたのと同じスレッドであっても、カーネルの一部であるコードである「カーネル空間」でのみコードを実行するようにできます。オペレーティングシステムの用語では、これが実際に行っていることなので、これは単にシステムコールと呼ばれます。これを「プロセス」がカーネルモードに切り替えて元に戻っていると見なすか、またはカーネル空間コードのみが実行され、ユーザー空間に戻るまでプロセスが事実上保留中であると見なすかは、あなた次第です。

x86 では、上位リングのものを下位リングに切り替えることができるため、割り込みハンドラが完了した後、3 に戻すことができます。これはすべてのシステム コールで発生するため、ハードウェアの観点からはすべてのシステム コールがシステム上で何でも実行できます。プログラムのすべての命令を逆順に実行し、必要に応じてメモリからすべてのコードを削除できます。または、リング 0 に切り替えて、プログラムの先頭から実行を開始することもできます。ご覧のとおり、これらの例は「カーネル/ユーザー」モードの概念を破っています。ハードウェアにはそのような概念は存在しないためです。ただし、Linux では、常にカーネル空間への呼び出しとユーザー空間への戻りとして実装されています (x86 では、事実上、メモリはリング 0 から保護されていません)。

そのため、カーネル/ユーザー モードの切り替えは、スレッド保護リングから抜け出すことができるソフトウェア割り込みハンドラーを使用して実装されますが、実行はカーネル空間でのみ行われ、その後、リング 3 に戻った後にのみ、システム コールを実行したユーザー空間プロセスに返されるように実装されます。

関連情報