3

我正在编写一个中断服务例程,它应该使用 int 70h 和 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

当我取消注释 INT70H 中的mov ax, 0mov dx, 0行时,我得到Testing!并且 DosBox 挂起,有时会崩溃。VMware 和 VirtualBox 也是如此。

当我用来自 INT70H 的两个 mov 注释掉读取 RTC 寄存器 C 的行时,我得到Testing!Testing!int 70h working并且 DosBox 挂起。VirtualBox 和 VMware 也会发生同样的事情。如果 INT70H 中的两个 mov 未注释,我得到Testing!并挂起。

这让我相信它可能是一些 DOS 系统调用(我不应该在最终产品中使用)可能会做坏事,但即使它们被注释掉,当我运行 INT70H 时,计算机也会挂起。

我的主要问题是,现在我完全不知道如何开始解决这个问题。

4

3 回答 3

1

中断服务程序 (ISR) 必须保存它使用的所有寄存器并恢复它们(这样被中断的软件就不会看到寄存器被随机丢弃)。这包括段寄存器(例如 DS 和 ES)。您需要在 ISR 开头附近的“ push ds”和“ 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 在后台执行的操作可能会干扰您的测试;你可以在像 Bochs 这样的东西中调试它,而无需先在虚拟机中安装 DOS/FreeDOS。作为额外的好处,您可以在目标操作模式(例如,可能是 32 位保护模式)中执行此操作,而不是稍后重写 16 位实模式代码。

于 2011-12-28T04:03:42.550 回答
1

中断服务程序必须在执行任何依赖于它们的操作之前设置段寄存器。调用中断时,它可以具有系统中绝对任何内容的上下文。打印字符串的调用尤其成问题,因为它们依赖于ds:dx字符串地址,但ds没有设置。

除此之外,它表面上看起来还不错。看看设置是否ds解决了挂起问题。如果没有,请跟进。

于 2011-12-27T19:26:35.447 回答
0

这是一个非常奇怪的错误。非常感谢所有提供帮助的人,但最后发现,当我设置 RTC 时,我在写入之前没有将输出寄存器设置为 B。现在它工作正常。

于 2011-12-30T11:59:53.990 回答