2017-02-08 2 views
3

Я пытаюсь настроить аппаратный прерыватель в защищенном режиме, используя для компиляции в . Вот наименьший код возможно (прерывание от таймера), я думаю:Защищенное устройство Прерывание обработчика? (DJGPP)

#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). Я пропустил линию?

+2

'counter' должен быть помечен' volatile'. –

+0

Кроме того, избавляйтесь от ненужных бросков в вызовах '_go32_dpmi_lock_code' и' ... data'. Они берут 'void *' (который примет указатель любого типа) и 'size_t' (что является результатом' sizeof'). –

+1

Кроме того, ваше использование 'endHandler', чтобы попытаться вычислить размер' handler', является сомнительным. Ничто не гарантирует, что 'endHandler' придет сразу после' handler', как вы, кажется, ожидаете. В GCC лучшим решением является установка 'handler' в пользовательский раздел и использование переменной скрипта компоновщика для получения его размера. Однако я не уверен в DJGPP. –

ответ

0

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

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

_go32_dpmi_lock_code((void *) handler, 4096); 

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

+0

Спасибо! Информация о старом обработчике, которая важна, важна. Я посмотрел на него дальше и узнал, что, вероятно, делает старый обработчик.] (Http://webpages.charter.net/danrollins/techhelp/0105.HTM) Добавление «outportb (0x20, 0x20);» моему обработчику кажется чтобы он работал как старый. Но я оставлю это при цепочке, если на самом деле это добавленное преимущество вы упомянули. – tobywoby

+0

@tobywoby Это может не потерять время на DOSBox, который может не полностью эмулировать часы BIOS, например, вместо этого вместо этого используются часы операционной системы хоста. На реальном ПК, хотя он будет терять время, потому что обработчик прерывания таймера BIOS увеличивает счетчик, используемый BIOS для отслеживания текущего времени. –

Смежные вопросы