2017-02-08 30 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(因此永遠不會停止主循環),使我猜測處理程序不能正確返回或僅被調用一次。另一方面鏈接工作正常(刪除包裝線,並用chain_protected_mode替換set_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將在handler之後放置endHandler。我建議你只是簡單地鎖定兩個頁面handler啓動並在情況下,它橫跨頁下頁:

_go32_dpmi_lock_code((void *) handler, 4096); 

注意這裏需要投,因爲是從指針沒有自動轉換的功能類型指向void的指針。

+0

謝謝!有關舊處理程序的信息是_that_重要的信息很好。我進一步研究並發現[舊的處理程序可能做了什麼](http://webpages.charter.net/danrollins/techhelp/0105.HTM)將'outportb(0x20,0x20);'添加到我的處理程序中似乎讓它像舊的一樣工作。 但是如果它真的具有你提到的附加利益,我會放棄它。 – tobywoby

+0

@tobywoby它可能不會在DOSBox上浪費時間,例如通過使用主機操作系統時鐘代替BIOS時鐘,這可能無法完全模擬BIOS時鐘。在真實的PC上,雖然它會失去時間,因爲BIOS的定時器中斷處理程序增加了BIOS使用的計數器來跟蹤當前時間。 –