【问题标题】:Dos Interrupt Handler Locks Up ProgramDos 中断处理程序锁定程序
【发布时间】:2017-01-02 23:43:26
【问题描述】:

我正在尝试制作一个简单的游戏引擎/库来创建我自己的 DOS 游戏。我目前正在努力让输入正常工作。我遇到的问题是我处理 int 9(键盘输入)的自定义 ISR 锁定了我的程序。

注意:我通过使用我的编译器的 _dos_getvect() 和 _dos_setvect() 让它工作;但是,我不知道为什么我自己的自定义 getInterruptVector() 和 setInterruptVector() 不起作用。如果有人能解释原因,我将不胜感激。

查看“interrupt_hooker.c”中的相关代码。

main.c

#include "input.h"
#include "stdio.h"

int main(int argc, char *argv[])
{
    hookKeyboardISR();

    unsigned char i = 0;

    while(1)
    {
        printf("%i", 1);
        //i = getKey(SCAN_ESC);
        //printf("%i", i);
    }

    unhookKeyboardISR();
    return 0;
}

输入.h

#ifndef INPUT_H_INCLUDED
#define INPUT_H_INCLUDED

#include "scan_codes.h"

void            hookKeyboardISR();
void            unhookKeyboardISR();

unsigned char   getKey(unsigned char scan_code);

unsigned char   isExtended();

#endif // INPUT_H_INCLUDED

输入.c

#include "input.h"
#include "interrupt_hooker.h"

#ifndef NULL
#define NULL ((void*)0)
#endif // NULL

unsigned char key_array[MAX_SCAN_CODES] = {0};
unsigned char extended_key = 0;

void __interrupt (*oldKeyboardISR)() = NULL;


unsigned char getKey(unsigned char scan_code)
{
    return key_array[scan_code];
}

unsigned char isExtended()
{
    return extended_key;
}

void __interrupt keyboardISR()
{
    unsigned char scan_code = 0;

    unsigned char temp = 0;
    scan_code = inp(0x60);
    outp(0x61,(temp = inp(0x61)) | 0x80);
    outp(0x61,temp);
    /*asm
    {
        in  al, 60h         //get scan code from keyboard controller
        mov scan_code, al   //put it in scan_code

        in  al, 61h
        or  al, 80h
        out 61h, al
        xor al, 80h
        out 61h, al
    }*/

    switch(scan_code)
    {
    //if extended code
    case 0xe0:
        extended_key = 1;
        break;

    case 0xe1:
        break;

    default:
        //check if break code
        if(scan_code & 0x80){
            scan_code &= 0x7f;

            //set key to released
            key_array[scan_code] = 0;

        }
        else{
            //set key to pressed
            key_array[scan_code] = 1;
        }

        extended_key = 0;
        break;
    }

    //send EOI
    outp(0x20, 0x20);
    /*asm
    {
        sti
        mov al, 20h
        out 20h, al
    }*/
}

void hookKeyboardISR()
{
    if(oldKeyboardISR == NULL){
        getInterruptVector(0x09, oldKeyboardISR);
        setInterruptVector(0x09, keyboardISR);
    }
}

void unhookKeyboardISR()
{
    if(oldKeyboardISR != NULL){
        setInterruptVector(0x09, oldKeyboardISR);
        oldKeyboardISR = NULL;
    }
}

interrupt_hooker.h

#ifndef INTERRUPT_HOOKER_H_INCLUDED
#define INTERRUPT_HOOKER_H_INCLUDED

void getInterruptVector(unsigned char int_number, void __interrupt (*isr)());

void setInterruptVector(unsigned char int_number, void __interrupt (*isr)());

#endif // INTERRUPT_HOOKER_H_INCLUDED

interrupt_hooker.c

void getInterruptVector(unsigned char int_number, void __interrupt (*isr)())
{
    asm
    {
        cli
        mov al, int_number
        mov ah, 35h
        int 21h

        mov word ptr [isr], bx
        mov word ptr [isr+2], es
        sti
    }
}

void setInterruptVector(unsigned char int_number, void __interrupt (*isr)())
{
    asm
    {
        cli
        mov dx, word ptr [isr+2]
        mov ds, dx
        mov dx, word ptr [isr]

        mov al, int_number
        mov ah, 25h
        int 21h
        sti
    }
}

【问题讨论】:

    标签: c assembly game-engine dos


    【解决方案1】:

    mov dx, word ptr [isr] 可能会尝试使用您刚刚破坏的ds,除非isr 被解析为bp+offset,在这种情况下它将使用ss,这应该很好。另外,我猜编译器不会高兴你销毁ds

    更安全的代码可能是:

    cli
    push ds
    mov al, int_number
    mov ah, 25h
    mov dx, word ptr [isr]
    mov ds, word ptr [isr+2]
    int 21h
    pop ds
    sti
    

    您的 getInterruptVector 已损坏,因为它缺少间接级别 - 您只是在修改 C 中按值传递的参数。您必须将其调用为 getInterruptVector(0x09, &oldKeyboardISR);(注意 & ) 当然在你的函数中取消引用它,比如:

        mov al, int_number
        mov ah, 35h
        int 21h
    
        mov di, word ptr [isr]
        mov [di], bx
        mov [di+2], es
    

    (假设有一个 16 位的近端指针,不确定你的内存模型是什么。)

    【讨论】:

    • 是的,您的 asm 代码似乎运行良好。谢谢你。唯一的问题是getInterruptVector(0x09, &oldKeyboardISR) 给了我一个错误。错误消息是“错误:需要对函数参数 2 进行显式转换才能获取。”我真的不知道这意味着什么。我正在使用 Digital Mars C 并为小内存模型编译,顺便说一句。
    • 当然,你还需要在函数定义中添加一个*,我跳过了那部分。 IE。 void getInterruptVector(unsigned char int_number, void __interrupt (**isr)()) 或者,你知道,你可以让它返回值而不是传递一个输出指针参数。
    • 不,那没用。还是同样的错误。我想我可以返回一个函数指针,但我更喜欢这种方式,因为它更一致。这样的固执迫使我学习东西,这就是这个 DOS 项目的全部目的。这个问题似乎与&oldKeyboardISR 有关,因为我可以将它传递给 getInterruptVector() 或 setInterruptVector() 并且它给了我错误,但是当我通过&keyboardISR 它工作得很好。
    • 另外,我不认为这可以通过值传递,因为根据定义,我是传递一个指向函数的指针。
    • 您可能忘记更新标头中的原型和 .c 文件中的实现。请注意,这仅适用于 get。 C 中的所有参数都是按值传递的。如果要修改指针,则需要将指针传递给它,因此是双重间接的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    • 2017-03-02
    • 2011-07-20
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    相关资源
    最近更新 更多