Linuxカーネルのコードの大部分はCで記述されていますが、そのコードの多くの部分は、実行中のプラットフォームに非常に固有のものであり、それを考慮する必要があります。
これの特定の例は、ほとんどのアーキテクチャ(ページテーブルの階層)で同様に機能しますが、各アーキテクチャの特定の詳細(各アーキテクチャのレベル数など)を備えた仮想メモリです。 Linuxカーネルコードは、ページテーブルのレベルが少ないアーキテクチャでコンパイラーによって省略される可能性のあるこれらの階層を走査するマクロを導入します(したがって、コードはCで記述されていますが、アーキテクチャの詳細は考慮。)
他の多くの領域は各アーキテクチャに非常に固有であり、アーチ固有のコードで処理する必要があります。ただし、これらのほとんどにはアセンブリ言語のコードが含まれます。例は次のとおりです。
コンテキストの切り替え:コンテキストの切り替えでは、切り替えられるプロセスのすべてのレジスタの値を保存し、CPUにスケジュールされたプロセスの保存セットからレジスタを復元します。レジスタの数とセットでさえ、各アーキテクチャに非常に固有です。通常、このコードはアセンブリに実装され、レジスタへのフルアクセスを可能にし、コンテキストスイッチングのパフォーマンスがシステムにとって重要になる可能性があるため、可能な限り高速に実行されるようにします。
システムコール:ユーザー空間コードがシステムコールをトリガーできるメカニズムは、通常、アーキテクチャに固有です(場合によっては特定のCPUモデルにも、たとえばIntelとAMDが異なる命令を導入したため、古いCPUにはそれらの命令がない場合があります。それらはまだユニークです。)
割り込みハンドラー:割り込み(ハードウェア割り込み)の処理方法の詳細は、通常プラットフォーム固有であり、通常、プラットフォームで使用されている特定の呼び出し規則を処理するためのアセンブリレベルの接着剤が必要です。また、割り込みを有効/無効にするためのプリミティブは通常プラットフォーム固有であり、アセンブリコードも必要です。
初期化:初期化の方法の詳細には、通常、プラットフォームに固有の詳細も含まれ、多くの場合、カーネルへのエントリポイントを処理するためにいくつかのアセンブリコードが必要です。複数のCPU(SMP)を備えたプラットフォームでは、通常、他のCPUをオンラインにする方法の詳細もプラットフォーム固有です。
ロックプリミティブ:いくつかのアーキテクチャでは、それらを効率的に実装するために異なるCPU命令を提供する(または好む)ため、ロックプリミティブ(スピンロックなど)の実装には、通常プラットフォーム固有の詳細も含まれます。アトミック操作を実装するものもあれば、アトミックにテスト/更新できるcmpxchgを提供するものもあります(ただし、他のライターが最初に侵入した場合は失敗します)。多くの場合、これらにはアセンブリコードの記述も含まれます。
プラットフォームまたはアーキテクチャ固有のコードがカーネルで必要とされ、おそらく他の領域(具体的には、またはLinuxカーネルでは、。)があり、カーネルのソースツリーを見ると、下のアーキテクチャ固有のサブツリーがあるarch/
と下のinclude/arch/
あなたはもっと見つけることができますが、この例。
実際には驚くべきものもあります。たとえば、各アーキテクチャで使用できるシステムコールの数は異なり、一部のアーキテクチャでは一部のシステムコールが存在し、他のアーキテクチャでは存在しないことがわかります。(x86でも、システムコールのリストは32ビットカーネルと64ビットカーネルで異なります。)
要するに、プラットフォーム固有のカーネルが認識する必要のあるケースはたくさんあります。Linuxカーネルはそれらのほとんどを抽象化しようとするため、高レベルのアルゴリズム(メモリ管理やスケジューリングの仕組みなど)をCで実装し、すべてのアーキテクチャで同じ(またはほぼ同じ)動作をさせることができます。