3

タイマーで使用するためにint70hとIRQ8を使用してRTCによって引き起こされた割り込みを処理することになっている割り込みサービスルーチンを書いています。残念ながら、私はそれに関して多くの問題を抱えていたので、私は問題をいくつかの小さな問題に分けて、それぞれを独立して解決することにしました。まず、ハードウェアの部分をあきらめて、最初にソフトウェアに割り込みを実装することにしました。

現在、NASMとDosBoxを使用しています。

ISRコードは次のとおりです。

segment .code
; ----------------------------------------------
; writes a message on the screen
; every time interrupt is called
; ----------------------------------------------

INT_CODE equ 070h

my_int:
    pusha           ;saves all registers on stack so they get preserved

    ;EDIT1
    xor ax, ax      ;sets ax to zero
    mov es, ax      ;puts zero into extra segment register
    mov bx, [es:INT_CODE*4+2] ;this should give us the sergment of the ISR
    mov ds, bx      ;the segment is now in ds
    ;END OF EDIT1

    ;mov ax, 0      ;cleans any garbage in ax

    ;mov ah, 09h    ;preparing to call DOS system call, remove later
    mov ax, string_s
    mov si, ax
    call _print_string


    ;int 021h       ;this should hopefully work

    mov al, 0Ch     ; Accessing RTC
    out 070h, al    ; register C should be read
    in al, 071h     ;or there won't be any new interrupts (or so it's supposed to be)

    ;mov ax, 0      ; again we clear anything left in ax, just in case
    ;mov ah, 09h    ; preparing to write string
    mov ax, string_e
    mov si, ax
    call _print_string
    ;int 021h       ; this should work

    mov al, 20h     ;we're letting PICs know the interrupt ended
    out 0A0h, al    ;notifying second PIC
    out 020h, al    ;notifying first PIC

    popa            ;application gets its registers back

    iret

_inst_70:
    cli             ;hardware interrupts are now stopped
    xor     ax, ax
    mov     es, ax
    mov     bx, [es:INT_CODE*4]
    mov     [old_int70_off], bx
    mov     bx, [es:INT_CODE*4+2]
    mov     [old_int70_seg], bx

; adding our routine to interrupt vector table
    mov     dx, my_int
    mov     [es:INT_CODE*4], dx
    mov     ax, cs
    mov     [es:INT_CODE*4+2], ax
    sti

    ;mov ah, 09h

    mov ax, string_inst
    mov si, ax
    call _print_string
    ;int 021h

    ret

; -----------------------------------------------------------------------------
; return old int 70 h

_uninst_70:
    cli
    xor     ax, ax
    mov     es, ax
    mov     ax, [old_int70_seg]
    mov     [es:INT_CODE*4+2], ax
    mov     dx, [old_int70_off]
    mov     [es:INT_CODE*4], dx
    sti
    ret

_print_string:

    pusha
    mov     ah, 0Eh                     ; BIOS INT 10h teletype (TTY) function
.Repeat:
    lodsb                               ; takes one character from a string
    cmp     al, 0
    je     .End                         ; If it's zero, end of string
    int     10h                         ; if not, call BIOS
    jmp    .Repeat                      ; and go to next character
.End:
    popa
    ret

segment .data

string_s: db 'We're in ISR',0
string_e: db 'It's working',0
string_inst: db 'Installed',0

old_int70_seg: dw 0
old_int70_off: dw 0

次のプログラムを使用して、この割り込みをテストしています。

;myint
org 100h;installs the interrupt
segment .code

main:
    call   _inst_70

    ;call   _uninst_70 ; THIS IS ON PURPOSE!
    ret

%include "myint.asm"

;int70h
org 100h            ;calls the interrupt
segment .code
    mov ah, 09h     ; getting ready to print string
    mov dx, string1
    int 21h

    ;mov ax, 0      ;getting rid of the last message
    ;mov dx, 0

    int 070h        ;calling the interrupt

    mov ah, 09h
    mov dx, string2;
    int 21h

    ret

