
コンピューティングにおいて、システムコール(一般にsyscallと略される)は、コンピュータプログラムが、それが実行されるオペレーティングシステム[a]にサービスを要求するプログラム的な方法です。これには、ハードウェア関連のサービス(たとえば、ハードディスクドライブへのアクセスやデバイスのカメラへのアクセス)、新しいプロセスの作成と実行、プロセススケジューリングなどの重要なカーネルサービスとの通信が含まれます。システムコールは、プロセスとオペレーティングシステム間の重要なインターフェイスを提供します。
ほとんどのシステムでは、システムコールはユーザー空間プロセスからのみ実行できますが、 OS/360や後継システムなどの一部のシステムでは、特権システムコードもシステムコールを発行します。[1]
組み込みシステムの場合、システムコールは通常、 CPU の 特権モードを変更しません。
特権
一部の組み込みシステムを除き、最近のプロセッサのアーキテクチャのほとんどには、セキュリティ モデルが採用されています。たとえば、リングモデルでは、ソフトウェアを実行できる複数の特権レベルが指定されています。プログラムは通常、独自のアドレス空間に制限されるため、実行中の他のプログラムやオペレーティング システム自体にアクセスしたり変更したりすることはできません。また、通常、ハードウェア デバイス (フレーム バッファーやネットワークデバイスなど) を 直接操作することもできません。
ただし、多くのアプリケーションはこれらのコンポーネントにアクセスする必要があるため、オペレーティング システムではシステム コールが利用可能になり、このような操作を明確に定義して安全に実装できます。オペレーティング システムは最高レベルの権限で実行され、アプリケーションがシステム コールを介してサービスを要求できるようにします。システム コールは多くの場合、割り込みによって開始されます。割り込みにより、CPU は自動的に高い権限レベルに設定され、カーネルに制御が渡されます。カーネルは、要求されたサービスを呼び出し元プログラムに許可するかどうかを決定します。サービスが許可されると、カーネルは、呼び出し元プログラムが直接制御できない特定の命令セットを実行し、権限レベルを呼び出し元プログラムのレベルに戻し、制御を呼び出し元プログラムに戻します。
仲介者としての図書館
一般的に、システムは、通常のプログラムとオペレーティング システムの間に位置するライブラリまたはAPI を提供します。 Unix 系システムでは、その API は通常、 glibc などの C ライブラリ (libc) の実装の一部であり、システム コールのラッパー関数を提供します。ラッパー関数の名前は、多くの場合、呼び出すシステム コールと同じになります。 Windows NTでは、そのAPIはntdll.dllライブラリ内のネイティブAPIの一部です。これは、通常のWindows APIの実装で使用される文書化されていない API であり、Windows 上の一部のシステム プログラムによって直接使用されます。 ライブラリのラッパー関数は、システム コールを使用するための通常の関数呼び出し規約(アセンブリレベルのサブルーチン呼び出し) を公開するとともに、システム コールをよりモジュール化します。 ここで、ラッパーの主な機能は、システム コールに渡されるすべての引数を適切なプロセッサ レジスタ(および場合によっては呼び出しスタック) に配置し、カーネルが呼び出す一意のシステム コール番号を設定することです。 このように、OS とアプリケーションの間に存在するライブラリは、移植性を高めます。
ライブラリ関数の呼び出し自体はカーネル モードへの切り替えを引き起こさず、通常は通常のサブルーチン呼び出しです(たとえば、一部の命令セット アーキテクチャ(ISA) の "CALL" アセンブリ命令を使用)。実際のシステム コールはカーネルに制御を移します (また、それを抽象化するライブラリ呼び出しよりも実装およびプラットフォームに依存します)。たとえば、Unix 系システムでは、forkおよびexecveは C ライブラリ関数であり、順に、forkおよびシステム コールを呼び出す命令を実行します。アプリケーション コードexecで直接システム コールを行うのはより複雑で、埋め込みアセンブリ コードの使用が必要になる場合があります ( CおよびC++の場合)。また、システム コール操作の低レベル バイナリ インターフェイスの知識も必要になります。これは時間の経過とともに変更される可能性があり、したがってアプリケーション バイナリ インターフェイスの一部ではなくなる可能性があります。ライブラリ関数はこれを抽象化するためのものです。
エクソカーネルベースのシステムでは、ライブラリは仲介者として特に重要です。エクソカーネルでは、ライブラリはユーザー アプリケーションを非常に低レベルのカーネルAPIから保護し、抽象化とリソース管理を提供します。
IBMのOS/360、DOS/360、TSS/360は、アセンブリ言語マクロのライブラリを通じてほとんどのシステムコールを実装していますが、[b]呼び出しリンケージを持つサービスもいくつかあります。これは、アセンブリ言語でのプログラミングが高級言語の使用よりも一般的だった時代にその起源が生まれたことを反映しています。したがって、IBMのシステムコールは高級言語プログラムによって直接実行することはできず、呼び出し可能なアセンブリ言語ラッパーサブルーチンが必要でした。それ以来、IBMは、z/OSやz/VSEなどの高級言語から呼び出すことができる多くのサービスを追加しました。最近のMVS/SPのリリースとそれ以降のすべてのMVSバージョンでは、一部のシステムコールマクロがプログラム呼び出し(PC)を生成します。
例とツール
Unix、Unix系、その他のPOSIX準拠のオペレーティングシステムでは、よく使われるシステムコールはopen、、、、、、、、、、およびです。最近のオペレーティングシステムの多くreadは、数百のシステムコールを持っています。例えば、writeLinuxとOpenBSDにはそれぞれ300を超えるシステムコールがあり、[2]close [ 3]、wait NetBSDには500近くあり、[ 4] 、 FreeBSDには500以上あり、[5]、 Windowsにはwin32k(グラフィカル)とntdll(コア)のシステムコールに分かれて2000近くあり、[6]、Plan 9には51があります。[7]execforkexitkill
strace、ftrace、trussなどのツールを使用すると、プロセスを開始から実行して、プロセスが呼び出すすべてのシステム コールを報告したり、すでに実行中のプロセスに接続して、そのプロセスが実行したシステム コールを、その操作がユーザーの権限に違反しない限り傍受したりできます。プログラムのこの特別な機能は、通常、ptraceなどのシステム コールや、 procfs内のファイルに対するシステムコールでも実装されます。
典型的な実装
システム コールを実装するには、ユーザー空間からカーネル空間への制御の移行が必要であり、これには何らかのアーキテクチャ固有の機能が関係します。これを実装する一般的な方法は、ソフトウェア割り込みまたはトラップを使用することです。割り込みはオペレーティング システムカーネルに制御を移行するため、ソフトウェアは必要なシステム コール番号をレジスタに設定し、ソフトウェア割り込みを実行するだけで済みます。
これは多くのRISCプロセッサに提供されている唯一の技術ですが、 x86などのCISCアーキテクチャは追加の技術をサポートしています。たとえば、x86命令セットには/と/命令が含まれています(これら2つのメカニズムはそれぞれAMDとIntelによって独立して作成されましたが、本質的には同じことを行います)。これらは、割り込みのオーバーヘッドなしでシステムコールの制御をカーネルにすばやく転送するように設計された「高速」制御転送命令です。[8] Linux 2.5は、利用可能なx86でこれを使用し始めました。以前は、割り込み0x80が実行される前にシステムコール番号がレジスタに格納される命令を使用していました。[9] [10]SYSCALLSYSRETSYSENTERSYSEXIT INTEAX
古いメカニズムにコールゲートがあります。これは元々Multicsで使用され、後にIntel x86のコールゲートなどにも使用されました。これにより、プログラムはオペレーティングシステムが事前に設定した安全な制御転送メカニズムを使用してカーネル関数を直接呼び出すことができます。このアプローチは x86 では人気がありませんが、これはおそらく、x86 のメモリセグメンテーションを使用する far call (現在のコードセグメントとは異なるセグメントにあるプロシージャの呼び出し[11] )が必要であり、その結果移植性が失われることと、前述のより高速な命令が存在することが原因です。
IA-64アーキテクチャでは、 EPC(Enter Privileged Code) 命令が使用されます。最初の 8 つのシステム コール引数はレジスタで渡され、残りはスタックで渡されます。
IBM System/360メインフレーム ファミリとその後継機種では、レジスタではなく命令に番号を持つスーパーバイザ コール命令( SVC ) によって、ほとんどの[c] IBM 独自のオペレーティング システムの従来の機能と Linux のすべてのシステム コールのシステム コールが実装されています。MVS の以降のバージョンでは、IBM は多くの新しい機能にプログラム コール (PC) 命令を使用しています。特に、呼び出し元がサービス要求ブロック(SRB) モードになっている可能性がある場合に、PC が使用されます。
PDP -11 ミニコンピュータは、IBM System/360 SVCや x86 INTと同様に、命令内にコードを配置するEMT、TRAP、およびIOT命令を使用していました。これらの命令は、特定のアドレスに割り込みを生成し、制御をオペレーティング システムに渡します。PDP-11 シリーズの後継であるVAX 32 ビットでは、さまざまなレベルの特権コードへのシステム コールを実行するためにCHMK、CHME、およびCHMS命令が使用されていました。コードは命令の引数です。
システムコールのカテゴリ
システムコールは、おおまかに6つの主要なカテゴリに分類できます。[12]
- プロセス制御
- ファイル管理
- ファイルの作成、ファイルの削除
- 開く、閉じる
- 読む、書く、再配置
- ファイル属性を取得/設定する
- デバイス管理
- デバイスの要求、デバイスの解放
- 読む、書く、再配置
- デバイス属性の取得/設定
- デバイスを論理的に接続または切断する
- 情報メンテナンス
- システム全体の情報を取得/設定します (時間、日付、コンピューター名、エンタープライズなどを含む)
- プロセス、ファイル、またはデバイスのメタデータを取得/設定します (作成者、オープナー、作成日時などを含む)
- コミュニケーション
- 通信接続の作成、削除
- メッセージを送信、受信する
- 転送ステータス情報
- リモートデバイスの接続または切断
- 保護
- ファイルの権限を取得/設定する
プロセッサモードとコンテキスト切り替え
ほとんどのUnix 系システムでは、システムコールはカーネルモードで処理されます。これは、プロセッサ実行モードをより特権モードに変更することで実現されますが、プロセスの コンテキストスイッチは必要ありません。ただし、特権コンテキストスイッチは発生します。ハードウェアは、プロセッサステータスレジスタに従って実行モードの観点から世界を認識し、プロセスはオペレーティングシステムによって提供される抽象化です。システムコールは通常、別のプロセスへのコンテキストスイッチを必要とせず、代わりに、それを呼び出したプロセスのコンテキストで処理されます。[13] [14]
マルチスレッドプロセスでは、複数のスレッドからシステムコールを行うことができます。このような呼び出しの処理は、特定のオペレーティングシステムカーネルとアプリケーションランタイム環境の設計に依存します。次のリストは、オペレーティングシステムが従う典型的なモデルを示しています。[15] [16]
- 多対 1モデル: プロセス内の任意のユーザー スレッドからのすべてのシステム コールは、単一のカーネル レベル スレッドによって処理されます。このモデルには重大な欠点があります。ブロッキング システム コール (ユーザーからの入力待ちなど) によって、他のすべてのスレッドがフリーズする可能性があります。また、一度に 1 つのスレッドしかカーネルにアクセスできないため、このモデルでは複数のプロセッサ コアを利用できません。
- 1 対 1モデル: システム コール中、すべてのユーザー スレッドは個別のカーネル レベル スレッドに接続されます。このモデルは、システム コールをブロックするという上記の問題を解決します。このモデルは、すべての主要なLinux ディストリビューション、macOS、iOS、最近のWindowsおよびSolarisバージョンで採用されています。
- 多対多モデル: このモデルでは、ユーザー スレッドのプールがカーネル スレッドのプールにマップされます。ユーザー スレッド プールからのすべてのシステム コールは、対応するカーネルスレッド プール内のスレッドによって処理されます。
- ハイブリッドモデル: このモデルは、カーネルの選択に応じて、多対多モデルと 1 対 1 モデルの両方を実装します。これは、IRIX、HP-UX、およびSolarisの古いバージョンで使用されています。
参照
注記
参考文献
- ^ IBM (1967 年 3 月)。「SVC ルーチンの作成」。IBM System/360 オペレーティング システム システム プログラマーズ ガイド(PDF)。第 3 版。32 ~ 36 ページ。C28-6550-2。
- ^ "syscalls(2) - Linuxマニュアルページ".
- ^ OpenBSD (2013年9月14日). 「システムコール名 (kern/syscalls.c)」. BSD 相互参照.
- ^ NetBSD (2013年10月17日). 「システムコール名 (kern/syscalls.c)」. BSD 相互参照.
- ^ 「FreeBSD syscalls.c、システムコール名と ID のリスト」。
- ^ マテウシュ「j00ru」ユルチク (2017 年 11 月 5 日)。 「Windows WIN32K.SYS システムコールテーブル (NT/2000/XP/2003/Vista/2008/7/8/10)」。
{{cite web}}: CS1 maint: 数値名: 著者リスト (リンク) - ^ "sys.h".ベル研究所の Plan 9。2023年9月8日時点のオリジナルよりアーカイブ。システムコール名と ID のリスト。
- ^ “SYSENTER”. OSDev wiki . 2023年11月8日時点のオリジナルよりアーカイブ。
- ^ 匿名 (2002 年 12 月 19 日). 「Linux 2.5 で vsyscalls、sysenter のサポートが開始」KernelTrap . 2008 年1 月 1 日閲覧。
- ^ Manu Garg (2006)。「Linux 2.6 の Sysenter ベースのシステム コール メカニズム」。
- ^ 「Liberation: x86 命令セットリファレンス」renejeschke.de . 2015年7月4日閲覧。
- ^ Silberschatz, Abraham (2018).オペレーティングシステムの概念。Peter B Galvin、Greg Gagne (第10版)。ホーボーケン、ニュージャージー州: Wiley。p. 67。ISBN 9781119320913. OCLC 1004849022.
- ^ Bach, Maurice J. (1986)、「UNIXオペレーティングシステムの設計」、Prentice Hall、pp. 15-16。
- ^ Elliot, John (2011). 「ProgClub でのシステムコール実装に関する議論、Bach 1986 からの引用を含む」。2012 年 7 月 24 日時点のオリジナルよりアーカイブ。2011年10 月 1 日閲覧。
- ^ 「スレッド」.
- ^ 「スレッドモデル」(PDF)。
外部リンク
- 最新の Unix 系システムコールの一覧
- 主な API 関数と構造を含むインタラクティブな Linux カーネル マップ (PDF 版)
- Linux システム コール - IA-32呼び出し規約を使用したLinux カーネル2.2のシステム コール
- Linux/i86 でのシステムコールの動作 (1996、1993 0.99.2 カーネルに基づく)
- Linux 2.6 の Sysenter ベースのシステム コール メカニズム (2006)
- Linux システムコールを使用したカーネルコマンド、IBM developerWorks
- Choudhary、Amit; Linux 2.6 でシステム コールを実装するための HOWTO
- Jorrit N. Herder、Herbert Bos、Ben Gras、Philip Homburg、Andrew S. Tanenbaum、「Minix 3 でのモジュラー システム プログラミング」、;login: 31、第 2 号 (2006 年 4 月)、19 ~ 28 ページ、2018 年 3 月 5 日にアクセス
- C 言語で書かれたシンプルなオープン Unix シェル - Unix でのシステム コールの例
- ネイティブ API の内部 – Windows NT ネイティブ API (システム コールを含む)
- Gulbrandsen, John; SYSENTER 命令によるシステム コールの最適化、CodeGuru.com、2004 年 10 月 8 日
- osdev ウィキ
