模擬Linus Torvalds:從頭開始創建自己的操作系統(VI)

好了,稍加括號後,我們將繼續進行一系列教程。 如果返回上一代碼,則必須將ISR除以零。 現在,我們必須填寫發布了其消息的其餘ISR(前32個)。 好了,現在我們將繼續編程中斷,我們將執行IRQ(也稱為IRQ) 中斷請求。 這些IRQ由硬件設備(例如鍵盤,鼠標,打印機等)生成。 最初,前8個IRQ會自動映射到IDT的8至15位置。由於我們將前32個IRQ用於異常,所以現在我們必須重新映射它們。 我們將IRQ從32設置為45。為此,我們必須首先重新映射IRQ:

void ND::IRQ::Remap(int pic1, int pic2)
{
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
/* send ICW1 */
ND::Ports::OutputB(PIC1, ICW1);
ND::Ports::OutputB(PIC2, ICW1);
/* send ICW2 */
ND::Ports::OutputB(PIC1 + 1, pic1); /* remap */
ND::Ports::OutputB(PIC2 + 1, pic2); /* pics */
/* send ICW3 */
ND::Ports::OutputB(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
ND::Ports::OutputB(PIC2 + 1, 2);
/* send ICW4 */
ND::Ports::OutputB(PIC1 + 1, ICW4);
ND::Ports::OutputB(PIC2 + 1, ICW4);
/* disable all IRQs */
ND::Ports::OutputB(PIC1 + 1, 0xFF);
}

現在,我們創建一個函數來安裝IRQ:

void ND::IRQ::Install()
{
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BLACK);
ND::Screen::PutString("\nInstalling IRQ...");
ND::IRQ::Remap(0x20,0x28);
ND::IDT::SetGate(32,(unsigned)ND::IRQ::IRQ1,0x08,0x8E);
ND::IDT::SetGate(33,(unsigned)ND::IRQ::IRQ2,0x08,0x8E);
ND::IDT::SetGate(34,(unsigned)ND::IRQ::IRQ3,0x08,0x8E);
ND::IDT::SetGate(35,(unsigned)ND::IRQ::IRQ4,0x08,0x8E);
ND::IDT::SetGate(36,(unsigned)ND::IRQ::IRQ5,0x08,0x8E);
ND::IDT::SetGate(37,(unsigned)ND::IRQ::IRQ6,0x08,0x8E);
ND::IDT::SetGate(38,(unsigned)ND::IRQ::IRQ7,0x08,0x8E);
ND::IDT::SetGate(39,(unsigned)ND::IRQ::IRQ8,0x08,0x8E);
ND::IDT::SetGate(40,(unsigned)ND::IRQ::IRQ9,0x08,0x8E);
ND::IDT::SetGate(41,(unsigned)ND::IRQ::IRQ10,0x08,0x8E);
ND::IDT::SetGate(42,(unsigned)ND::IRQ::IRQ11,0x08,0x8E);
ND::IDT::SetGate(43,(unsigned)ND::IRQ::IRQ12,0x08,0x8E);
ND::IDT::SetGate(44,(unsigned)ND::IRQ::IRQ13,0x08,0x8E);
ND::IDT::SetGate(45,(unsigned)ND::IRQ::IRQ14,0x08,0x8E);
ND::IDT::SetGate(46,(unsigned)ND::IRQ::IRQ15,0x08,0x8E);
ND::IDT::SetGate(47,(unsigned)ND::IRQ::IRQ16,0x08,0x8E);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("done");
asm volatile("sti");
}

asm的句子 STI 我們激活IRQ。 好吧,現在我們去做類似ISR的事情。 基本IRQ的功能:

void ND::IRQ::IRQ1()
{
asm volatile(
"cli \n"
"pushl 0\n"
"pushl 32\n"
"jmp ND_IRQ_Common"
);
}

通用部分(與ISR相同):

extern "C"
void ND_IRQ_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_IRQ_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"
);
}

和一個基本的處理程序:

extern "C"
void ND_IRQ_Handler(struct regs* r)
{
void (*handler)(struct regs *r);
if(r->int_no >= 40)
{
ND::Ports::OutputB(0xA0,0x20);
}
ND::Ports::OutputB(0x20,0x20);
}

這樣,即使他們仍然不執行任何操作,我們也應該已經激活了IRQ。 在下一章中,我們將看到如何從這些IRQ(例如時鐘或鍵盤)中獲取數據。

NextDivel-IRQ


至此,今天的帖子結束了。 如您現在所見,由於其他問題,我的寫作時間有所減少。 即使如此,我將繼續直到擁有更完整的操作系統


發表您的評論

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

*

