class: title, smokescreen, shelf, no-footer # 割り込み <div class=footnote> <small> 今回は短め。動作イメージのみ、実コードの解説もなし </small> </div> --- class: compact # はじめに <div class=footnote> <small> (脚注) 攻め=こちらから定期的に終わりましたか?と尋ねまくる方法もありますが、 それは効率がよくない </small> </div> カーネルに気づいてほしいイベントがある時に、それを知らせる処理が**割り込み**です 1. カーネルに気づいてほしいときとは? - エラーが発生しました - 下請け(のデバイス)さんから「依頼された仕事が終わったよ」と連絡したい - (ユーザプロセスが)カーネルさんにしかできない仕事を依頼したい 1. **特権権限**が必要な仕事 ... 下請けさんに出来ない処理はカーネルにしてもらうしかない - その典型がデバイスの制御 1. 仕事が終わったか?を知る方法は2種類(**攻めvs受け**?)考えられます - 処理が終わったら連絡して欲しいという方法として**割り込み**を用います - 次回「同期と排他制御」でも少し話します --- name: priviledged-processing class: title, smokescreen, shelf, no-footer # 特権処理 --- class: col-2,compact # カーネルだけが特権処理を行います <div class=footnote> <small> (脚注) 演習ではsuもしくはsudoコマンドで管理者になって行う操作をしています。 そういった<B>演習/実務</B>で行うシステム管理(例:ユーザ作成,パスワード変更)も<B>OS管理者だけが行う特権処理</B>ですが、 ほぼ<B>設定ファイルの編集権限の制御(Unixセキュリティ,ユーザ権限)</B>の話なので、 今回のテーマとは毛色が異なります </small> </div> - OSでは特権が必要な処理があります <br> **デバイスの入出力**が典型例で「だれでも出来る」のは危険です - たとえば、 **だれでもストレージに書きこめたら重要なデータを好きに書き換えでき**てしまいます。 各種入出力も同様で、入出力に介入できたら嘘の情報を入力、出力できます <wbr> - TSSでは、**カーネルだけが特権処理を実行できるように作成**します。 実現には**CPU**の**支援**が必要です <small> - なお、かつてのMS-DOS時代の(昔の)パソコンのように、 そういった概念がない(個人向け)OSもありましたが、 現代では、個人向け製品でも、きちんと権限の概念を持つべきでしょう (もちろん家電製品なら不要ということはありえます。 炊飯器や冷蔵庫には要らなそうです:-) </small> --- class: img-right,compact # OSの階層セキュリティモデル <div class=footnote> <small> <small> (脚注) カーネルはスーパバイザ、システムコールはスーパバイザコールとも呼ばれます。 本稿ではUnixに合わせてカーネルとシステムコールという用語を使います。 講義の後半、 仮想化の解説で<B>ハイパーバイザ</B>という用語が出てきますが、 これはsuperより上位の動作なのでhyperと呼んでいるのですよ:) </small> </small> </div> ![height240px](../basic/images/os_ring_model.png) ![height240px](images/food_scotch_egg.png) ![height180px](../../internal/process/images/easter_bunny.png) <small> - 階層構造のモデルを想定しています、言うなれば**卵**もしくは**玉ねぎ**型モデル - 真ん中(卵の黄身)は特権が必要とされるゾーン(**カーネル**に相当する部分) - 境界線(卵の殻=**シェル**)の通過が許可されているのは特別な命令のみです (ユーザプロセスからカーネルへの依頼が**システムコール** - 卵の外はユーザアプリを動作させる世界(**ユーザランド**)で**特権処理は不可**; いわばサーバ構築はイースターエッグのお絵描き? - CPUにも同様の卵/たまねぎ型の権限階層があります。 これが前提なのでOSも同じ**卵**型の階層 </small> --- class: title, smokescreen, shelf, no-footer # 通常処理を中断するイベント --- class: compact # 実行を一時中断するイベントは3種類 - CPUは機械語を読みながら処理を続けます。 特に何もなければ機械語を読みつづけ、実行しつづけます。 これが通常状態ですが、 この通常処理を一時**中断**して**特別な処理に移るイベント**が**3種類**あります。 | 種類 | 別名 | 備考 | |------------------------ |---------------------- |------------------------------------------ | | システムコール | ソフトウエア割り込み | ユーザプロセスからカーネルへ依頼する方法 | | 例外 | | 0で割り算やハードウエアエラーなど | | デバイスからの割り込み | ハードウエア割り込み | ハードウエアの制御 | --- class: compact # 実行を一時中断するイベントの別分類(基本情報処理試験) <div class=footnote> <small> <small> (脚注1) 基本情報処理試験の分類では、こうなっています。 仕方ないので、この用語も覚えてください。 Unixカーネルのソースコードでは、こういう区別をした書き方をしていないので、 本稿では無視して前頁の用語のまますすめます:-) <br> (脚注2) 中分類は前頁とあわせていますが、 基本情報処理試験では、もっと細かい分類をした用語を覚える必要がある? </small> </small> </div> - 割り込みは原因により二種類に大別できます。 実行中のプログラムが原因でおこるものを**内部割込み**と呼び, プログラムに関係なくおこるものを**外部割込み**と呼びます | 大分類 | 中分類 | 概要 | |-------------- |---------------------- |------------------ | | 内部割り込み | エラー | ゼロで割ったなど | | | システムコール | ユーザプロセスからカーネルへ依頼する方法 | | 外部割り込み | エラー | ハードウエア障害 | | | ハードウエア割り込み | ハードウエアの制御 | --- class: img-right,compact # システムコール: 特権処理をカーネルにおねがいする <div class=footnote> <small> <small> (脚注1) <B>コンテキスト切り替え(context switch)</B>は、 ユーザプロセスからカーネルプロセスへ切り替わる動作および逆の動作部分 <br> (脚注2) 3の処理が長い場合(例:HDD/SSDへの読み書き)、 途中で4へ進み、他のプロセスへswitchします。 3の処理終了(その合図が次頁)後のいつか、依頼主へ戻る4-5が行われますが、 その時期は3の処理とスケジューラ次第 (解説を適度な長さにするため不正確)。 </small> </small> </div> ![](images/syscall.png) ユーザプロセスは次のように動作します <small> 1. **システムコール**を呼び出すと、CPUにより処理が一時中断されます 1. ユーザプロセスの情報(コンテキスト) をメモリに保存します 1. カーネルに制御が移り、カーネルが依頼された処理を行います 1. 保存していたユーザプロセスの情報を復元し、 中断されたところから再開できるように準備 1. ユーザプロセスに戻り、中断されたところから処理を再開します </small> --- class: img-right,compact # ハードウエア割り込み: デバイスからの合図で処理を中断 <div class=footnote> <small> <small> (脚注1) <b>処理のトリガーが異なるだけ>で、動作は前頁と同様です</b> (前頁はプロセスから自発的に依頼、本頁はハードウエアから合図) <br> (脚注2) 図ではユーザプロセスですが、 割り込まれるプロセスはカーネル(が実行中の処理)のこともあります <br> (脚注3) 前頁の脚注にもあるように、 適度な長さに抑えるために正確さは犠牲 (モヤモヤする人は是非ソースコードを読もう!) </small> </small> </div> ![](images/trap.png) <small> ハードウエアから割り込み=終了の合図が送られてきます (右図の0;オレンジ色の部分) 1. CPUにより処理が一時中断されます 1. ユーザプロセスの情報(コンテキスト) をメモリに保存します 1. カーネルに制御が移り処理を行います **(例:HDD/SSDからの読み込み結果を返す準備)** 1. 保存していた情報を復元して中断されたところから再開できるように準備 1. ユーザプロセスに戻り、中断されたところから処理を再開します </small> --- class: img-right,compact # エラー: デバイスからの合図で処理を中断 <div class=footnote> <small> <small> (脚注1) 前半は前頁と同様ですが、後半は異なり、 プロセスを終了させることが多いです (ハードウエアからのエラーは致命的なレベルが普通なので処理を再開することは少ない)。 プロセスはzombieになり、後で死神=reaperが回収します:-)。 Unix Kernelではreaperという用語を使ってないですが、 他のソフトウエアではreaperという表現を使うことがよくあります (19世紀なかば以降の用例のようです) <br> (脚注2) 他の用例: CHAPTER 37: THE REAPER WHOSE NAME IS DEATH - L.M.Montgomery, Anne of Green Gables (1908) <br> (脚注3) この図は、実行中に0の割算などの致命的エラーがおきたケースです。 ハード障害などでは、そのハードを使おうとしたプロセスが終了するわけですが、 それは図で中断されたプロセスとは限らない。 前頁までと同様、不正確(全ケースを書くと長いぞ) </small> </small> </div> ![](images/fault.png) <small> エラーを知らせるために割込みをかけると 1. CPUにより現在実行中の処理が一時中断され 1. エラー情報とユーザプロセスの情報(コンテキスト) をメモリに保存します 1. カーネルに制御が移り、エラーに対応します。 たいていは致命的エラーなので該当するプロセスは終了です (死亡印をつけておきます) 1. プロセスに戻る途中でプロセスは終了 </small> --- class: img-right,compact # 割り込み優先度と多重割り込み <div class=footnote> <small> (脚注) 多重割り込みくらいまでは基本情報処理試験に出るから、やっておきますね... </small> </div> ![](images/trap-prilevel.png) - 各割り込みに優先度を設定しています - 致命的なエラーは最高優先度で割り込むべきだし、 時計も優先度を高くしないと時間が狂います - ストレージやネットワークの読み書きはエラーや時計ほど優先されなくても大丈夫 - 右図は、 ストレージ(HDD)の処理をしている途中で、時計のハードウエア割り込みがかかり、 優先度の高い時計の処理を一時おこなったあと再びストレージの処理にもどっている様子 --- class: title, smokescreen, shelf, no-footer # 発展: 割り込みとメモリレイアウト <div class=footnote> <small> 中間試験には出さないけれど、メモリレイアウト例と割り込みの関係を解説 </small> </div> --- class: img-right,compact # メモリ最下部にある割り込み設定の例 ![height480px](images/trapvec.png) <small> - DEC PDP11上のUnix第6版(16ビットCPU)における割り込み設定の例です。 縦はアドレスの番地(8進数)です。 横幅は32ビットで、16ビットの設定を2つ並べて書いています。 - メモリの一番下に、 アドレス0番地から上に向かい、 割り込みベクタの定義が並んでいます。 - たとえば時計(水晶振動子)からのハードウエア割り込みの場合、 アドレスの64番地から設定を読み込むようにハードウエアを作りこみます。 読み込むのは「時計の関数アドレス」と「優先度6」という設定で、 これらをCPUに設定します(そのような動作を自動的にするようCPUが作られています) </small> --- name: computer-basic class: title, smokescreen, shelf, no-footer # 付録: 割り込みベクタの例 <div class=footnote> <small> (脚注) 中間試験には出ません。解説も省略 </small> </div> --- class: compact # PDP11 割り込みベクタ |ベクタ位置 | 周辺デバイス | 割り込み優先度 | プロセス優先度 |-------|-----------------------|---------------|---------- |060 | テレタイプ入力 | 4 | 4 |064 | テレタイプ出力 | 4 | 4 |070 | 紙テープ出力 | 4 | 4 |074 | 紙テープ出力 | 4 | 4 |100 | クロック(電源周波数) | 6 | 6 |104 | クロック(プログラマブル) | 6 | 6 |200 | ラインプリンタ | 4 | 4 |220 | RKディクドライブ | 5 | 5 --- class: compact # PDP11 トラップベクタの例 |ベクタ位置 | トラップ種別 | プロセス優先度 |-------|-----------------------|------------ |004 | バスタイムアウト | 7 |010 | 不正命令 | 7 |014 | bpt トレース | 7 |020 | iot | 7 |024 | 電源異常 | 7 |030 | エミュレータトラップ命令 | 7 |034 | トラップ命令 | 7 |... | ... | ... |114 | 11/70 パリティ | 7 |240 | プログラムされた割込み | 7 |244 | 浮動小数点エラー | 7 |250 | セグメンテーション違反 | 7 --- # Intel 8086 割り込みベクタ |周辺デバイス | 割り込み番号 |------------------------|--------------- |タイマー | 0x08 |キーボード | 0x09 |RS-232C | 0x0B |RS-232C | 0x0C |フロッピーディスク | 0x0E --- class: compact # NEC PC-9800 割り込み番号の例 |周辺デバイス | 割り込み番号 |------------------------|--------------- |タイマー | 0x08 |キーボード | 0x09 |CRTC | 0x0A |RS-232C | 0x0C |フロッピーディスク | 0x13 --- class: img-right,compact # 8086 リアルモードにおける割り込み(キーボードの例) ![height480px](images/interrupt_8086_intvec.png) - 割り込みベクタはメモリ空間の先頭 1024 バイトに書かれており、 タイプひとつごとに 4 バイト(2 バイトの offset と 2 バイトの CS)を使用。 よってロードするベクタは「4 * (タイプ - 1)」の位置 1. 割り込みタイプ 09H がかかる 1. CS,IP,flags をスタックへ退避 1. 0024H からタイプ 09H の割り込みベクタをロードする 1. ロードした CS IP を実行する(キーボードの関数を呼び出して処理) 1. スタックへ退避しておいた CS,IP,flags を元に戻す