このXNUMX回目の記事では、理論と使用の両方でGDTと非常によく似た表を示します。IDTを参照します。 IDTは 割り込み説明表 yは、発生する割り込みを処理するために使用されるテーブルです。 たとえば、誰かが0で除算すると、処理を担当する関数が呼び出されます。 これらの関数はISR(割り込みサービスルーチン)。 それでは、IDTを作成して、ISRを追加しましょう。
まず、IDTに対応する構造を宣言します。
struct Entry{
uint16_t base_low;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
GDTと比較するとわかるように、Ptr構造は同一であり、エントリは非常に似ています。 したがって、エントリの配置(SetGate)とインストール(Install)の機能は非常に似ています。
void ND::IDT::SetGate(uint8_t num,uint32_t base,uint16_t sel, uint8_t flags)
{
idt[num].base_low=(base & 0xFFFF);
idt[num].base_high=(base >> 16) & 0xFFFF;
idt[num].sel=sel;
idt[num].always0=0;
idt[num].flags=flags;
}
インストール:
idtptr.limit=(sizeof(struct ND::IDT::Entry)*256)-1;
idtptr.base=(uint32_t)&idt;
ND::Memory::Set(&idt,0,sizeof(struct ND::IDT::Entry)*256);
ND::IDT::Flush();
見てみると、インストール関数は、他の投稿で宣言したND :: Memory :: Set関数を使用していることがわかります。 また、SetGateをまだ呼び出さず、ND :: IDT :: Flushを呼び出す方法も理解できます。この関数では、asmvolatileステートメントを再度使用します。
asm volatile("lidtl (idtptr)");
すべてがうまくいき、審美的な配置を行うと、次のようになります。
さて、IDTに割り込みを入力し始めます。 ここでは0つだけ作成しますが、残りは同じです。 ゼロ除算を行います。 数学でよく知られているように、数値を0で除算することはできません。これがプロセッサで発生すると、続行できないため、例外が生成されます。 IDTでは、リスト(XNUMX)の最初の割り込みがこのイベントに対応します。
IDTのインストール機能内のメモリ設定とフラッシュの間にこれを追加します。
ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);
コールバック関数はND :: ISR :: ISR1になります。これは、ASMを使用する必要がありますが、非常に単純です。
void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}
ND_ISR_Common C言語の関数として定義します。ファイルを保存して読みやすさを向上させるために、extern«C»{}を使用できます。
extern "C"
void ND_ISR_Common()
{
asm volatile(
"pusha \n"
"push %ds \n"
"push %es \n"
"push %fs \n"
"push %gs \n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_ISR_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}
ASMのこのコードは少し理解しにくいかもしれませんが、これは、割り込みによって生成されたデータにアクセスするためにCで構造体を宣言するためです。 明らかに、それが必要ない場合は、ND :: ISR :: ISR1などでカーネルパニックを呼び出すことができます。 構造は次のような形状をしています。
struct regs{
uint32_t ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss;
};
そして最後に、ND_ISR_Handler関数(これもCリンクを使用)を作成します。この関数では、カーネルパニックと、エラーのリストにあるものに応じたエラーの簡単な説明が表示されます。
extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}
これで、私たちはすでにこの中断に対処することができます。 残りの中断では、パラメーターを返すものがいくつかあり、reg構造体を使用してそれを取得することを除いて、同様に発生します。 ただし、それが実際に機能するかどうかをどのように知るのか疑問に思われるかもしれません。 それが機能するかどうかをテストするために、ND :: IDT :: Install()の後に簡単な行を導入します。
int sum=10/0;
コンパイルすると警告が表示され、実行しようとすると素敵な画面が表示されます。
これでこの投稿は終わりです。これは最も広範ですが、非常に機能的なもののXNUMXつだと思います。
LFSに切り替えましたが、より継続的です。
聖なる...とにかく、チュートリアルは良いです。
とても良いです、私は最初からそれをフォローしてきました。 各トレーラーにコードを添付していただけますか?
GitHubで利用可能なすべてのソースコードがあります。 http://github.com/AdrianArroyoCalle/next-divel そこから、ZIP、TAR.GZをダウンロードするか、gitを使用できます。
はははとても良いです! 承認してください! 🙂