*

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

  1.   aitor_cz 他說:

    非常感謝Adrian,我一有時間(現在我很忙,尤其是在使用操作系統時),我將開始逐步測試本教程。

  2.   紅寶石 他說:

    非常感謝您的發言。

  3.   佐助 他說:

    我正在做一個基於這些編程語言的項目的問題
    * HTML5
    * CSS3
    * Java
    我的問題是我希望該項目可執行,因此用戶可以在Linux和Windows等操作系統中使用它,能否告訴我我該怎麼做?

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

      與此無關,但我還是要回答你。 我認為它將是HTML5,CSS3和JavaScript而不是Java,因為HTML5和Java會致命。 使用HTML5,您可以像以前一樣創建網站,然後可以從Internet訪問這些網站。 如果要使其本地化,可以將其打包為Firefox OS和Chrome OS應用程序。 如果您想要的是每個操作系統中都有一個可執行文件,請看一下XUL Runner,它是使用Gecko引擎執行XUL(因此在元素內的HTML5)的工具。

    2.    索德·佩雷斯 他說:

      Java框架或面板是一個很好的選擇,我已經使用Java框架類作為Web瀏覽器在窗口中創建了一些可執行應用程序,但是沒有在任何頁面中使用它,而是在代碼中使用了直接路徑,並使用php執行了Java語句通過一個負責鋼鐵的.jar。 儘管我建議使用HTML5,CSS3和JavaScript,因為Adrian Java表示Html5需要致命的功能,這讓我很頭疼

  4.   魯班 他說:

    關於如何製作自己的編程語言的教程會很不錯

  5.   伊万 他說:

    很好的這一系列文章介紹瞭如何構建操作系統,您學到了很多東西。 我期待下一個輸入,我已經想要在操作系統中使用鍵盤。 我一直在搞亂git代碼,但無法使其與端口0x60和0x64一起使用。 即使我認為對於鍵盤來說,還是有一個中斷讓您按下了鍵。

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

      您實際上可以無中斷地獲得鍵盤輸入,但是必須在端口0x60上使用ND :: Ports :: InputB進行閱讀。 但是,執行此操作的理想方法是使用IRQ中斷。 我目前正在嘗試這樣做,因此需要花費更長的時間才能繼續。

      1.    Carlosorta 他說:

        嗨,阿德里安(Adrian),我一直在檢查代碼,它的功能以及它如何幫助我理解一些東西,給我留下了深刻的印象。

        我對它的工作方式有幾個小問題,來源是我從您的GIT那裡得到的:

        1.-在IRQ的一部分中,您提到IDT從0到32的位置被用作異常,IRQ從32(0x20)到45(0x2D)的位置被使用,但是IRQ總共為16,重映射是不是從0x20到0x30?

        2.-在IRQ部分中,請注意將設置門發送到IDT部分; 當您將它們分開時,請注意,它不再產生除以0的異常,因此有必要為所做的每個修改添加IDT Flush()。 為什麼設置定時器時IDT會發生變化,並且0之間的分頻停止工作?

        3.-我試圖通過一些打印來跟踪代碼,以指示代碼正在執行(以免逐步調試),但我意識到沒有IRQ在運行,我是否必須註冊其他內容生成IRQ中斷?

        1.    Carlosorta 他說:

          我忘了提到我找到了以下帶有信息的鏈接:
          http://arstechnica.com/civis/viewtopic.php?f=20&t=899001
          http://www.superfrink.net/athenaeum/OS-FAQ/os-faq-pics.html
          http://orga2.exp.dc.uba.ar/data/downloads/clasespracticas/interrupciones2_clase_17.pdf
          http://www.intel-assembler.it/PORTALE/4/231468_8259A_PIC.pdf

          顯然,對於處理IRQ,有必要考慮PIC,APIC,IOAPIC使用哪種類型的處理程序。 。 。等等。 有沒有一種方法可以動態管理IRQ,還是需要試試運氣?

  6.   Carlosorta 他說:

    下午好,阿德里安。

    我看到我的IRQ出現了問題,這就是為什麼無法進行代碼改進的原因,我製作了一個項目的副本並開始對其進行分析。 在進行中斷時,我在絲網印刷中添加了一個功能以打印struct reg的reg記錄; 我發現了幾件事,其中有一個註冊表正在運行,但我仍然找不到原因。 更改計時器中斷以測試鍵盤中斷並執行應做的事情,但我找不到問題,您能幫我繼續此好帖子嗎? 😀

    我離開了鏈接(由於我使用Mageia和Grub2,所以我進行了一些修改,我正在使用VirtualBox進行測試)
    https://www.mediafire.com/?93psrgaoozatse8

    等待您的細心回應,如果您有任何疑問或需要幫助,我想幫忙🙂

    1.    Carlosorta 他說:

      我忘了提一下,我還檢查了KernelPanic,因為ISR無法正常工作,並且在堆棧頂部存在相同的問題,正在過濾一個值,並且我不知道它是我的編譯器還是存在問題,我在Mageia 4.8.2中使用GCC 4

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

      我真的很喜歡您在該項目中對我的幫助。 我真的被計時器困住了,我不明白為什麼它不起作用。 我做了測試,修改了很多東西,但是沒有成功。 目前,我無法編輯代碼(我正在度假),但我會盡快對其進行仔細的研究。 我給您一個鏈接,其中包含有關此問題的信息,這似乎很常見: http://wiki.osdev.org/I_Cant_Get_Interrupts_Working

      關於例外,我想我記得您必須調用ASM中的“ sti”來激活它們,儘管很明顯某個地方有問題。

      1.    Carlosorta 他說:

        感謝您的回答,是的,的確如此。 中斷失敗,但是在堆棧中插入代碼是一個問題,並且是轉換問題,我將檢查鏈接並進行測試。 如果我解決了問題,我會通知您,否則,我會通知您進度。 節日快樂🙂

      2.    Carlosorta 他說:

        沒有辦法看到彙編代碼嗎?發生了什麼奇怪的事我找不到嗎?看一下這個屏幕(我把鏈接放在最後),這很奇怪,因為在IRQ 2功能(鍵盤)中),它會向堆棧輸入值0和0x20(32,因此適合測試),然後先推入(32位GPR寄存器),再依次輸入分段寄存器和棧頂,然後調用IRQ處理程序。 我開始看到每個堆棧,而且顯然是按順序排列的,但是如果您可以看到VM的輸出,則可以看到它又堆棧了一個元素,我找不到位置,我只知道它是一個0x10且結構變得混亂。 這是記錄結構。

        struct regs {
        uint32_t gs,fs,es,ds; / *持續秒數* /
        uint32_t edi,esi,ebp,esp,ebx,edx,ecx,eax; / *由“ pushal”推動* /
        uint32_t int_no,err_code; /* 錯誤代碼 */
        uint32_t eip,cs,eflags,useresp,ss; / *休息時堆疊* /
        };

        令我煩惱的是,它在頂部放置了一個元素,而且如果顯然所有內容都按原樣堆疊,我就找不到該元素的堆疊位置。 你有什麼想法嗎?

        http://www.subeimagenes.com/img/sin-titulo-1036729.jpg

  7.   Carlosorta 他說:

    使鍵盤中斷工作,但不使定時器中斷工作; 錯誤在於它的編譯方式,我使用objdump查看最終對象,結果發現,即使使用“ asm volatile”輸入的每個函數也都帶有pushl ebp,mov ebp,esp。 然後只需向其添加popl ebp以恢復初始堆棧,它將毫無疑問地傳遞參數。 在這裡,我為那些想要檢查它的人附加了代碼,如果您能找出為什麼計時器未生成中斷的原因,我很想知道,並在他們談論多任務的地方附加了一個鏈接。 http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
    下一個Divel
    https://www.mediafire.com/?kmo83dxyzc7c3cz

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

      我知道了。 這是另一個錯誤,它影響了Timer PIC的激活,特別是在IRQ重映射中,我必須修改兩行。 多虧了我可以在網站上看到一個與當時有所不同的代碼,然後單擊! 更改遵循以下原則:
      ND ::端口:: OutputB(PIC1 + 1,0xFF);
      ND ::端口:: OutputB(PIC2 + 1,0xFF);

      儘管我不確定,但您必須將值從0xFF(我說它表示已禁用)更改為0x00(我說它表示已啟用),但是它可以工作。 我已經在GitHub上更新了代碼。 非常感謝您為我的項目提供了幫助,由於這個問題,我對此有些遺棄。 H

      1.    Carlosorta 他說:

        不客氣,我期待該主題的下一個更新,您可以依靠我me(Y)

      2.    Carlosorta 他說:

        更改鍵盤字符串捕獲例程; 因為它在釋放鍵時正在讀取,並且在緩衝區中安裝了0,這在讀取時產生了問題,最後'\ n'將其更改為»,從而可以進行正確的打印

  8.   索德·佩雷斯 他說:

    您好,我閱讀了您的整篇文章,儘管實際上它不超過2篇文章,它確實非常好,可以保存所有內容,但是我真的需要學習c ++和posix來理解它,因為我了解“ c” (我著迷於該編程語言)但是,儘管c ++是c OO,但我從未真正從事過它,但請向我閱讀google的一些教程,然後返回這個非常有趣的問題:窗口啟動是否類似於Linux?

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

      從某種意義上說,Windows引導是類似的,因為這是使用x86處理器引導系統的方式,而基於xXNUMX處理器構建的操作系統的影響很小。 無論如何,我們並不是真正地自我引導,而是為我們啟動了GRUB。 設計用於引導Linux的GRUB可以引導Windows,在這種情況下也可以引導NextDivel。

      1.    大豆 他說:

        好的,謝謝,這意味著我想做的是可能的,我已經在研究c ++,並且我已經創建了一些應用程序並將您的系統安裝在pendrive上,並且我正在更詳細地研究它,這是一篇非常好的文章