模擬Linus Torvalds:從0(V)創建您自己的操作系統

在第五部分中,我們將看到一個在理論上和使用上都與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的結構是相同的,而Entry則是非常相似的。 因此,放置條目(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();

如果我們看一下,將會看到install函數使用了我們在另一篇文章中聲明的ND :: Memory :: Set函數。 我們還可以看到如何尚未對SetGate進行任何調用,而我們調用ND :: IDT :: Flush,對於此函數,我們再次使用了asm volatile語句:

asm volatile("lidtl (idtptr)");

如果一切順利,我們進行了美學安排,則應如下所示:

NextDivel-RTD

好的,現在我們開始用中斷填充IDT。 在這裡,我將只創建一個,其餘的將是相同的。 我要除以零休息。 如您在數學中所知,數字不能除以0。如果在處理器中發生這種情況,則會生成一個異常,因為它無法繼續。 在IDT中,列表(0)中的第一個中斷對應於此事件。

我們將其添加到IDT的Install函數中的內存設置和刷新之間:

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;

如果我們編譯它會給我們一個警告,如果我們嘗試執行它會得到一個漂亮的屏幕:

NextDivel-ISR


到此為止,我認為這是最廣泛但功能齊全的文章之一。


發表您的評論

您的電子郵件地址將不會被發表。 必填字段標有 *

*

*

  1. 負責數據:MiguelÁngelGatón
  2. 數據用途:控制垃圾郵件,註釋管理。
  3. 合法性:您的同意
  4. 數據通訊:除非有法律義務,否則不會將數據傳達給第三方。
  5. 數據存儲:Occentus Networks(EU)託管的數據庫
  6. 權利:您可以隨時限制,恢復和刪除您的信息。

  1.   中型 他說:

    我去了LFS,它比較連續。

  2.   埃利奧時間3000 他說:

    神聖的...無論如何,這些教程都是不錯的。

  3.   sc 他說:

    很好,我從一開始就關注它。 您可以將代碼附加到每個預告片上嗎?

    1.    阿德里安·阿羅約街 他說:

      您擁有GitHub上所有可用的源代碼: http://github.com/AdrianArroyoCalle/next-divel 您可以從那裡下載ZIP,TAR.GZ或僅使用git。

  4.   細微的 他說:

    哈哈哈很好! 批准! 🙂