0から作るソフトウェア開発
日々勉強中。。。 |
Follow @Nina_Petipa |
0から作るOS開発 割り込みその1 割り込みとIDTとGDT |
例外の割り込みベクタ | |||
---|---|---|---|
ベクタ番号 | ニーモニック | 説明 | 原因 |
0 | #DE |
除算エラー Divided by 0 |
0で割り算を行った DIV命令、IDIV命令 |
1 | #DB |
シングルステップ(デバッグ) Single Step(Debug) |
デバッガによるコード、データの参照 |
2 | - |
マスク不可割り込み NMI(Non-Maskable Interrupt) |
マスク不可能な外部割り込み |
3 | #BP |
ブレークポイント(デバッグ) Break Point(Debug) |
INT 3命令 |
4 | #OF |
オーバフロー Overflow |
INTO命令 |
5 | #BR |
バウンド範囲外 Bounds Check |
BOUND命令 |
6 | #UD |
無効なオペコード(未定義なオペコード) Undifined Operation Code Instruction |
UD2命令または無効なオペコード |
7 | #NM |
デバイス使用不可能(数値演算コプロセッサ無し) No Coprocessor |
浮動小数点命令、WAIT/FWAIT命令 |
8 | #DF |
ダブルフォルト Double Fault |
例外、NMI、INTRを生成できる命令 |
9 | #MF |
コプセッサセグメントオーバーラン Coprocessor Segment Overrun |
浮動小数点命令 Intel386プロセッサ以降のプロセッサでは生成されません |
10 | #TS |
無効なTSS(Task State Segments) Invalid TSS |
タスクスイッチ、TSSアクセス |
11 | #NP |
セグメントが不在 Segment Not Present |
セグメントレジスタのロード、システムセグメントへのアクセス |
12 | #SS |
スタックセグメントフォルト Stack Segment Fault |
スタック操作、SSレジスタのロード |
13 | #GP |
一般保護例外 General Protection Fault(GPF) |
メモリ参照、保護チェック |
14 | #PF |
ページフォルト Page Fault |
メモリ参照 |
15 | - | 予約 | - |
16 | #MF |
浮動小数点エラー(数値演算フォルト) Coprocessor Error |
浮動小数点命令、WAIT/FWAIT命令 |
17 | #AC |
アライメントチェック Alignment Check |
メモリ参照 Intel486プロセッサ以降のプロセッサで発生します |
18 | #MC |
マシンチェック Machine Check |
エラーコード、ソースがモデルに依存 インテルPentinumプロセッサ以降 |
19 | #XF |
SIMD浮動小数点例外 SIMD FPU Exception |
SIMD浮動小数点命令 |
20-31 | - | 予約 | - |
32-255 | - |
マスク可能割り込み IRQやソフトウェア割り込みの割り込みベクタとして使用します |
INTRピンによる外部割り込みまたはINT命令 |
IDTのディスクリプタ | ||
---|---|---|
ビット | ビット名称 | 説明 |
0-15 | Offset |
タスクゲート 使用しません |
割り込み/トラップゲート 割り込みハンドラのアドレスの下位16ビットを入れます |
||
16-31 | (TSS)Segment Selector |
タスクゲート TSSセグメントセレクタ |
割り込み/トラップゲート セグメントセレクタ (通常割り込みはring0で処理をするので、0x08のコードディスクリプタを設定します) |
||
31-35 | Unused | 使用しません |
36-39 | 0/Unused |
タスクゲート 使用しません |
割り込み/トラップゲート 0固定です |
||
40-42 | 0/1 |
タスクゲート 101b |
割り込みゲート 110b |
||
トラップゲート 111b |
||
43 | D |
ゲートのサイズを決定します 0:16ビット 1:32ビット 32ビットプロテクティッドモードですので、通常1に設定します |
44 | 0 | 0固定です |
45-46 |
DPL (Descriptor Plivilege Level) |
ディスクリプタの特権レベルを設定します(アクセス可能なレベルを設定します) セグメントセレクタで指定するRPLのレベルは現在実行中のレベルを意味します このディスクリプタにアクセスする場合はセグメントセレクタのRPLとこのDPLビットが比較されます |
47 |
セグメントプレゼントフラグ (Segment Present Flag) |
セグメントが存在するかどうかを設定します 0:セグメントは存在しない 1:セグメントは存在する 空のIDTのディスクリプタを作る場合はここに0を入れます |
48-63 | Offset |
タスクゲート 使用しません |
割り込み/トラップゲート 割り込みハンドラのアドレスの上位16ビットを入れます |
/* ================================================================================== Description : Gate Descriptor of IDT ================================================================================== */
typedef struct { unsigned short baseLo; unsigned short selector; unsigned char reserved; unsigned char flags; unsigned short baseHi; } __attribute__ ((packed)) GATE_DESCRIPTOR;
#define NUM_IDT 256
/* ================================================================================== Description : IDT ================================================================================== */
GATE_DESCRIPTOR idt[ NUM_IDT ];
/* ================================================================================== Description : IDTR ================================================================================== */
typedef struct { unsigned short size; GATE_DESCRIPTOR* base; } __attribute__ ((packed)) IDTR; IDTR idtr;
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Description : Definition for IDT Gate Descriptor Flags flags bit number description 0...4 interruptgate : 01110b = 32bit descriptor : 00110b = 16bit descriptor task gate : must be 00101b trap gate : 01111b = 32bit descriptor 5...6 descriptor privedlge : ring0 = 00b level : ring1 = 01b : ring2 = 10b : ring3 = 11b 7 present bit : Segment is present _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
#define DEF_IDT_FLAGS_INTGATE_16BIT 0x06 #define DEF_IDT_FLAGS_TSKGATE 0x05 #define DEF_IDT_FLAGS_CALL_GATE 0x0C #define DEF_IDT_FLAGS_INTGATE_32BIT 0x0E #define DEF_IDT_FLAGS_TRPGATE 0x0F #define DEF_IDT_FLAGS_DPL_LV0 0x00 #define DEF_IDT_FLAGS_DPL_LV1 0x20 #define DEF_IDT_FLAGS_DPL_LV2 0x40 #define DEF_IDT_FLAGS_DPL_LV3 0x60 #define DEF_IDT_FLAGS_PRESENT 0x80 #define DEF_IDT_INT_SELECTOR 0x08
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :setupInterruptGate Input :int int_num < interrupt number > void (interrupt_handller) ( ) < address of interrupt handller > Output :void Return :void Description :set up interrupt gate _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
void setupInterruptGate( int int_num, void *interrupt_handler ) { setupGateDescriptor( int_num, ( int )interrupt_handler, DEF_IDT_INT_SELECTOR, DEF_IDT_FLAGS_PRESENT | DEF_IDT_FLAGS_INTGATE_32BIT ); }
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :setupGateDescriptor Input :int int_num < interrupt number > int base < base address ( for interrupt and trap gate )> unsigned short selector < segment selector > unsigned char flags < flags of IDT > Output :void Return :void Description :set up gate descriptor _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
void setupGateDescriptor( int int_num, int base, unsigned short selector, unsigned char flags ) { idt[ int_num ].baseLo = ( unsigned short )( base & 0x0000FFFF ); idt[ int_num ].selector = selector; idt[ int_num ].reserved = 0x00; idt[ int_num ].flags = flags; idt[ int_num ].baseHi = ( unsigned short )( ( base & 0xFFFF0000 ) >> 16 ); }
idt[ int_num ].baseLo = ( unsigned short )( base & 0x0000FFFF );
idt[ int_num ].baseHi = ( unsigned short )( ( base & 0xFFFF0000 ) >> 16 );
idt[ int_num ].selector = selector;
idt[ int_num ].reserved = 0x00;
idt[ int_num ].flags = flags;
idtr.size = NUM_IDT * sizeof( GATE_DESCRIPTOR );
idtr.base = ( GATE_DESCRIPTOR *)idt;
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :load_idt Input :void Output :void Return :void Description :load idt _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
#define load_idt( ) ({ __asm__ __volatile__ ( "lidt idtr" ); })
idtr.size = NUM_IDT * sizeof( GATE_DESCRIPTOR );
idtr.base = ( GATE_DESCRIPTOR *)idt;
load_idt( );
セグメントディスクリプタ | ||
---|---|---|
ビット | ビット名称 | 説明 |
0-15 | Segment Limit Low |
そのセグメントのサイズを入れます。セグメントリミットは全部で20ビットのサイズですが ここは全20ビットのうち下位16ビット(0番目のビットから15番目のビット)を入れます |
16-31 | Base Address Low |
そのセグメントの開始アドレスを入れます。ベースアドレスは全部で32ビットのサイズですが ここは全32ビットのうち下位16ビット(0番目のビットから15番目のビット)を入れます |
32-39 | Base Address Mid |
そのセグメントの開始アドレスを入れます。ベースアドレスは全部で32ビットのサイズですが ここは全32ビットのうち中位8ビット(16番目のビットから23番目のビット)を入れます |
40-43 | Type |
セグメントのタイプを設定します。Sビットが1の場合ビット43でコードセグメントかデータセグメントか設定できます。
|
44 | S |
ディスクリプタタイプフラグです 0:システムセグメント用 1:コードセグメント、データセグメント用 |
45-46 | DPL |
Descriptor Plivilege Levelです。セグメントの特権レベルを設定します 0は最高位の特権レベル。リング0。0から3の値で指定します セグメントセレクタで指定するRPLのレベルは現在実行中のレベルを意味します セグメントにアクセスする場合はセグメントセレクタのRPLとこのDPLビットが比較されます |
47 | P |
Segment Present Flagです。セグメントがメモリ内に存在しているかどうかを設定します 0:セグメントがメモリ内に無い 1:セグメントがメモリ内に有る 通常はメモリ内にセグメントがありますので、1をセットします |
48-51 | Segment Limit Hi |
そのセグメントのサイズを入れます。セグメントリミットは全部で20ビットのサイズですが ここは全20ビットのうち上位4ビット(16番目のビットから19番目のビット)を入れます |
52 | AVL |
Availableフラグです。このビットについてはOS(カーネル)が自由に使用してよいビットとなります 使用目的は自由です |
54 | D/B |
デフォルトのオペレーションサイズを設定します 0:16ビット用のコードセグメント、データセグメントに使用します 1:32ビット用のコードセグメント、データセグメントに使用します |
55 | G |
Granularity Flag(グラニュラリティフラグ)です。セグメントリミットの単位を設定します 0:セグメントリミットの値をバイト単位として解釈します 1:セグメントリミットの値を×4Kバイト単位として解釈します 通常は1に設定します |
56-63 | Base Address Hi |
そのセグメントの開始アドレスを入れます。ベースアドレスは全部で32ビットのサイズですが ここは全32ビットのうち上位8ビット(24番目のビットから31番目のビット)を入れます |
/* ================================================================================== Description : Segment Descriptor of GDT ================================================================================== */
typedef struct { unsigned short limitLo; unsigned short baseLo; unsigned char baseMid; unsigned short flags; unsigned char baseHi; } __attribute__ ((packed)) SEGMENT_DESCRIPTOR;
#define NUM_GDT 3
/* ================================================================================== Description : GDT ================================================================================== */
SEGMENT_DESCRIPTOR gdt[ NUM_GDT ];
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Description :definition for Global descriptor flags bit number description 0...15 segment limit low 16...31 base address low 32...39 base address mid 40 access bit : unaccessed = 0b : accessed = 1b 41 read/write bit : read only = 0b : read/write = 1b 42 expansion direction : up direction = 0b : down direction = 1b 43 segment type : data segment = 0b : code segment = 1b 44 descriptor flag : for system segment = 0b : for code, data segment = 1b 45...46 descriptor privedlge : ring0 = 00b level : ring1 = 01b : ring2 = 10b : ring3 = 11b 47 present bit : Segment is present 48...51 segment limit hi 52 AVL : free to use by system program 53 reserved 54 d/b : for 16bit = 0b : for 32bit = 1b 55 G : unit of segment is byte : unit of segment is 4K 56...63 base address hi _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
#define NULL_DESCRIPTOR 0 #define CODE_DESCRIPTOR 1 #define DATA_DESCRIPTOR 2 #define TEMP_DESCRIPTOR 3 #define TASK_CODE_DESCRIPTOR 3 #define TASK_DATA_DESCRIPTOR 4 #define KTSS_DESCRIPTOR 5
/* Null Descriptor */
#define DEF_GDT_NULL_LIMIT 0x0000 #define DEF_GDT_NULL_BASELO 0x0000 #define DEF_GDT_NULL_BASEMID 0x00 #define DEF_GDT_NULL_FLAGS 0x0000 #define DEF_GDT_NULL_BASEHI 0x00
/* Code Descriptor */
#define DEF_GDT_CODE_LIMIT 0xFFFF #define DEF_GDT_CODE_BASELO 0x0000 #define DEF_GDT_CODE_BASEMID 0x00 #define DEF_GDT_CODE_FLAGS_BL 0x9A #define DEF_GDT_CODE_FLAGS_BH 0xCF #define DEF_GDT_CODE_FLAGS 0xCF9A #define DEF_GDT_CODE_BASEHI 0x00
/* Data Descriptor */
#define DEF_GDT_DATA_LIMIT 0xFFFF #define DEF_GDT_DATA_BASELO 0x0000 #define DEF_GDT_DATA_BASEMID 0x00 #define DEF_GDT_DATA_FLAGS 0xCF92 #define DEF_GDT_DATA_FLAGS_BL 0x92 #define DEF_GDT_DATA_FLAGS_BH 0xCF #define DEF_GDT_DATA_BASEHI 0x00
/* set up null descriptor */
gdt[ NULL_DESCRIPTOR ].limitLo = DEF_GDT_NULL_LIMIT;
gdt[ NULL_DESCRIPTOR ].baseLo = DEF_GDT_NULL_BASELO;
gdt[ NULL_DESCRIPTOR ].baseMid = DEF_GDT_NULL_BASEMID;
gdt[ NULL_DESCRIPTOR ].flags = DEF_GDT_NULL_FLAGS;
gdt[ NULL_DESCRIPTOR ].baseHi = DEF_GDT_NULL_BASEHI;
/* set up code descriptor */
gdt[ CODE_DESCRIPTOR ].limitLo = DEF_GDT_CODE_LIMIT;
gdt[ CODE_DESCRIPTOR ].baseLo = DEF_GDT_CODE_BASELO;
gdt[ CODE_DESCRIPTOR ].baseMid = DEF_GDT_CODE_BASEMID;
gdt[ CODE_DESCRIPTOR ].flags = DEF_GDT_CODE_FLAGS;
gdt[ CODE_DESCRIPTOR ].baseHi = DEF_GDT_CODE_BASEHI;
/* set up data descriptor */
gdt[ DATA_DESCRIPTOR ].limitLo = DEF_GDT_DATA_LIMIT;
gdt[ DATA_DESCRIPTOR ].baseLo = DEF_GDT_DATA_BASELO;
gdt[ DATA_DESCRIPTOR ].baseMid = DEF_GDT_DATA_BASEMID;
gdt[ DATA_DESCRIPTOR ].flags = DEF_GDT_DATA_FLAGS;
gdt[ DATA_DESCRIPTOR ].baseHi = DEF_GDT_DATA_BASEHI;
/* ================================================================================== Description : GDTR ================================================================================== */
typedef struct { unsigned short size; SEGMENT_DESCRIPTOR* base; } __attribute__ ((packed)) GDTR; GDTR gdtr;
gdtr.size = NUM_GDT * sizeof( SEGMENT_DESCRIPTOR );
gdtr.base = ( SEGMENT_DESCRIPTOR *)gdt;
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :load_gdt Input :void Output :void Return :void Description :load gdt _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
#define load_gdt( ) ({ __asm__ __volatile__ ( "lgdt gdtr" ); })
gdtr.size = NUM_GDT * sizeof( SEGMENT_DESCRIPTOR );
gdtr.base = ( SEGMENT_DESCRIPTOR *)gdt;
load_gdt( );
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :load_gdt Input :void Output :void Return :void Description :load gdt _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
PRIVATE INLINE VOID load_gdt( VOID ) { __asm__ __volatile__ ( "lgdt gdtr" ); __asm__ __volatile__ ( "mov %ax, 0x10" ); __asm__ __volatile__ ( "mov %ds, %ax" ); __asm__ __volatile__ ( "mov %es, %ax" ); __asm__ __volatile__ ( "mov %fs, %ax" ); __asm__ __volatile__ ( "mov %gs, %ax" ); __asm__ __volatile__ ( "mov %ss, %ax" ); __asm__ __volatile__ ( "jmp 0x08:_flush_seg" ); __asm__ __volatile__ ( "_flush_seg:" ); }
__asm__ __volatile__ ( "lgdt gdtr" );
__asm__ __volatile__ ( "mov %ax, 0x10" );
__asm__ __volatile__ ( "mov %ds, %ax" );
__asm__ __volatile__ ( "mov %es, %ax" );
__asm__ __volatile__ ( "mov %fs, %ax" );
__asm__ __volatile__ ( "mov %gs, %ax" );
__asm__ __volatile__ ( "mov %ss, %ax" );
__asm__ __volatile__ ( "jmp 0x08:_flush_seg" );
__asm__ __volatile__ ( "_flush_seg:" );
__asm__ __volatile__ ( "mov %ax, 0x08" );
__asm__ __volatile__ ( "mov %cs, %ax" );
//次の命令が続いています。
//この例では関数ですので、つぎにret命令が続くと想定します。
//(実際には__inline__してますので、多分違います。。。)
__asm__ __volatile__ ( "ret" );
//上記のret命令は説明のために追加しています。
__asm__ __volatile__ ( "jmp 0x08:_flush_seg" );
__asm__ __volatile__ ( "_flush_seg:" );