1. ホーム
  2. linux

[解決済み] カーネルスタックとユーザ空間スタック

2022-07-25 06:09:23

質問

カーネルスタックとユーザスタックの違いは何ですか?なぜカーネルスタックが使用されるのですか? ISR でローカル変数が宣言された場合、それはどこに格納されるのですか? 各プロセスは独自のカーネルスタックを持っているのですか?また、プロセスはどのようにこれら両方のスタック間を調整するのですか?

どのように解決するのですか?

<ブロッククオート
  1. カーネルスタックとユーザースタックの違いは何ですか?

要するに、メモリ内の異なる場所 (したがってスタックポインタレジスタの値も異なる) を使用し、通常は異なるメモリアクセス保護を行うことを除けば、何もありません。つまり、ユーザー モードで実行する場合、カーネル メモリ (その一部はカーネル スタック) はマップされていてもアクセスできません。逆に、カーネルコードから明示的に要求されない限り(Linuxでは copy_from_user() のような関数を通して)、ユーザー メモリ(ユーザー スタックを含む)には通常直接アクセスできません。

  1. なぜ [ 別々の ] カーネルスタックが使われるのですか?

特権とセキュリティの分離 1 つは、ユーザー空間プログラムはスタック (ポインタ) を好きなように作ることができ、通常は有効なものを持つことさえアーキテクチャ上必要ありません。そのため、カーネルは を信頼することができません。 したがって、カーネルはユーザー空間のスタックポインタが有効であるか、または使用可能であることを信頼することができず、したがって、それ自身の制御下で設定されたものを必要とします。x86 CPU では、特権モードの切り替えが発生するとスタック ポインターが自動的に切り替わり、異なる特権レベルのために使用される値は特権コード (つまり、カーネルのみ) によって設定可能です。

  1. ISRでローカル変数が宣言された場合、どこに格納されるのでしょうか?

カーネルスタックについて。カーネル (Linux カーネルのこと) が行うのは ではなく ISR を直接フックして、x86 アーキテクチャの 割り込みゲート の代わりに、登録されたハンドラを呼び出す前に割り込み前のレジスタの状態を保存する、共通のカーネル割り込みエントリ/イグジットメカニズムに割り込みディスパッチを委ねます。割り込みをディスパッチする際に CPU 自身が特権やスタックスイッチを実行することがありますが、これはカーネルによって使用/設定されるため、共通の割り込みエントリ コードはすでにカーネル スタックが存在することに依存することができるのです。

しかし、カーネルコードの実行中に発生した割り込みは、単にその時点で所定の位置にあるカーネルスタックを使用します(継続)。これは、割り込みハンドラーが深くネストされたコールパスを持つ場合、スタック オーバーフローにつながる可能性があります (深いカーネル コールパスが割り込まれ、ハンドラーが別の深いパスを引き起こす場合。Linux では、ファイルシステム/ソフトウェア RAID コードが iptables がアクティブなネットワーク コードによって割り込まれると、未チューンの古いカーネルではそのようになることがわかっています ... 解決方法は、この種のワークロードのカーネル スタックの大きさを増やすことです)。

  1. 各プロセスは独自のカーネルスタックを持つのでしょうか?

各プロセスだけでなく、各 スレッド はそれ自身のカーネルスタックを持ちます (そして、実際にはそれ自身のユーザースタックも)。プロセスとスレッドの (Linux にとっての) 唯一の違いは、複数のスレッドがアドレス空間を共有できる (プロセスを形成する) という事実であることを忘れないでください。

  1. これらのスタック間で、どのようにプロセスを調整するのですか?

全くその必要はありません。スケジューリング (異なるスレッドをいつどのように実行するか、スレッドの状態をどのように保存および復元するか) はオペレーティング システムのタスクであり、プロセスはこれに関与する必要がありません。スレッドが作成されると (そして各プロセスは少なくとも 1 つのスレッドを持たなければなりません)、カーネルはそれらのためにカーネルスタックを作成します。一方ユーザ空間のスタックは、スレッドを作成するために使われるどのメカニズムによっても、明示的に作成または提供されます (例えば makecontext() または pthread_create() を使用すると、呼び出し側が子スレッドのスタックに使用するメモリ領域を指定できます)、または継承されます(新しいプロセスを作成するときに、通常 "copy on write" / COW と呼ばれるオンアクセス メモリ クローニングにより)。

とはいえ、そのプロセス
はそのスレッドのスケジューリングに影響を与え、かつ/または コンテキスト (状態、その中でもスレッドのスタックポインタ) に影響を与えます。これには複数の方法があります。UNIX のシグナル setcontext() , pthread_yield() / pthread_cancel() , ... - が、これは本来の質問から少し脱線しています。