Linus Torvaldsのエミュレート:独自のオペレーティングシステムを最初から作成する(VI)

さて、少し括弧を付けた後、一連のチュートリアルを続けます。 前のコードに戻る場合は、ゼロ除算のISRが必要です。 ここで、メッセージを投稿した残りのISR(最初の32)に入力する必要があります。 さて今、私たちはプログラミングの中断を続けるつもりです、私たちは別名として知られているIRQをするつもりです 要求を中断します。 これらのIRQは、キーボード、マウス、プリンターなどのハードウェアデバイスによって生成されます。 最初に、最初の8つのIRQがIDTの位置8〜15に自動的にマップされます。例外に最初の32を使用したので、それらを再マップする必要があります。 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の文 スティ 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からデータを取得する方法を説明します。

NextDive-IRQ


そして、これで今日の投稿は終わりです。 あなたが今見ることができるように、私は他の問題のためにあまり定期的に書きません。 それでも、より完全なオペレーティングシステムができるまで続けます


コメントを残す

あなたのメールアドレスが公開されることはありません。 必須フィールドには付いています *

*

*

  1. データの責任者:MiguelÁngelGatón
  2. データの目的:SPAMの制御、コメント管理。
  3. 正当化:あなたの同意
  4. データの伝達:法的義務がある場合を除き、データが第三者に伝達されることはありません。
  5. データストレージ:Occentus Networks(EU)がホストするデータベース
  6. 権利:いつでも情報を制限、回復、削除できます。

  1.   aitor_cz

    エイドリアン、ありがとうございました。時間があり次第(今はオペレーティングシステムでも忙しいです)、チュートリアルのテストを段階的に開始します。

  2.   ルビー

    どうもありがとうございました。

  3.   サスケ

    これらのプログラミング言語に基づいたプロジェクトを行っているXNUMXつの質問
    * Html5
    * Css3
    * Java
    私の質問は、ユーザーがLinuxやWindowsなどのオペレーティングシステムで使用できるように、このプロジェクトを実行可能にしたいということです。その方法を教えてください。

    1.    AdrianArroyoStreet

      これとは何の関係もありませんが、とにかくお答えします。 HTML5とJavaは致命的にうまくいくので、JavaではなくHTML3、CSS5、JavaScriptになると思います。 HTML5を使用すると、インターネットからアクセスする以前と同じようにWebサイトを作成できます。 ローカルにしたい場合は、FirefoxOSおよびChromeOSアプリとしてパッケージ化できます。 必要な場合は、各オペレーティングシステムに、GeckoエンジンでXUL(したがって要素内のHTML5)を実行するツールであるXULRunnerを調べた実行可能ファイルがあります。

    2.    ソイドペレス

      Javaフレームまたはパネルは非常に優れたオプションです。JavaフレームクラスをWebブラウザーとして使用してウィンドウ内に実行可能アプリをいくつか作成しましたが、ページに使用する代わりに、コードで直接パスを指定し、phpを使用してJava文を実行します。鋼の世話をする.jarを介して。 Adrian Javaが言うように、HTML5、CSS3、JavaScriptの使用をお勧めしますが、Html5では致命的であり、多くの頭痛の種をもたらしました。

  4.   都市

    独自のプログラミング言語を作成する方法に関するチュートリアルがあればいいでしょう

  5.   イワン

    オペレーティングシステムの構築方法に関するこのシリーズの記事は非常に優れており、多くのことを学びます。 次のエントリを楽しみにしています。すでにOSにキーボードが必要です。 私はgitコードをいじっていますが、ポート0x60と0x64で動作させることができませんでした。 キーボードの場合、キーを押すと中断が発生したと思いましたが。

    1.    AdrianArroyoStreet

      実際には、中断することなくキーボード入力を取得できますが、ポート0x60でND ::ポート:: InputBを使用して読み取る必要があります。 ただし、これを行う理想的な方法は、IRQ割り込みを使用することです。 私は現在それをやろうとしていますが、そのために続行するのに少し時間がかかります。

      1.    カルロソータ

        こんにちはエイドリアン、私はコードをチェックしていて、それが何をするのか、そしてそれが私がいくつかのことを理解するのにどれほどうまく役立ったかに感銘を受けました。

        それがどのように機能するかについていくつかの小さな質問があり、ソースは私があなたのGITから得たものです:

        1.- IRQの部分で、0から32までのIDT位置が例外に使用され、IRQに32(0x20)から45(0x2D)が使用されたと述べましたが、IRQは合計16であり、再マッピングは0x20からではありません。 0x30に?

        2.- IRQの部分で、セットゲートをIDTセクションに送信したことに注意してください。 それらを分離するとき、0による除算の例外が生成されなくなったことに注意してください。したがって、行われる変更ごとにIDTフラッシュ()を追加する必要があります。 タイマーを設定するとIDTが変更され、0の間の除算が機能しなくなるのはなぜですか?

        3.-実行中のコードを示すために(段階的にデバッグしないように)印刷してコードをトレースしようとしましたが、IRQが実行されていないことに気付きましたが、他に何かを登録する必要がありますか?生成されたIRQ割り込みに?

        1.    カルロソータ

          私はこれらのリンクを情報とともに見つけたことに言及するのを忘れました:
          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.   カルロソータ

    こんにちはエイドリアン。

    IRQに問題があることがわかったため、コードを進めることができませんでした。プロジェクトのコピーを取り、分析を開始しました。 中断を行った瞬間に、structregのregレコードを印刷する機能をスクリーン印刷に追加しました。 レジストリが実行されていることをいくつか見つけましたが、それでも理由がわかりません。 キーボード割り込みのタイマー割り込みを変更して、テストして実行する必要がありますが、問題が見つかりません。助けて、この良い投稿を続けていただけますか? 😀

    リンクを残します(MageiaとGrub2を使用し、VirtualBoxを使用してテストしているため、いくつかの変更があります)
    https://www.mediafire.com/?93psrgaoozatse8

    あなたの注意深い応答を待っています、そしてあなたが質問があるか何かが必要な場合は私が助けたいです🙂

    1.    カルロソータ

      ISRが機能せず、スタックの最上位で同じ問題が発生し、値がリークしていて、それが自分のコンパイラなのか問題があるのか​​わからないため、KernelPanicもチェックしたことを忘れました。 GCC 4.8.2 with Mageia 4

    2.    AdrianArroyoStreet

      私はあなたがプロジェクトで私を助けてくれるのが本当に好きです。 私は本当にタイマーで立ち往生していて、なぜそれが機能しないのか理解できません。 私はかなりの数のことを修正するテストをしました、そしてそれはうまくいきませんでした。 現在、コードを編集することはできません(休暇中です)が、できるだけ早くコードをよく見ていきます。 よくあることのように思われるこの問題に関する情報へのリンクを提供します。 http://wiki.osdev.org/I_Cant_Get_Interrupts_Working

      例外については、どこかに問題があることは明らかですが、ASMで「sti」を呼び出してアクティブ化する必要があることを覚えていると思います。

      1.    カルロソータ

        あなたの答えをありがとう、そして確かにそうです。 割り込みは失敗していましたが、スタックへのコードの挿入の問題とキャストの問題でした。リンクを確認してテストを行います。 私がそれを解決するならば、私はあなたに知らせます、そして、そうでなければ、私はあなたに進歩を知らせます。 ハッピーホリデー🙂

      2.    カルロソータ

        アセンブルされたコードを見る方法がありませんか?何か奇妙なことが起こり、何が見つからないのですか?この画面を見てください(最後にリンクを置きます)、IRQ 2機能(キーボード)にあるので奇妙なことです)スタックに値0と0x20(32なので、テストに適合)を入力し、次にpushal(32ビットGPRレジスタ)、セグメンテーションレジスタ、スタックの最上位を入力して、IRQハンドラを呼び出します。 私は各スタックを確認し始めましたが、どうやらそれは正常ですが、VMの出力を見ると、もう0つの要素がスタックしていることがわかります。場所がわかりません。これは、10xXNUMXであり、構造であることがわかります。故障します。 これがレコード構造です。

        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; / *休憩時間にスタック* /
        };

        一番上にもうXNUMXつの要素が配置されているのが気になります。どうやらすべてが適切にスタックされていると、どこにスタックされているのかわかりません。 あなたはそれが何であるかについて何か考えがありますか?

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

  7.   カルロソータ

    キーボード割り込みを機能させますが、タイマー割り込みは機能させません。 エラーはコンパイル方法にあり、objdumpを使用して最終オブジェクトを確認しました。「asmvolatile」を使用しても入力されたすべての関数には、pushl ebp、mov ebp、espも付随していることがわかりました。 次に、popl ebpを追加して初期スタックを復元すると、必ず引数が渡されます。 ここにチェックしたい人のためにコードを添付します。タイマーによって割り込みが生成されない理由がわかれば、それを知りたいので、マルチタスクについて話しているリンクを添付します。 http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
    次のDivel
    https://www.mediafire.com/?kmo83dxyzc7c3cz

    1.    AdrianArroyoStreet

      わかった。 これは、Timer PICのアクティブ化に影響を与えた別のサイトのバグでした。具体的には、IRQリマップで、変更する必要のあるXNUMX行がありました。 その時点で何か違うものを持っていたコードをウェブサイトで見ることができたという事実のおかげで、クリックしてください! 変更は次のようなものでした。
      ND ::ポート:: OutputB(PIC1 + 1、0xFF);
      ND ::ポート:: OutputB(PIC2 + 1、0xFF);

      よくわかりませんが、値を0xFF(無効を示していると思います)から0x00(有効を示していると思います)に変更する必要がありましたが、機能します。 GitHubのコードを更新しました。 この問題で少し見捨てられたプロジェクトを手伝ってくれて本当にありがとう。 H

      1.    カルロソータ

        どういたしまして、トピックの次の更新を楽しみにしています、そしてあなたは何でも私を頼りにすることができます🙂(Y)

      2.    カルロソータ

        キーボードの文字列キャプチャルーチンを変更します。 キーが離されたときに読み取りを行っており、バッファに0をマウントしているため、読み取りに問題が発生し、最後に「\ n」を»に変更して正しい印刷が機能するようにします。

  8.   ソイドペレス

    こんにちは、私はあなたの投稿全体を読みました、実際には2つ以下の投稿ですが、それは本当にとても良いです、すべてを保存します、しかし私は「c」について知っているのでそれを理解するためにc ++とposixを本当に勉強する必要があります(私はそのプログラミング言語に魅了されています)しかし、c ++はcOOですが、実際に取り組んだことはありません。グーグルでいくつかのチュートリアルを読んでから、これを非常に興味深い質問に戻します。ウィンドウの起動はLinuxに似ていますか?

    1.    AdrianArroyoStreet

      Windowsでの起動は、これがx86プロセッサを搭載したシステムを起動する方法であり、その上に構築されたオペレーティングシステムがほとんど影響を与えないという意味で似ています。 とにかく、私たちは実際に自分自身を起動しているわけではありません。それは私たちのためにGRUBを開始しています。 Linuxを起動するように設計されたGRUBは、Windows、この場合はNextDivelを起動できます。

      1.   

        わかりました、つまり、私がやりたいことが可能であることを意味します。私はすでにc ++を勉強していて、いくつかのアプリを作成してシステムをペンドライブにインストールしました。詳細に勉強しています。非常に良い投稿です。