要するに、メモリ内の別の場所 (したがって、スタック ポインタ レジスタの別の値) を使用することと、通常は別のメモリ アクセス保護を使用すること以外には何もありません。つまりユーザー モードで実行する場合、カーネル メモリ (カーネル スタックの一部) はマップされていてもアクセスできません。逆に、カーネル コードによって明示的に要求されていない場合 (Linux では、copy_from_user()
などの関数を介して) )、ユーザー メモリ (ユーザー スタックを含む) は通常、直接アクセスできません。
- [別の] カーネル スタックが使用されるのはなぜですか?
特権とセキュリティの分離。 1 つは、ユーザー空間プログラムはスタック (ポインター) を好きなように作成でき、通常、有効なスタックを持つ必要さえないというアーキテクチャ上の要件はありません。したがって、カーネルは信頼できません ユーザー空間のスタック ポインターは有効でも使用可能でもないため、独自の制御下に 1 つのセットが必要になります。 CPU アーキテクチャが異なれば、これはさまざまな方法で実装されます。 x86 CPU は、特権モードの切り替えが発生したときにスタック ポインターを自動的に切り替えます。さまざまな特権レベルに使用される値は、特権コード (つまり、カーネルのみ) によって構成可能です。
<ブロック引用>- ローカル変数が ISR で宣言されている場合、どこに保存されますか?
カーネル スタック上。カーネル (つまり、Linux カーネル) はしない ISR を x86 アーキテクチャの 割り込みゲート に直接フックする 代わりに、登録されたハンドラーを呼び出す前に、割り込み前のレジスタ状態を保存する共通のカーネル割り込みエントリ/出口メカニズムに割り込みディスパッチを委譲します。割り込みをディスパッチするときに CPU 自体が特権および/またはスタック スイッチを実行する可能性があり、これはカーネルによって使用/設定されるため、共通の割り込みエントリ コードは存在するカーネル スタックに既に依存できます。
つまり、カーネル コードの実行中に発生する割り込みは、その時点で適切なカーネル スタックを単純に (継続して) 使用します。これは、割り込みハンドラーが深くネストされた呼び出しパスを持っている場合、スタック オーバーフローにつながる可能性があります (深いカーネル呼び出しパスが中断され、ハンドラーが別の深いパスを引き起こした場合。Linux では、iptables がアクティブなネットワーク コードによってファイルシステム/ソフトウェア RAID コードが中断されます。調整されていない古いカーネルでそのようなトリガーになることが知られています...解決策は、そのようなワークロードのカーネル スタック サイズを増やすことです)。
- 各プロセスには独自のカーネル スタックがありますか?
各プロセスだけでなく、各スレッド には独自のカーネル スタックがあります (実際、独自のユーザー スタックもあります)。プロセスとスレッドの (Linux に対する) 唯一の違いは、複数のスレッドがアドレス空間を共有できる (プロセスを形成する) ことです。
<ブロック引用>- これらのスタック間でプロセスはどのように調整されますか?
まったくありません - その必要はありません。スケジューリング (異なるスレッドがいつどのように実行されるか、それらの状態がどのように保存および復元されるか) はオペレーティング システムのタスクであり、プロセスはこれに関与する必要はありません。スレッドが作成されると (各プロセスには少なくとも 1 つのスレッドが必要です)、カーネルはそれらのスレッドのカーネル スタックを作成しますが、ユーザー空間スタックは、スレッドの作成に使用されるメカニズムによって明示的に作成/提供されます (makecontext()
または pthread_create()
呼び出し元が、「子」スレッドのスタックに使用されるメモリ領域を指定できるようにするか、または継承されます (新しいプロセスを作成するときに、通常は「書き込み時コピー」/COW と呼ばれるオンアクセス メモリ クローニングによって)。
そうは言っても、プロセスはできます スレッドのスケジューリングに影響を与える、および/またはコンテキストに影響を与える (状態、その中にはスレッドのスタックポインターがあります)。これには複数の方法があります:UNIX シグナル、setcontext()
、 pthread_yield()
/ pthread_cancel()
、... - しかし、これは元の質問から少し逸れています。
私の回答は、他の SO の質問から収集されたものです。
What's the difference between kernel stack and user stack?
カーネル プログラマーは、カーネルが誤ったユーザー プログラムから制限されるべきであることを知っています。カーネルとユーザー空間の両方で同じスタックを保持すると、ユーザー アプリケーションの単純な segfault によってカーネルがクラッシュし、再起動が必要になるとします。
ISR スタックのような CPU ごとに 1 つの「カーネル スタック」と、プロセスごとに 1 つの「カーネル スタック」があります。各プロセスには 1 つの「ユーザー スタック」がありますが、各スレッドには、ユーザー スレッドとカーネル スレッドの両方を含む独自のスタックがあります。
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Why kernel stack is used?
そのため、カーネル モードでは、ユーザー空間に似たローカル変数である関数呼び出しを処理するために、スタックのようなメカニズムが必要です。
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
If a local variable is declared in an ISR, where it will be stored?
ISR スタック (IRQSTACKSIZE) に格納されます。 ISR は、ハードウェアがサポートしている場合にのみ、別の割り込みスタックで実行されます。それ以外の場合、ISR スタック フレームは、中断されたスレッドのスタックにプッシュされます。
ユーザー空間は、割り込みが現在のプロセスのカーネル スタックで提供されているのか、別の ISR スタックで提供されているのかを知りませんし、率直に言って気にしません。割り込みは CPU ごとに発生するため、ISR スタックは CPU ごとに存在する必要があります。
Does each process has its own kernel stack ?
はい。各プロセスには独自のカーネル スタックがあります。
Then how the process coordinates between both these stacks?
@FrankH の回答は素晴らしいと思います。