0

別の ISR (Interrupt Service Routine) にジャンプするには、far jump 命令を生成する必要があります。私は 32 ビットの FreeDOS アプリケーションを開発しています。

OW のマニュアル ( cguide.pdfおよびclr.pdf ) を読んだ後、警告やエラーなしで正常にコンパイルされる 2 つの方法を見つけました。

    /* Code Snippet #1 */

    #pragma aux old08 aborts ;
    void (__interrupt __far *old08)(void);      // function pointer declaration


    void __interrupt __far new08(void) {

           /* Do some processing here ... */

           (*old08)();  /* OW will now generate a jump inst. instead of call*/
     }

私が考え出した他のアプローチは次のとおりです。

      /* Code Snippet #2 */

      static void jumpToOld08(void);         
      # pragma aux jumpToOld08 = \
             ".686p"     \       
             "                DB      0xEA"  \          
             "off_old08       DD      0"     \               
             "sel_old08       DW      0"     ;             


      void __interrupt __far new08(void){

               /* Do some processing here ... */

               jumpToOld08();   
      }

      extern unsigned short sel_old08;
      extern unsigned int off_old08;

      sel_old08 = ( __segment )FP_SEG(old08);
      off_old08 = FP_OFF(old08);        

さて、私の質問は、上記の 2 つの方法のどちらがより正しいか、または優れているかということです。アイデアや意見はありますか?

これを達成する他の方法はありますか?

4

3 に答える 3

2

interrupt機能は常に遠いです。

手動で作成したファージャンプは、命令自体に関する限り正しいように見えますが、(呼び出す代わりに)単にジャンプnew08()しても、プロローグでスタックに以前に保存されたものは削除されません(これは潜在的に多くのレジスター、そして最も重要なのは、あなたold08()が戻らなければならない差出人住所も埋もれていることです!)。

なぜそんなに独創的ですか?

于 2012-07-18T09:39:46.743 に答える
0
    #include <dos.h>
    void _chain_intr( void (__interrupt __far *func)(void) );

この関数を使用して、チェーン内の別の割り込みハンドラにジャンプできます。この関数は戻りません。割り込みキーワードによって保存されたすべてのレジスタをポップオフし、ハンドラにジャンプします。funcで指定された割り込みハンドラが制御を受け取ると、スタックとレジスタは、割り込みが発生したように見えます。

この関数は、 interruptキーワードで宣言された関数内でのみ使用できます。

呼び出しよりもジャンプの利点は、irq ハンドラーでは明らかではありませんが、ソフトウェア割り込みハンドラーでは明らかです。チェーン内の次のソフトウェア割り込みハンドラーは、渡されたパラメーターなどの情報が cpu レジスターに含まれていることを期待しているため、次のハンドラーにジャンプする前に、chainintr は、次のハンドラーが直接制御を受け取ったかのように、すべての cpu レジスターを復元します。

于 2012-07-28T03:51:05.847 に答える
0

私はおそらく次のように書くでしょう:

void far_jump (uint32_t offset, uint16_t selector)
{
    /* remove the (callee's) stack frame including the return address by manipulating esp & ebp */

    /* the top of the stack now points to offset:selector */

    _asm
    {
        retf    ; or whatever the asm syntax dictates
    }

    /* esp & ebp will now point to the caller's stack frame */
}

思い出したように、32 ビット モードでは、下位 16 ビットのみが使用されていても、セレクターが 32 ビット単位でプッシュおよびポップされます。

于 2012-08-19T09:00:41.537 に答える