0

フラットメモリモードでHW割り込みを置き換える方法について質問があります...

  1. 私のアプリケーションについて...
    • WatcomCDOS32/Aを組み合わせて作成されました。
    • DOSモードで実行するために作成されました(OSモードではありません)
    • DOS32 / Aを使用すると、100万を超えるメモリにアクセスし、使用する大容量メモリを割り当てることができます...(フラットメモリモードで実行中!!!)
  2. 現在の問題...
    • 1枚のPCIカードにISR(割り込みサービスルーチン)を書きたい。したがって、HW割り込みを「置き換える」必要があります。
    • 元。PCIカードの割り込みライン=0DOSでは0xE。これは、このデバイスが8259のIRQ14を介して割り込みを発行することを意味します。

しかし、フラットモードでこの割り込みを置き換えるという目標を達成する方法はありませんでしたか?

@リソースを見つけました...-watcomCのライブラリには、_dos_getvect、_dos_setvect、および_chain_intrを使用してINT0x1Cをフックするサンプルが1つあります...このコードをテストしてOKでした。しかし、それを私の場合に適用すると、INT76(IRQ14は"INT 0x76" <-(14-8)+ 0x70)で、何も起こりませんでした。

  • HW割り込みが生成されていることを確認しましたが、自分のISRが呼び出されませんでした...

私は何かを失いますか?または、目標を達成するために使用できる機能はありますか?

================================================== =============

[20120809] DPMI呼び出し0x204および0x205 を使用しようとしましたが、 MyISR()がまだ呼び出されていないことがわかりました。私がしたことを以下に説明しました。多分あなた方全員が私にいくつかの提案をすることができます!

1)インラインアセンブリを使用してDPMI呼び出し0x204および0x205を実装し、OKをテストします...

元。DPMI 0x204を使用して16個のIRQの割り込みベクトルを表示すると、次の結果が得られます( selector:offset ): 8:1540(INT8)、8:1544(INT9)、.....、8:1560(INT70)、8 :1564(INT71)、...、8:157C(INT77)

元。DPMI 0x205を使用してIRQ14 (INT76)の割り込みベクトルを設定し、CF = 0を返し、成功したことを示します

2)次のように独自のISR MyISR()を作成します。

volatile int tick=0;  // global and volatile...
void MyISR(void)
{
  tick = 5;  // simple code to change the value of tick...
}

3) DPMI呼び出し0x205によって新しい割り込みベクトルを設定します。

selector = FP_SEG(MyISR);  // selector = 0x838 here
offset = FP_OFF(MyISR);    // offset   = 0x30100963 here
sts = DPMI_SetIntVector(0x76, selector, offset, &out_ax);

次に、sts = 0(CF = 0)は成功したことを示します!

  • ここで奇妙なことの1つは、私のアプリはフラットメモリモデルで実行され、MyISR()のセレクターは0である必要があると思います...しかし、DPMI呼び出し0x205のセレクター= 0の場合、CF=1およびAX=0x8022を取得し、「無効なセレクター」!

4) HW割り込みを生成し、証拠は次のとおりです。

  • PCIデバイス構成レジスタ0x5ビット2(割り込み無効)= 0
  • PCIデバイス構成レジスタ0x6ビット3(割り込みステータス)= 1
  • PCIデバイス構成レジスタ0x3C/0x3D(割り込みライン)= 0xE / 0x2
  • DOSでは、割り込みモードはPICモード(8259モード)およびピンベース(MSIE = 0)です。

5)ティックの値を表示し、それがまだ「0」であることを確認しました...

したがって、MyISR()が正しく呼び出されていないと思います...

4

2 に答える 2

0

割り込みをいじってからしばらく経ちましたが、テーブルは、プロセッサが割り込みを処理するためにどこに行くべきかを設定するためのポインタです。私は8086コードしか使用していなかったので、プロセスを提供することはできますが、コードを提供することはできません。

擬似コード:

Initialize:
    Get current vector - store value
    Set vector to point to the entry point of your routine

次:

Process Interrupt:
    Your code decides what to do with data
    If it's your data:
        process it, and return
    If not:
        jump to the stored vector that we got during initialize, 
        and let the chain of interrupts continue as they normally would