segment .data
string1: db 'Testing!',0
string2: db 'int 70h working',0
_print_string:

        pusha
        mov     ah, 0Eh         ; BIOS INT 10h teletype (TTY) function
.Repeat:
        lodsb                   ; takes one character from a string
        cmp     al, 0
        je     .End             ; If it's zero, end of string
        int     10h             ; if not, call BIOS
        jmp    .Repeat          ; and go to next character
.End:
        popa
        ret

今、私たちは興味深い部分に到達しています。

インストールプログラムを呼び出すと、割り込みがインストールされ、プログラムが正常に終了したように見えるというメッセージが表示されます。

INT70H.COMを呼び出すと、メモリ領域のダンプのように見えるものが表示されます。その中で唯一読めるものは: Testing!Testing!int 70h workingC:\NASM-DOS\NASM.EXE

mov ax, 0INT70Hのandmov dx, 0行のコメントを外すTesting!と、DosBoxがハングし、クラッシュすることがあります。VMwareとVirtualBoxでも同じことが起こります。

INT70Hからの2つのmovsがコメントされた状態でRTCのレジスタCを読み取っている行をコメントアウトすると、取得Testing!Testing!int 70h workingしてDosBoxがハングします。VirtualBoxとVMwareでも同じことが起こります。INT70Hの2つのmovがコメントされていない場合、私は取得Testing!してハングします。

これにより、一部のDOSシステムコール(最終製品で使用することは想定されていません)が何か悪いことをしている可能性があると思いましたが、コメントアウトしても、INT70Hを実行するとコンピューターがハングします。

私の主な問題は、今のところ、この問題に取り組み始める方法がまったくわからないということです。

4

3 に答える 3

1

割り込みサービスルーチンは、セグメントレジスタに依存する操作を実行する前に、セグメントレジスタを設定する必要があります。割り込みが呼び出されると、システム内のあらゆるもののコンテキストを持つことができます。ds:dx文字列を印刷するための呼び出しは、文字列アドレスに依存しているため、特に問題がありますが、ds設定されていません。

それ以外は、表面的にはきれいに見えます。セットアップdsによってハングの問題が解決するかどうかを確認します。そうでない場合はフォローアップします。

于 2011-12-27T19:26:35.447 に答える
1

割り込みサービスルーチン(ISR)は、使用するレジスタを保存して復元する必要があります(割り込みが発生したソフトウェアが、ランダムにゴミ箱に入れられたレジスタを認識しないようにするため)。これには、セグメントレジスタ(DSやESなど)が含まれます。push dsISRの開始近くに「」と「」が必要でありpush es、「iret」の前に対応する「pop」命令が必要です。

BIOS関数はいずれも再入可能ではないため、ISRでそれらを使用することは安全ではありません。実行されている可能性のある他のコードがそれらを使用しないことを保証できない場合を除きます。これには、「int 0x10、ah = 0x0E」関数(メインコードおよびメインコードを中断するISRで使用している)が含まれます。テストのためだけにある場合。代わりに、ディスプレイメモリへの直接書き込みを試してください(たとえば、テキストモードの場合は " mov ax,0xB800; mov es,ax; inc word [es:0]")。

OSコードをテストする場合、多くの場合、OSコードをテストする方が簡単です。たとえば、これが意図的に戻らなかった(ロックされた)ブートセクタに実装された場合。そうすれば、以前のIVTエントリを保存/復元したり、テストに干渉する可能性のあるDOSやTSRがバックグラウンドで実行していることを心配したりする必要がなくなります。最初に仮想マシン内にDOS/FreeDOSをインストールしなくても、Bochsのようなものでデバッグできます。追加のボーナスとして、後で16ビットのリアルモードコードを書き換えるのではなく、ターゲットの動作モード(たとえば32ビットのプロテクトモード)でそれを行うことができます。

于 2011-12-28T04:03:42.550 に答える
0

これは本当に奇妙なバグでした。助けてくれたすべての人に感謝しますが、結局、RTCを設定するときに、書き込む前に出力レジスタをBに設定しなかったことがわかりました。今では正常に動作します。

于 2011-12-30T11:59:53.990 に答える