SlideShare a Scribd company logo
1 of 19
Download to read offline
4 章 Linux カーネル – 割り込み・例外 4
・例外ベクタと例外ハンドラ
・割り込みディスクリプタテーブル
・割り込み信号発生からハンドラ実行まで
・ハンドラ実行終了後の処理
・割り込み / 例外処理のネスト
mao
Web >https://www.pridact.com
Twitter >https://twitter.com/rivarten
Mail   >official@pridact.com
はじめに
割り込み・例外の話
視点
・概要
・ハードウェアの動作
・データ構造
・データ構造の操作の仕方
・ソースコード
ソースコードの情報が載っている場合は ,
実際にソースコードに目を通しながら資料を見ていっ
たほうがいいかもしれません。
今回はハードウェアの話が多いかもしれません
この資料について
・間違っていたらご指摘をお願い致します。
・ Linux Kernel のバージョンは 4.9.16 です。
・ページタイトルに * 印が付いているページは、
 少し踏み込んだ内容になっています。
 ざっと全体に目を通したければ、読み飛ばして
 もらっても構いません。
カーネル参考文献
< 参考書 >
 〜基本的に古い情報だが、基本は学べる〜
・詳解 LINUX カーネル 第 3 版 (O’REILLY
・ Linux カーネル 2.6 解読室 (Softbank Creative
・ Linux カーネル解析入門 ( 工学社
・ Modern Operating Systems 3e International
(Pearson, Andrew S. Tanenbaum)
 〜初期化部分を知りたいなら〜
・新装改訂版 Linux のブートプロセスを見る
( アスキー・メディアワークス )
< 参考 Web>
・ Linux Cross Reference[http://lxr.free-electrons.com]
・ Wikipedia
例外ベクタと例外ハンドラ (1)
・例外ベクタ (x86)
ベクタ番号 名前 種類 説明
0 除算エラー (Devide Error) フォルト プログラムが 0 で整数除算すると発生
1
デバッグ例外 (Debug) トラップ ,
フォルト
eflags レジスタの TF=1 で発生 ( デバッガでの
ステップ実行に有用 ). 有効化したデバッグレ
ジスタのアドレス範囲内にある命令を実行し
たり , オペランドへアクセスしたりした時もデ
バッグ例外が発生 .
2
マスク不可割り込み (Non-Maskable
Interrupt) ---
マスク不可割り込み用に予約
(NMI ピンを使用 )
3
ブレークポイント (Breakpoint) トラップ int3( ブレークポイント ) 命令によって発生 .
通常はデバッガがこの命令を埋め込む .
4
オーバーフロー (Overflow) トラップ into( オーバーフローを調べる ) 命令を実行し
た時に ,eflags レジスタの OF(overflow) レジス
タ フラグが設定されている場合に発生
5
Bound 範囲超過 (Bounds check) フォルト bound( アドレス範囲を調べる ) 命令を , アドレ
スの有効範囲外にあるオペランドとともに実
行すると発生 .
6
無効オペコード (Invalid opcode) フォルト CPU が無効なオペコード ( 実行する動作を決
定するマシン語の一部 ) を検出すると発生
7
デバイス使用不可能 (Device not
available)
フォル ESCAPE 命令 ,MMX 命令 ,SSE/SSE2 命令を
実行した時に ,cr0 レジスタの TS フラグが設
定されている場合に発生
例外ベクタと例外ハンドラ (2)
・例外ベクタ (x86)
ベクタ番号 名前 種類 説明
8
ダブルフォルト (Double falult) アボート CPU が例外ハンドラを呼び出す時に別の例
外を検出すると , 通常 2 つの例外は順次処
理されるが , 稀にプロセッサが連続して処理
できない場合があり , その時に発生 .
9
コプロセッサセグメントオーバーラン
(Coprocessor segment overrun)
アボート 外部算術演算コプロセッサで問題が起こると
発生 . 古い 80386 プロセッサの場合にのみ発
生
10
無効 TSS(Invalid TSS) フォルト 無効な TSS を持つプロセスに切り替えようと
した場合に発生
11
セグメント不在 (Segment not present) フォルト メモリ中に存在しない ( セグメントディスクリプ
タの P フラグが設定されていない ) セグメント
を参照した場合に発生
12
スタックセグメントフォルト (Stack
segment fault)
フォルト 命令がスタックセグメントの範囲を越えようと
した場合 , または ss レジスタが指すセグメン
トがメモリ中に存在しない場合に発生 .
13
一般保護 (General protection) フォルト x86 のプロテクトモードの保護規則に違反し
た場合に発生
14
ページフォルト (Page fault) フォルト 参照されたページがメモリ上に存在しない
か , 対応するページテーブルエントリが NULL
か , ページング保護機構に違反した場合に発
生
例外ベクタと例外ハンドラ (3)
・例外ベクタ (x86)
ベクタ番号 名前 種類 説明
15 Intel が予約済み ---
16
浮動小数点エラー (Floating point error) フォルト CPU に組み込まれている浮動小数点回路が
エラーを検出した場合に発生 . 算術オーバー
フローやゼロ除算など .x86 では , 符号付き除
算の結果が符号付き整数にならない場合 (-
2,147,483,648/-1 など ) にも発生 .
17
アラインメントチェック (Alignment check) フォルト オペランドのアドレスが正しくアラインされて
いない場合に発生
18
マシンチェック アボート マシンチェック機構が CPU やバスのエラーを
検出した場合に発生 .
19
SIMD 浮動小数点例外 (SIMD floating
point exception)
フォルト CPU に組み込まれている SSE や SSE2 回路
が浮動小数点演算でエラーを検出した場合
に発生 .
20~31
将来のために Intel が予約
---
例外ベクタと例外ハンドラ (4)
・例外ハンドラ (x86)
ベクタ番号 例外 ハンドラ シグナル
0 除算エラー (Divide Error) divide_error() SIGFPE
1 デバッグ例外 (Debug) debug() SIGTRAP
2
マスク不可割り込み (Non-Maskable
Interrupt)
nmi()
---
3 ブレークポイント (Breakpoint) int3() SIGTRAP
4 オーバーフロー (Overflow) overflow() SIGSEGV
5 Bound 範囲超過 (Bounds check) bounds() SIGSEGV
6 無効オペコード (Invalid opcode) invalid_op() SIGILL
7
デバイス使用不可能 (Device not
available)
device_not_available()
---
8 ダブルフォルト (Double falult) doublefault_fn() ---
9
コプロセッサセグメントオーバーラン
(Coprocessor segment overrun)
coprocessor_segment_ove
rrun()
SIGFPE
10 無効 TSS(Invalid TSS) invalid_TSS() SIGSEGV
11 セグメント不在 (Segment not present) segment_not_present() SIGBUS
12
スタックセグメントフォルト (Stack
segment fault)
stack_segment() SIGBUS
例外ベクタと例外ハンドラ (5)
・例外ハンドラ (x86)
ベクタ番号 例外 ハンドラ シグナル
13 一般保護 (General protection) general_protection() SIGSEGV
14 ページフォルト (Page fault) page_fault() SIGSEGV
15 Intel が予約済み --- ---
16 浮動小数点エラー (Floating point error) coprocessor_error() SIGFPE
17 アラインメントチェック (Alignment check) alignment_check() SIGBUS
18 マシンチェック (Machine check) machine_check() ---
19
SIMD 浮動小数点例外 (SIMD floating
point exception)
simd_coprocessor_error() SIGFPE
割り込みディスクリプタテーブル (1)
・割り込みディスクリプタテーブル IDT
  (Interrupt Descriptor Table)
・割り込みや例外のベクタとハンドラのアドレスの対応を保持 .
・形式は GDT や LDT とほぼ同じ .
・ IDT 最大サイズは 256×8byte=2KB
・ IDT はメモリ上の任意の位置に置くことができる .
・ CPU の idtr レジスタに IDT のベースリニアアドレスとリミットを指定 .
・割り込みを使用する前に lidt アセンブリ命令で初期化する .
・ 40~43bit(type) の内容がディスクリプタの種類を表している .
・ディスクリプタの種類
・タスクゲート
・割り込みゲート
・トラップゲート
Linux では , 割り込み処理に割り込みゲートを使用し ,
例外処理にトラップゲートを使用している .
割り込みディスクリプタテーブル (2)
・タスクゲート
プロセスの TSS セレクタを置く .
割り込み信号が発生した時に実行中のプロセスの TSS と置き換えられる .
ダブルフォルト例外は , カーネルの不正処理を表していて ,
Linux においてタスクゲートを用いる唯一の例外 .
割り込みディスクリプタテーブル (3)
・割り込みゲート
割り込み・例外のハンドラがあるセグメントの
セグメントセレクタとセグメント内でのオフセットを置く .
このセグメントに制御を移す間は ,
プロセッサは eflags.if=0 にしてマスク可能割り込みを禁止する .
割り込みディスクリプタテーブル (4)
・トラップゲート
割り込みゲートと同様だが , 別のセグメントに制御を移す間でも ,
プロセッサが eflags.if フラグを変更しない点で異なる .
割り込み信号発生からハンドラ実行まで (1)
・前提条件
 ・カーネルの初期化が完了し ,CPU がプロテクトモードで動作している .
0. ある 1 つの命令を実行後 ,cs/eip レジスタは次に実行すべき命令のアドレ
 スが入っている . これを実行する前に , 制御回路は前の命令の実行中に
 割り込み・例外が発生していないかを調べる (INTR,NMI を調べる )
 発生していれば , 制御回路は以降の処理を進める .
1. 割り込み・例外に対応するベクタ (0≦i≦255) を取得する .
2.idtr レジスタが指す IDT から i 番目のエントリを読み取る .
  ( 該当エントリには割り込みゲートかトラップゲートが存在する )
3.gdtr レジスタから GDT ベースアドレスを取得し ,
  GDT 内から IDT エントリのセレクタがさすセグメントディスクリプタを取得 .
 このディスクリプタに , 割り込み / 例外ハンドラがあるセグメントのベースア
 ドレスがある .
割り込み信号発生からハンドラ実行まで (2)
4. 割り込み元の正当性の確認 .
・ cs レジスタの CPL と GDT 内のセグメントディスクリプタの DPL を比較 .
  CPL: 割り込みを発生させたプログラムの現行特権レベル
  DPL: セグメントアクセスに必要な特権レベル
・ DPL の特権レベルより CPL の特権レベルの方が低い
  ( 値としては ,CPL>DPL)
 ⇒一般保護例外 .
  割り込みハンドラは , 割り込みを発生させたプログラムより
  低い特権レベルでは動作できない .
・ OK
 ソフトウェア的に生成された割り込み / 例外の場合 (int n,int 3,into
 命令等 ), さらなるセキュリティチェックを行う .
・ CPL と IDT 内のセグメントディスクリプタの DPL を比較
・ DPL の特権レベルより CPL の特権レベルの方が低い
  ( 値としては ,CPL>DPL)
 ⇒一般保護例外 .
   ユーザアプリケーションによるトラップゲートや割り込み
   ゲートへのアクセスを防ぐ .
割り込み信号発生からハンドラ実行まで (3)
5. 特権レベルが変更されているかを調べる .
CPL ≠ セグメントディスクリプタの DPL
⇒ 制御回路は新しい特権レベル用のスタックを用意する .
a. tr レジスタを読み取り , 実行中のプロセスの TSS にアクセス .
b. ss/esp レジスタに ,TSS に置かれている新しい特権レベル用の
 論理アドレスを ss/esp に読み込む .
c. 古い特権レベル用スタックの論理アドレスを表す ss/esp を ,
 新しいスタックに退避 .
6. フォルトが発生した場合 , 例外を発生させた命令の論理アドレスを
  cs/eip に読み込む . これで再実行が可能になる .
7. スタックに eflags,cs,eip レジスタの内容を退避する .
8. 例外がハードウェアエラーコードを持っていれば , スタックに退避する .
9.IDT 内の i 番目のエントリにあるセグメントセレクタとゲートディスクリプタの
 オフセットフィールドを ,cs/eip レジスタに読み込む .
 これが割り込み・例外ハンドラの最初の命令の論理アドレスを表す .
push 順 :[ss,esp] → [eflags,cs,eip] → ( ハードウェアエラーコード )
ハンドラ実行終了後の処理
iret 命令を実行して , 割り込まれたプロセスに制御を移す .
pop 順 :[ss,esp] ← [eflags,cs,eip] ← ( ハードウェアエラーコード )
1. スタックに退避されている cs,eip,eflags レジスタの値を読み込む .
2. ハンドラの CPL が ,cs の CPL と同じかどうか調べる .
  ( 割り込まれたプロセスがハンドラと同じ特権レベルで動作していたか )
 ・同じ⇒ iret は実行を終了
 ・違う⇒次のステップに進む .
3. スタックから ss/esp レジスタを読み込む .
  ( 古い特権レベル用のスタックに戻る )
4.ds,es,fs,gs セグメントレジスタを調べる .
  CPL の特権レベル > DPL の特権レベル ( 値は ,CPL<DPL) となるセグメン
 トディスクリプタを参照するセレクタがあれば ,
 そのセグメントレジスタをクリア .
カーネルルーチンが実行したセグメントを , それより特権レベルが低いプロセスが使用してしまう事を防ぐ .
クリアしなければ , カーネル空間にアクセス可能になってしまう .
割り込み・例外処理のネスト (1)
・割り込み / 例外のカーネル実行パスがネストすることもある .
・カーネル実行パスのネストを許可する条件
 「割り込みハンドラ実行中に絶対にプロセスを切り替えないこと」
カーネル実行パスを再開させる為に必要なデータは ,
カレントプロセスのカーネルスタックに積まれる為 ,
割り込みハンドラ動作中に , 他のプロセスに切り替えられない .
・例外のほとんどはユーザーモードの時だけ発生 .
 ページフォルト例外はカーネルモードでも発生 .
システムコールのカーネル実行パス + ページフォルト例外のカーネル実行パス
・割り込みは , カレントプロセスのデータを参照しない .
・割り込みハンドラは , 別の割り込みハンドラや例外ハンドラに
 割り込むことがある .
・例外ハンドラが割り込みハンドラに割り込むことはない .
・マルチプロセッサにおいて , 例外用のカーネル実行パスは ,
 ある CPU で処理開始された後 , プロセスの切り替えによって ,
 別の CPU に移動することもある .
割り込み・例外処理のネスト (2)
・ Linux がカーネル実行パスのネストを許可する理由
1.PIC やデバイスコントローラのスループット向上 .
PIC やデバイスコントローラは ,
CPU から ACK を受取るまで処理を止めたまま .
カーネル実行パスを切り替えて動作させると , 他の割り込み処理の
実行中であっても , カーネルが ACK を返すことができる .
2. 優先度レベルがない割り込みモデルを実現できる .
割り込みハンドラは , 他の割り込みハンドラの処理を遅延できる為 ,
デバイスに優先順位をあらかじめ与えておく必要がない .
これにより , カーネルコードが単純化でき , 移植性が向上 .

More Related Content

What's hot

BGP Unnumbered で遊んでみた
BGP Unnumbered で遊んでみたBGP Unnumbered で遊んでみた
BGP Unnumbered で遊んでみたakira6592
 
introduction to linux kernel tcp/ip ptocotol stack
introduction to linux kernel tcp/ip ptocotol stack introduction to linux kernel tcp/ip ptocotol stack
introduction to linux kernel tcp/ip ptocotol stack monad bobo
 
eBPF - Rethinking the Linux Kernel
eBPF - Rethinking the Linux KerneleBPF - Rethinking the Linux Kernel
eBPF - Rethinking the Linux KernelThomas Graf
 
Lxc で始めるケチケチ仮想化生活?!
Lxc で始めるケチケチ仮想化生活?!Lxc で始めるケチケチ仮想化生活?!
Lxc で始めるケチケチ仮想化生活?!Etsuji Nakai
 
ARM Trusted FirmwareのBL31を単体で使う!
ARM Trusted FirmwareのBL31を単体で使う!ARM Trusted FirmwareのBL31を単体で使う!
ARM Trusted FirmwareのBL31を単体で使う!Mr. Vengineer
 
大規模DCのネットワークデザイン
大規模DCのネットワークデザイン大規模DCのネットワークデザイン
大規模DCのネットワークデザインMasayuki Kobayashi
 
Introduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and DracutIntroduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and DracutTaisuke Yamada
 
0章 Linuxカーネルを読む前に最低限知っておくべきこと
0章 Linuxカーネルを読む前に最低限知っておくべきこと0章 Linuxカーネルを読む前に最低限知っておくべきこと
0章 Linuxカーネルを読む前に最低限知っておくべきことmao999
 
UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動uchan_nos
 
ELFの動的リンク
ELFの動的リンクELFの動的リンク
ELFの動的リンク7shi
 
今だからこそ知りたい Docker Compose/Swarm 入門
今だからこそ知りたい Docker Compose/Swarm 入門今だからこそ知りたい Docker Compose/Swarm 入門
今だからこそ知りたい Docker Compose/Swarm 入門Masahito Zembutsu
 
[232] 성능어디까지쥐어짜봤니 송태웅
[232] 성능어디까지쥐어짜봤니 송태웅[232] 성능어디까지쥐어짜봤니 송태웅
[232] 성능어디까지쥐어짜봤니 송태웅NAVER D2
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
Building Network Functions with eBPF & BCC
Building Network Functions with eBPF & BCCBuilding Network Functions with eBPF & BCC
Building Network Functions with eBPF & BCCKernel TLV
 
Fun with Network Interfaces
Fun with Network InterfacesFun with Network Interfaces
Fun with Network InterfacesKernel TLV
 
FD.io VPP事始め
FD.io VPP事始めFD.io VPP事始め
FD.io VPP事始めtetsusat
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)Kuniyasu Suzaki
 

What's hot (20)

eBPF Basics
eBPF BasicseBPF Basics
eBPF Basics
 
BGP Unnumbered で遊んでみた
BGP Unnumbered で遊んでみたBGP Unnumbered で遊んでみた
BGP Unnumbered で遊んでみた
 
introduction to linux kernel tcp/ip ptocotol stack
introduction to linux kernel tcp/ip ptocotol stack introduction to linux kernel tcp/ip ptocotol stack
introduction to linux kernel tcp/ip ptocotol stack
 
eBPF - Rethinking the Linux Kernel
eBPF - Rethinking the Linux KerneleBPF - Rethinking the Linux Kernel
eBPF - Rethinking the Linux Kernel
 
あなたのところに専用線が届くまで
あなたのところに専用線が届くまであなたのところに専用線が届くまで
あなたのところに専用線が届くまで
 
Lxc で始めるケチケチ仮想化生活?!
Lxc で始めるケチケチ仮想化生活?!Lxc で始めるケチケチ仮想化生活?!
Lxc で始めるケチケチ仮想化生活?!
 
ARM Trusted FirmwareのBL31を単体で使う!
ARM Trusted FirmwareのBL31を単体で使う!ARM Trusted FirmwareのBL31を単体で使う!
ARM Trusted FirmwareのBL31を単体で使う!
 
大規模DCのネットワークデザイン
大規模DCのネットワークデザイン大規模DCのネットワークデザイン
大規模DCのネットワークデザイン
 
Introduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and DracutIntroduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and Dracut
 
Dpdk performance
Dpdk performanceDpdk performance
Dpdk performance
 
0章 Linuxカーネルを読む前に最低限知っておくべきこと
0章 Linuxカーネルを読む前に最低限知っておくべきこと0章 Linuxカーネルを読む前に最低限知っておくべきこと
0章 Linuxカーネルを読む前に最低限知っておくべきこと
 
UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動
 
ELFの動的リンク
ELFの動的リンクELFの動的リンク
ELFの動的リンク
 
今だからこそ知りたい Docker Compose/Swarm 入門
今だからこそ知りたい Docker Compose/Swarm 入門今だからこそ知りたい Docker Compose/Swarm 入門
今だからこそ知りたい Docker Compose/Swarm 入門
 
[232] 성능어디까지쥐어짜봤니 송태웅
[232] 성능어디까지쥐어짜봤니 송태웅[232] 성능어디까지쥐어짜봤니 송태웅
[232] 성능어디까지쥐어짜봤니 송태웅
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
Building Network Functions with eBPF & BCC
Building Network Functions with eBPF & BCCBuilding Network Functions with eBPF & BCC
Building Network Functions with eBPF & BCC
 
Fun with Network Interfaces
Fun with Network InterfacesFun with Network Interfaces
Fun with Network Interfaces
 
FD.io VPP事始め
FD.io VPP事始めFD.io VPP事始め
FD.io VPP事始め
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
 

Similar to 4章 Linuxカーネル - 割り込み・例外 4

Dalvik仮想マシンのアーキテクチャ 改訂版
Dalvik仮想マシンのアーキテクチャ 改訂版Dalvik仮想マシンのアーキテクチャ 改訂版
Dalvik仮想マシンのアーキテクチャ 改訂版Takuya Matsunaga
 
Exploring the x64
Exploring the x64Exploring the x64
Exploring the x64FFRI, Inc.
 
2014 1018 OSC-Fall Tokyo NETMF
2014 1018 OSC-Fall Tokyo NETMF2014 1018 OSC-Fall Tokyo NETMF
2014 1018 OSC-Fall Tokyo NETMFAtomu Hidaka
 
Android デバッグ小ネタ
Android デバッグ小ネタAndroid デバッグ小ネタ
Android デバッグ小ネタl_b__
 
2014 dart flight school in Tokyo
2014 dart flight school in Tokyo2014 dart flight school in Tokyo
2014 dart flight school in Tokyonothingcosmos
 
Secure element for IoT device
Secure element for IoT deviceSecure element for IoT device
Secure element for IoT deviceKentaro Mitsuyasu
 
ソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdf
ソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdfソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdf
ソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdf耕二 阿部
 
Tremaで試すFirewall
Tremaで試すFirewallTremaで試すFirewall
Tremaで試すFirewallM Hagiwara
 
Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版Takuya Matsunaga
 
CLRの基礎 - プログラミング .NET Framework 第3版 読書会
CLRの基礎 - プログラミング .NET Framework 第3版 読書会CLRの基礎 - プログラミング .NET Framework 第3版 読書会
CLRの基礎 - プログラミング .NET Framework 第3版 読書会Yoshihisa Ozaki
 
4章 Linuxカーネル - 割り込み・例外 5
4章 Linuxカーネル - 割り込み・例外 54章 Linuxカーネル - 割り込み・例外 5
4章 Linuxカーネル - 割り込み・例外 5mao999
 
201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト
201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト
201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキストVxRail ChampionClub
 
Meltdown を正しく理解する
Meltdown を正しく理解するMeltdown を正しく理解する
Meltdown を正しく理解するNorimasa FUJITA
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overviewRyo Sakamoto
 
2012-04-25 ASPLOS2012出張報告(公開版)
2012-04-25 ASPLOS2012出張報告(公開版)2012-04-25 ASPLOS2012出張報告(公開版)
2012-04-25 ASPLOS2012出張報告(公開版)Takahiro Shinagawa
 
ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門Hirotaka Kawata
 
seccamp2012 チューター発表
seccamp2012 チューター発表seccamp2012 チューター発表
seccamp2012 チューター発表Hirotaka Kawata
 

Similar to 4章 Linuxカーネル - 割り込み・例外 4 (20)

Dalvik仮想マシンのアーキテクチャ 改訂版
Dalvik仮想マシンのアーキテクチャ 改訂版Dalvik仮想マシンのアーキテクチャ 改訂版
Dalvik仮想マシンのアーキテクチャ 改訂版
 
Exploring the x64
Exploring the x64Exploring the x64
Exploring the x64
 
Interrupts on xv6
Interrupts on xv6Interrupts on xv6
Interrupts on xv6
 
Reconf 201901
Reconf 201901Reconf 201901
Reconf 201901
 
2014 1018 OSC-Fall Tokyo NETMF
2014 1018 OSC-Fall Tokyo NETMF2014 1018 OSC-Fall Tokyo NETMF
2014 1018 OSC-Fall Tokyo NETMF
 
Android デバッグ小ネタ
Android デバッグ小ネタAndroid デバッグ小ネタ
Android デバッグ小ネタ
 
2014 dart flight school in Tokyo
2014 dart flight school in Tokyo2014 dart flight school in Tokyo
2014 dart flight school in Tokyo
 
Secure element for IoT device
Secure element for IoT deviceSecure element for IoT device
Secure element for IoT device
 
ソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdf
ソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdfソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdf
ソフトウェア設計原則【SOLID】を学ぶ #2 インターフェイス分離の原則.pdf
 
Tremaで試すFirewall
Tremaで試すFirewallTremaで試すFirewall
Tremaで試すFirewall
 
Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版
 
CLRの基礎 - プログラミング .NET Framework 第3版 読書会
CLRの基礎 - プログラミング .NET Framework 第3版 読書会CLRの基礎 - プログラミング .NET Framework 第3版 読書会
CLRの基礎 - プログラミング .NET Framework 第3版 読書会
 
4章 Linuxカーネル - 割り込み・例外 5
4章 Linuxカーネル - 割り込み・例外 54章 Linuxカーネル - 割り込み・例外 5
4章 Linuxカーネル - 割り込み・例外 5
 
201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト
201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト
201711 vxrailチャンピオンクラブ_ワークショップ~入門編~テキスト
 
Meltdown を正しく理解する
Meltdown を正しく理解するMeltdown を正しく理解する
Meltdown を正しく理解する
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overview
 
2012-04-25 ASPLOS2012出張報告(公開版)
2012-04-25 ASPLOS2012出張報告(公開版)2012-04-25 ASPLOS2012出張報告(公開版)
2012-04-25 ASPLOS2012出張報告(公開版)
 
Source Code of Dart
Source Code of DartSource Code of Dart
Source Code of Dart
 
ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門
 
seccamp2012 チューター発表
seccamp2012 チューター発表seccamp2012 チューター発表
seccamp2012 チューター発表
 

4章 Linuxカーネル - 割り込み・例外 4

  • 1. 4 章 Linux カーネル – 割り込み・例外 4 ・例外ベクタと例外ハンドラ ・割り込みディスクリプタテーブル ・割り込み信号発生からハンドラ実行まで ・ハンドラ実行終了後の処理 ・割り込み / 例外処理のネスト mao Web >https://www.pridact.com Twitter >https://twitter.com/rivarten Mail   >official@pridact.com
  • 3. この資料について ・間違っていたらご指摘をお願い致します。 ・ Linux Kernel のバージョンは 4.9.16 です。 ・ページタイトルに * 印が付いているページは、  少し踏み込んだ内容になっています。  ざっと全体に目を通したければ、読み飛ばして  もらっても構いません。
  • 4. カーネル参考文献 < 参考書 >  〜基本的に古い情報だが、基本は学べる〜 ・詳解 LINUX カーネル 第 3 版 (O’REILLY ・ Linux カーネル 2.6 解読室 (Softbank Creative ・ Linux カーネル解析入門 ( 工学社 ・ Modern Operating Systems 3e International (Pearson, Andrew S. Tanenbaum)  〜初期化部分を知りたいなら〜 ・新装改訂版 Linux のブートプロセスを見る ( アスキー・メディアワークス ) < 参考 Web> ・ Linux Cross Reference[http://lxr.free-electrons.com] ・ Wikipedia
  • 5. 例外ベクタと例外ハンドラ (1) ・例外ベクタ (x86) ベクタ番号 名前 種類 説明 0 除算エラー (Devide Error) フォルト プログラムが 0 で整数除算すると発生 1 デバッグ例外 (Debug) トラップ , フォルト eflags レジスタの TF=1 で発生 ( デバッガでの ステップ実行に有用 ). 有効化したデバッグレ ジスタのアドレス範囲内にある命令を実行し たり , オペランドへアクセスしたりした時もデ バッグ例外が発生 . 2 マスク不可割り込み (Non-Maskable Interrupt) --- マスク不可割り込み用に予約 (NMI ピンを使用 ) 3 ブレークポイント (Breakpoint) トラップ int3( ブレークポイント ) 命令によって発生 . 通常はデバッガがこの命令を埋め込む . 4 オーバーフロー (Overflow) トラップ into( オーバーフローを調べる ) 命令を実行し た時に ,eflags レジスタの OF(overflow) レジス タ フラグが設定されている場合に発生 5 Bound 範囲超過 (Bounds check) フォルト bound( アドレス範囲を調べる ) 命令を , アドレ スの有効範囲外にあるオペランドとともに実 行すると発生 . 6 無効オペコード (Invalid opcode) フォルト CPU が無効なオペコード ( 実行する動作を決 定するマシン語の一部 ) を検出すると発生 7 デバイス使用不可能 (Device not available) フォル ESCAPE 命令 ,MMX 命令 ,SSE/SSE2 命令を 実行した時に ,cr0 レジスタの TS フラグが設 定されている場合に発生
  • 6. 例外ベクタと例外ハンドラ (2) ・例外ベクタ (x86) ベクタ番号 名前 種類 説明 8 ダブルフォルト (Double falult) アボート CPU が例外ハンドラを呼び出す時に別の例 外を検出すると , 通常 2 つの例外は順次処 理されるが , 稀にプロセッサが連続して処理 できない場合があり , その時に発生 . 9 コプロセッサセグメントオーバーラン (Coprocessor segment overrun) アボート 外部算術演算コプロセッサで問題が起こると 発生 . 古い 80386 プロセッサの場合にのみ発 生 10 無効 TSS(Invalid TSS) フォルト 無効な TSS を持つプロセスに切り替えようと した場合に発生 11 セグメント不在 (Segment not present) フォルト メモリ中に存在しない ( セグメントディスクリプ タの P フラグが設定されていない ) セグメント を参照した場合に発生 12 スタックセグメントフォルト (Stack segment fault) フォルト 命令がスタックセグメントの範囲を越えようと した場合 , または ss レジスタが指すセグメン トがメモリ中に存在しない場合に発生 . 13 一般保護 (General protection) フォルト x86 のプロテクトモードの保護規則に違反し た場合に発生 14 ページフォルト (Page fault) フォルト 参照されたページがメモリ上に存在しない か , 対応するページテーブルエントリが NULL か , ページング保護機構に違反した場合に発 生
  • 7. 例外ベクタと例外ハンドラ (3) ・例外ベクタ (x86) ベクタ番号 名前 種類 説明 15 Intel が予約済み --- 16 浮動小数点エラー (Floating point error) フォルト CPU に組み込まれている浮動小数点回路が エラーを検出した場合に発生 . 算術オーバー フローやゼロ除算など .x86 では , 符号付き除 算の結果が符号付き整数にならない場合 (- 2,147,483,648/-1 など ) にも発生 . 17 アラインメントチェック (Alignment check) フォルト オペランドのアドレスが正しくアラインされて いない場合に発生 18 マシンチェック アボート マシンチェック機構が CPU やバスのエラーを 検出した場合に発生 . 19 SIMD 浮動小数点例外 (SIMD floating point exception) フォルト CPU に組み込まれている SSE や SSE2 回路 が浮動小数点演算でエラーを検出した場合 に発生 . 20~31 将来のために Intel が予約 ---
  • 8. 例外ベクタと例外ハンドラ (4) ・例外ハンドラ (x86) ベクタ番号 例外 ハンドラ シグナル 0 除算エラー (Divide Error) divide_error() SIGFPE 1 デバッグ例外 (Debug) debug() SIGTRAP 2 マスク不可割り込み (Non-Maskable Interrupt) nmi() --- 3 ブレークポイント (Breakpoint) int3() SIGTRAP 4 オーバーフロー (Overflow) overflow() SIGSEGV 5 Bound 範囲超過 (Bounds check) bounds() SIGSEGV 6 無効オペコード (Invalid opcode) invalid_op() SIGILL 7 デバイス使用不可能 (Device not available) device_not_available() --- 8 ダブルフォルト (Double falult) doublefault_fn() --- 9 コプロセッサセグメントオーバーラン (Coprocessor segment overrun) coprocessor_segment_ove rrun() SIGFPE 10 無効 TSS(Invalid TSS) invalid_TSS() SIGSEGV 11 セグメント不在 (Segment not present) segment_not_present() SIGBUS 12 スタックセグメントフォルト (Stack segment fault) stack_segment() SIGBUS
  • 9. 例外ベクタと例外ハンドラ (5) ・例外ハンドラ (x86) ベクタ番号 例外 ハンドラ シグナル 13 一般保護 (General protection) general_protection() SIGSEGV 14 ページフォルト (Page fault) page_fault() SIGSEGV 15 Intel が予約済み --- --- 16 浮動小数点エラー (Floating point error) coprocessor_error() SIGFPE 17 アラインメントチェック (Alignment check) alignment_check() SIGBUS 18 マシンチェック (Machine check) machine_check() --- 19 SIMD 浮動小数点例外 (SIMD floating point exception) simd_coprocessor_error() SIGFPE
  • 10. 割り込みディスクリプタテーブル (1) ・割り込みディスクリプタテーブル IDT   (Interrupt Descriptor Table) ・割り込みや例外のベクタとハンドラのアドレスの対応を保持 . ・形式は GDT や LDT とほぼ同じ . ・ IDT 最大サイズは 256×8byte=2KB ・ IDT はメモリ上の任意の位置に置くことができる . ・ CPU の idtr レジスタに IDT のベースリニアアドレスとリミットを指定 . ・割り込みを使用する前に lidt アセンブリ命令で初期化する . ・ 40~43bit(type) の内容がディスクリプタの種類を表している . ・ディスクリプタの種類 ・タスクゲート ・割り込みゲート ・トラップゲート Linux では , 割り込み処理に割り込みゲートを使用し , 例外処理にトラップゲートを使用している .
  • 11. 割り込みディスクリプタテーブル (2) ・タスクゲート プロセスの TSS セレクタを置く . 割り込み信号が発生した時に実行中のプロセスの TSS と置き換えられる . ダブルフォルト例外は , カーネルの不正処理を表していて , Linux においてタスクゲートを用いる唯一の例外 .
  • 13. 割り込みディスクリプタテーブル (4) ・トラップゲート 割り込みゲートと同様だが , 別のセグメントに制御を移す間でも , プロセッサが eflags.if フラグを変更しない点で異なる .
  • 14. 割り込み信号発生からハンドラ実行まで (1) ・前提条件  ・カーネルの初期化が完了し ,CPU がプロテクトモードで動作している . 0. ある 1 つの命令を実行後 ,cs/eip レジスタは次に実行すべき命令のアドレ  スが入っている . これを実行する前に , 制御回路は前の命令の実行中に  割り込み・例外が発生していないかを調べる (INTR,NMI を調べる )  発生していれば , 制御回路は以降の処理を進める . 1. 割り込み・例外に対応するベクタ (0≦i≦255) を取得する . 2.idtr レジスタが指す IDT から i 番目のエントリを読み取る .   ( 該当エントリには割り込みゲートかトラップゲートが存在する ) 3.gdtr レジスタから GDT ベースアドレスを取得し ,   GDT 内から IDT エントリのセレクタがさすセグメントディスクリプタを取得 .  このディスクリプタに , 割り込み / 例外ハンドラがあるセグメントのベースア  ドレスがある .
  • 15. 割り込み信号発生からハンドラ実行まで (2) 4. 割り込み元の正当性の確認 . ・ cs レジスタの CPL と GDT 内のセグメントディスクリプタの DPL を比較 .   CPL: 割り込みを発生させたプログラムの現行特権レベル   DPL: セグメントアクセスに必要な特権レベル ・ DPL の特権レベルより CPL の特権レベルの方が低い   ( 値としては ,CPL>DPL)  ⇒一般保護例外 .   割り込みハンドラは , 割り込みを発生させたプログラムより   低い特権レベルでは動作できない . ・ OK  ソフトウェア的に生成された割り込み / 例外の場合 (int n,int 3,into  命令等 ), さらなるセキュリティチェックを行う . ・ CPL と IDT 内のセグメントディスクリプタの DPL を比較 ・ DPL の特権レベルより CPL の特権レベルの方が低い   ( 値としては ,CPL>DPL)  ⇒一般保護例外 .    ユーザアプリケーションによるトラップゲートや割り込み    ゲートへのアクセスを防ぐ .
  • 16. 割り込み信号発生からハンドラ実行まで (3) 5. 特権レベルが変更されているかを調べる . CPL ≠ セグメントディスクリプタの DPL ⇒ 制御回路は新しい特権レベル用のスタックを用意する . a. tr レジスタを読み取り , 実行中のプロセスの TSS にアクセス . b. ss/esp レジスタに ,TSS に置かれている新しい特権レベル用の  論理アドレスを ss/esp に読み込む . c. 古い特権レベル用スタックの論理アドレスを表す ss/esp を ,  新しいスタックに退避 . 6. フォルトが発生した場合 , 例外を発生させた命令の論理アドレスを   cs/eip に読み込む . これで再実行が可能になる . 7. スタックに eflags,cs,eip レジスタの内容を退避する . 8. 例外がハードウェアエラーコードを持っていれば , スタックに退避する . 9.IDT 内の i 番目のエントリにあるセグメントセレクタとゲートディスクリプタの  オフセットフィールドを ,cs/eip レジスタに読み込む .  これが割り込み・例外ハンドラの最初の命令の論理アドレスを表す . push 順 :[ss,esp] → [eflags,cs,eip] → ( ハードウェアエラーコード )
  • 17. ハンドラ実行終了後の処理 iret 命令を実行して , 割り込まれたプロセスに制御を移す . pop 順 :[ss,esp] ← [eflags,cs,eip] ← ( ハードウェアエラーコード ) 1. スタックに退避されている cs,eip,eflags レジスタの値を読み込む . 2. ハンドラの CPL が ,cs の CPL と同じかどうか調べる .   ( 割り込まれたプロセスがハンドラと同じ特権レベルで動作していたか )  ・同じ⇒ iret は実行を終了  ・違う⇒次のステップに進む . 3. スタックから ss/esp レジスタを読み込む .   ( 古い特権レベル用のスタックに戻る ) 4.ds,es,fs,gs セグメントレジスタを調べる .   CPL の特権レベル > DPL の特権レベル ( 値は ,CPL<DPL) となるセグメン  トディスクリプタを参照するセレクタがあれば ,  そのセグメントレジスタをクリア . カーネルルーチンが実行したセグメントを , それより特権レベルが低いプロセスが使用してしまう事を防ぐ . クリアしなければ , カーネル空間にアクセス可能になってしまう .
  • 18. 割り込み・例外処理のネスト (1) ・割り込み / 例外のカーネル実行パスがネストすることもある . ・カーネル実行パスのネストを許可する条件  「割り込みハンドラ実行中に絶対にプロセスを切り替えないこと」 カーネル実行パスを再開させる為に必要なデータは , カレントプロセスのカーネルスタックに積まれる為 , 割り込みハンドラ動作中に , 他のプロセスに切り替えられない . ・例外のほとんどはユーザーモードの時だけ発生 .  ページフォルト例外はカーネルモードでも発生 . システムコールのカーネル実行パス + ページフォルト例外のカーネル実行パス ・割り込みは , カレントプロセスのデータを参照しない . ・割り込みハンドラは , 別の割り込みハンドラや例外ハンドラに  割り込むことがある . ・例外ハンドラが割り込みハンドラに割り込むことはない . ・マルチプロセッサにおいて , 例外用のカーネル実行パスは ,  ある CPU で処理開始された後 , プロセスの切り替えによって ,  別の CPU に移動することもある .
  • 19. 割り込み・例外処理のネスト (2) ・ Linux がカーネル実行パスのネストを許可する理由 1.PIC やデバイスコントローラのスループット向上 . PIC やデバイスコントローラは , CPU から ACK を受取るまで処理を止めたまま . カーネル実行パスを切り替えて動作させると , 他の割り込み処理の 実行中であっても , カーネルが ACK を返すことができる . 2. 優先度レベルがない割り込みモデルを実現できる . 割り込みハンドラは , 他の割り込みハンドラの処理を遅延できる為 , デバイスに優先順位をあらかじめ与えておく必要がない . これにより , カーネルコードが単純化でき , 移植性が向上 .