ついに:

Program End:
    check to see if interrupt still points to your code
        if yes, set vector back to the saved value
        if no, set beginning of your code to long jump to vector address you saved, 
            or set a flag that lets your program not process anything
于 2012-07-24T21:36:14.793 に答える
0

'_dos_getvect'および'_dos_setvect'の代わりに、それぞれDPMI関数0204hおよび0205hを使用してみてください。

プログラムのランタイム環境は、DOS32AまたはDPMIサーバー/ホストです。したがって、DOS int21h機能を使用する代わりに、提供されたAPIを使用してください。ただし、DOS32Aはint21h割り込みをインターセプトするため、リアルモードに関する限り、コードは正常に機能するはずです。

実際に行ったことは、「_dos_getvect」および「_dos_setvect」関数を使用して、IRQ14のリアルモード割り込みハンドラーのみをインストールすることです。

代わりにDPMI関数を使用することにより、 IRQ14のプロテクトモード割り込みハンドラーをインストールすると、DOS32aはIRQ14割り込みをこのプロテクトモードハンドラーに自動パスアップします。

思い出してください:IRQがアサートされている間、DOSエクステンダ/DPMIサーバーはプロテクトモードまたはリアルモードにすることができます。

これは、アプリケーションがDOSまたはBIOS APIを使用しているため、エクステンダーはそれらを実行するためにリアルモードに切り替え、プロテクトモードアプリケーションに制御を移すためにプロテクトモードに戻る必要があります。

DOS32aは、エクステンダーがリアルモードのときにIRQ14がアサートされた場合に、プロテクトモードハンドラーを呼び出すリアルモードコールバック(少なくともハードウェア割り込みの場合)を割り当てることによってこれを行います。

エクステンダーがプロテクトモードの場合、IRQ14がアサートされている間、エクステンダーは自動的に制御をIRQ14ハンドラーに転送します。

ただし、IRQにプロテクトモードハンドラーをインストールしなかった場合、DOS32aはリアルモードコールバックを割り当てず、リアルモードirqハンドラーが制御を取得しない可能性があります。しかし、それはコントロールAFAIKを受け取るはずです。

とにかく、上記の2つの関数を試してみてください。そして、ショーンが言ったように、前のint76h割り込みハンドラーにチェーンします。

要するに:

DOS32aの場合、「_dos_getvect」および「_dos_setvect」関数を使用する必要はありません。代わりに、プロテクトモードIRQハンドラーをインストールするためにDPMI関数0204hおよび0205hを使用してください。

アドバイス:割り込みハンドラーの最初のステップは、デバイスが実際に割り込みを生成したかどうか、またはこのirq(この場合はIRQ14)を共有している他のデバイスであるかどうかを確認することです。これを行うには、デバイスの「割り込み保留ビット」をチェックします。設定されている場合は、デバイスにサービスを提供し、次のハンドラーにチェーンします。1に設定されていない場合は、次のハンドラーにチェーンするだけです。

編集済み: OWに付属しているものではなく、最新バージョンのDOS32aを 使用してください。

2012年8月14日の更新:

はい、FP_SEGマクロとFP_OFFマクロを使用して、セレクターとオフセットをそれぞれ取得できます。これは、実際のモードでこれらのマクロを使用してセグメントとオフセットを取得する場合と同じです。

MK_FPマクロを使用して、セレクターとオフセットから遠いポインターを作成することもできます。例えば。MK_FP(セレクター、オフセット)。

Cでハンドラーを作成するときは、「__interrupt」キーワードを使用して割り込みハンドラーを宣言する必要があります。

スニペットは次のとおりです。

             #include <i86.h>  /* for FP_OFF, FP_SEG, and MK_FP in OW */

             /* C  Prototype for your IRQ handler */
             void   __interrupt    __far irqHandler(void);
                        .
                        . 
                        .
          irq_selector = (unsigned short)FP_SEG( &irqHandler );
          irq_offset = (unsigned long)FP_OFF( &irqHandler );

          __dpmi_SetVect( intNum, irq_selector, irq_offset );
                        .
                        . 
                        .

