Застрял обработчик защищенного аппаратного прерывания? (DJGPP)

Я пытаюсь настроить обработчик аппаратного прерывания в защищенном режиме, используя djgpp-2 для компиляции в dosbox-0.74. Вот наименьший возможный код (прерывание по таймеру), я думаю:

#include <dpmi.h>
#include <go32.h>
#include <stdio.h>

unsigned int counter = 0;

void handler(void) {
    ++counter;
}
void endHandler(void) {}

int main(void) {
    _go32_dpmi_seginfo oldInfo, newInfo;

    _go32_dpmi_lock_data(&counter, sizeof(counter));
    _go32_dpmi_lock_code(handler, endHandler - handler);

    _go32_dpmi_get_protected_mode_interrupt_vector(8, &oldInfo);

    newInfo.pm_offset = (int) handler;
    newInfo.pm_selector = _go32_my_cs();
    _go32_dpmi_allocate_iret_wrapper(&newInfo);

    _go32_dpmi_set_protected_mode_interrupt_vector(8, &newInfo);

    while (counter < 3) {
        printf("%u\n", counter);
    }

    _go32_dpmi_set_protected_mode_interrupt_vector(8, &oldInfo);
    _go32_dpmi_free_iret_wrapper(&newInfo);

    return 0;
}

Обратите внимание, что я не связываю свой обработчик, а заменяю его. Счетчик не увеличится за пределы 1 (поэтому никогда не останавливая основной цикл), заставляя меня догадываться, что обработчик не возвращается правильно или вызывается только один раз. С другой стороны, цепочка работает нормально (удалите строки-обертки и замените set_protected_mode с chain_protected_mode). Я пропускаю линию?

1 ответ

Решение

Вам нужно связать старый обработчик прерываний, как в примере с Jonathon Reinhart, на который ссылается документация, так как старый обработчик скажет контроллеру прерываний прекратить утверждение прерывания. Это также будет иметь дополнительное преимущество, заключающееся в том, что часы BIOS будут тикать, поэтому они не будут терять несколько секунд при каждом запуске программы. В противном случае, когда ваш обработчик прерываний вернется, ЦПУ немедленно вызовет этот обработчик, и ваша программа застрянет в бесконечном цикле.

Также нет гарантии, что GCC разместит endHandler после handler, Я бы рекомендовал просто заблокировать обе страницы handler начинается и следующая страница в случае, если она выходит за пределы страницы:

_go32_dpmi_lock_code((void *) handler, 4096);

Обратите внимание, что приведение здесь необходимо, так как нет автоматического преобразования из указателя на типы функций в указатель на void.

Другие вопросы по тегам