close

最近在編寫內核驅動時出現因缺頁中斷被屏蔽而導致CPU佔用100%,不得不重啟的現象。
SoftICE中顯示的信息是: 

Break due to Page Fault(0Eh)...Fault=0000
現在基本搞清了這件事情。簡要陳述之並介紹幾個和改變中斷級有關的內核函數給大家。
  缺頁中斷,是指若要訪問的單元不在內存中時,需要臨時從硬盤調入一頁放入內存。

這種中斷由於是磁盤中斷,因此運行的中斷級按道理說應該是DIRQL硬件中斷級,但是由於這件事情呢,是歸IO管理器統一管理的,所以實際上屬於軟中斷,是屬於DISPATCH_LEVEL中斷級的。

因此如果訪問內存的代碼運行 在同一中斷級或更高中斷級上的話,缺頁中斷就會遭到屏蔽。也就是說我們要讀數據,數據現在在硬盤上,但是我們不讓CPU去硬盤上取數據,沒有數據,我們又 必須等著數據,因此就成為一種死循環。


    解決問題的辦法之一是想辦法在我們讀數據時保證數據在內存中,這也是WDM給我們提供的主要思路,就是申請非分頁內存(non paged memory)。這樣在我們讀數據期間就不用跨頁,也就不會產生缺頁中斷,一直有數據,也就不會出現死循環等待了。


    另一個思路是儘量在低中斷級上讀數據,這樣即使產生缺頁中斷我們可以等把磁盤上的數據取出來以後繼續讀,但是在驅動編程的很多場合下還是要在大於或等於 DISPATCH_LEVEL中斷級上讀數據的。所以在WDM編程中有一個不成文的規定,那就是在DISPATCH_LEVEL中斷級以上必須訪問非分頁內存。


    結論是,儘量使用兩種思路的結合,也就是說在中斷級較低且不太要求讀取速度的場合下最好用第二種方法,畢竟非分頁內存比較少,屬於稀缺資源。如果必須要在高中斷級上讀,那就用非分頁內存。


    下面介紹三個和中斷級有關的內核函數(在MSDN中能找到):

一、KeRaiseIrql 這個函數把硬件中斷級提升到一個指定的IRQL值,因此來屏蔽那些對當前處理器的相等或較低中斷級上的中斷。


【函數原型】
VOID KeRaiseIrql(
    KIRQL  NewIrql,     //輸入參數,用於指定要提升到的中斷級,
    PKIRQL  OldIrql     //輸出參數,用於記錄原來的中斷級,以便恢復
    );

二、KeLowerIrql這個函數把硬件中斷級恢復到原來的IRQL值。


【函數原型】
VOID KeLowerIrql(
    IN KIRQL  NewIrql   //輸入參數,應該是KeRaiseIrql函數的輸出參數,用來恢復到原來的中斷級,而不能是一個新的值
    );


三、KeGetCurrentIrql 這個函數用來獲取當前的IRQL值


【函數原型】
KIRQL KeGetCurrentIrql();

注意:1、調用這幾個函數需要包含wdm.h 或 ntddk.h文件,開發驅動的一般都會包含它們。

        2、對於前兩個函數,只有當NewIrql>=CurrentIrql才能成功調用KeRaiseIrql,

只有當NewIrql& lt;=CurrentIrql才能成功調用KeLowerIrql。而且KeLowerIrql的參數必須是先前調用KeRaiseIrql是返回的輸 出參數,也就是說這兩個內核函數一般是成對出現的。


       3、本質上,這種參數規定決定了我們只能提升中斷級,而不能任意降低中斷級,這也是一個合理的要求,因為大部分高中斷級並不能用代碼來降低,它們是由內核的規則規定了的。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 殘月影 的頭像
    殘月影

    Rootkit --逆向工程技術--

    殘月影 發表在 痞客邦 留言(0) 人氣()