または、これを試してください:

          extern void sendEOItoMaster(void);  
          # pragma aux sendEOItoMaster = \                         
                "mov  al,    0x20"  \       
                "out  0x20,  al"    \       
                modify [eax] ;



          extern void sendEOItoSlave(void);  
          # pragma aux sendEOItoSlave = \                           
              "mov  al,    0x20"  \       
              "out  0xA0,  al"    \       
              modify [eax] ;


      unsigned int   old76_selector, new76_selector;
      unsigned long  old76_offset, new76_offset;


      volatile int chain = 1; /* Chain to the old handler */
      volatile int tick=0;  // global and volatile...


     void (__interrupt __far *old76Handler)(void) = NULL;      // function pointer declaration

     void __interrupt __far new76Handler(void) {


            tick = 5;  // simple code to change the value of tick...

               .
               .
               .

           if( chain ){

                 // disable irqs if enabled above.

                 _chain_intr( old76Handler );  // 'jumping' to the old handler

                //  ( *old76Handler )();          // 'calling' the old handler 

           }else{

               sendEOItoMaster();
               sendEOItoSlave();
           }

      }


      __dpmi_GetVect( 0x76, &old76_selector, &old76_offset );

      old76Handler = ( void (__interrupt __far *)(void) ) MK_FP (old76_selector, old76_offset)

      new76_selector = (unsigned int)FP_SEG( &new76Handler );
      new76_offset = (unsigned long)FP_OFF( &new76Handler );

      __dpmi_SetVect( 0x76, new76_selector, new76_offset );

                    .
                    .

ノート:

最初に、フックしているIRQ#が実際に関連するPCIデバイスの割り込みピンに割り当てられている/マップされていることを再確認する必要があります。IOWは、最初にPCI構成スペースから「割り込みラインレジスタ」(割り込みピンレジスタではない)を読み取り、そのirq#のみをフックします。このレジスタの有効な値は、次のとおりです。0x00から0x0Fまで、0x00はIRQ0を意味し、0x01はIRQ1を意味します。

POST / BIOSコードは、起動中に「割り込みラインレジスタ」に値を書き込みます。このレジスタを変更してはなりません(もちろん、OSライターが処理する割り込みルーティングの問題を処理している場合を除きます)。

また、古いハンドラーにチェーンしている場合は、DPMI呼び出し0204hを使用して、古いハンドラーのセレクターとオフセットを取得して保存する必要があります。そうでない場合は、スレーブPICに属するIRQ(つまり、INT0Ahを含むINT70hから77h)をフックした場合に備えて、マスターPICとスレーブPICの両方にEOI(割り込み終了)を送信することを忘れないでください。マスターPICに属するIRQをフックした場合。

フラットモデルでは、BASEアドレスは0、制限は0xFFFFFで、Gビット(つまり粒度ビット)=1です。

ベースとリミット(セグメントの属性ビット(Gビットなど)とともに)は、特定のセグメントに対応する記述子に存在します。記述子自体は、記述子テーブルにあります。

記述子テーブルは、各エントリが8バイトの配列です。

セレクターは、記述子テーブル(GDTまたはLDT)の8バイト記述子エントリーへのポインター(またはインデックス)にすぎません。したがって、セレクターを0にすることはできません。

16ビットセレクタの下位3ビットには特別な意味があり、記述子テーブルの記述子エントリにインデックスを付けるために使用されるのは上位13ビットのみであることに注意してください。

GDT=グローバル記述子テーブル

LDT=ローカル記述子テーブル

システムは1つのGDTのみを持つことができますが、多くのLDTを持つことができます。

GDTのエントリ番号0として、予約されており、使用できません。AFAIK、DOS32Aは、アプリケーション用のLDTを作成しません。代わりに、GDT自体で、アプリケーションに対応する記述子エントリを割り当てて初期化します。

x86アーキテクチャでは、セレクタを使用してメモリにアクセスしようとすると、0セレクタは無効と見なされるため、セレクタは0であってはなりません。任意のセグメントレジスタに0を正常に配置できますが、そのセグメントにアクセス(読み取り/書き込み/実行)しようとした場合にのみ、CPUが例外を生成します。

割り込みハンドラの場合、フラットモードの場合でもベースアドレスは0である必要はありません。DPMI環境には、これを行う正当な理由が必要です。結局のところ、x86アーキテクチャのあるレベルでセグメンテーションに取り組む必要があります。

                  PCI device config register 0x5 bit2(Interrupt Disabled) = 0

                  PCI device config register 0x6 bit3(Interrupt status) = 1  

バスマスタコマンドとステータスレジスタをそれぞれ意味していると思います。これらは実際にはI/Oスペースまたはメモリスペースのいずれかに存在しますが、PCI構成スペースには存在しません。したがって、IN / OUTまたはMOV命令を介して、それらを直接読み取り/書き込みできます。

読み取り/書き込みのPCI構成レジスタには、構成の赤/書き込みメソッドまたはPCIBIOSルーチンを使用する必要があります。

ノート:

多くのPCIディスクコントローラには、「割り込みイネーブル/ディセーブル」ビットと呼ばれるビットがあります。このビットを含むレジスタは通常PCI構成スペースにあり、データシートから見つけることができます。

実際、この設定は、PCIコントローラーに接続されたデバイスによって生成された割り込みをPCIバスに「転送」するためのものです。

このビットを介して割り込みが無効になっている場合、デバイス(PCIコントローラーに接続されている)が割り込みを生成している場合でも、割り込みはPCIバスに転送されません(したがって、cpuは割り込みが発生したかどうかを知ることはありません)。 PCIコントローラのビット(このビットは「割り込みの有効化/無効化」ビットとは異なります)は、デバイス(PCIコントローラに接続されている、たとえばハードディスク)が割り込みを生成したことを通知するように設定されているため、プログラムはこのビットと適切なアクションを実行します。プログラミングの観点からは、ポーリングに似ています。

これは通常、バス以外のマスター転送にのみ適用されます。

ただし、バスマスター転送(つまりDMA)を使用しているように見えるため、この場合は適用しないでください。

しかしとにかく、PCIコントローラーのデータシートを注意深く読み、特に割り込み処理に関連するビット/レジスターを探すことをお勧めします。

編集:

アプリケーションレベルのプログラミングに関する限り、プログラムはコードの外部にアクセスしないため、_farポインタに遭遇/使用する必要はありません。

ただし、これは完全には当てはまりません。システムレベルのプログラミングに進む場合は、メモリマップドデバイスレジスタ、外部ROM、または割り込みハンドラの実装などにアクセスする必要があります。

ここで話が変わります。セグメントの作成、つまり記述子の割り当てとそれに関連するセレクターの取得により、コードにバグがあったとしても、現在のコードが実行されている特定のセグメントの外部にあるものを煩わしく変更することはありません。そうしようとすると、CPUは障害を生成します。したがって、外部デバイス(特にメモリマップドデバイスのレジスタ)にアクセスする場合、またはBIOSなどのROMデータにアクセスする場合は、記述子を割り当て、実行する必要のある領域に応じてベースとセグメントの制限を設定することをお勧めします。読み取り/書き込みして続行します。しかし、あなたはそうする義務はありません。

たとえばROMにあるいくつかの外部コードは、far呼び出しで呼び出されると想定しています。

前に述べたように、x86アーキテクチャでは、完全に無効にする方法がないため、あるレベル(さらに下に行く)でセグメンテーションを処理する必要があります。しかし、フラットモデルでは、前述のように、外部(プログラムへの書き込み)にアクセスするときに、プログラマーの補助としてセグメンテーションが存在します。ただし、使用したくない場合は使用する必要はありません。

割り込みハンドラが呼び出されると、割り込みが発生したプログラムのベースと制限がわかりません。割り込みプログラムのセグメント属性、制限などはわかりません。CSとEIPを除いて、すべてのレジスタは割り込みハンドラで未定義の状態にあります。したがって、現在実行中のプログラムの外部のどこかにあることを示すために、far関数として宣言する必要があります。

于 2012-07-28T05:02:01.427 に答える