Monday, September 03, 2007

Windows Driver programming[2]

IRQL(Interrupt Request Level)

Microsoft 訂出了 32 個 IRQL,但是呢,基本上 Driver 只會碰到三個 IRQ Level:Passive、Dispatch、Device(DIRQL)。 IRQL 高的 Thread 不會被 IRQL 低的 Thread 中斷。跑在 Passive Level 的 thread,限制最少。 而跑在 Dispath Level 的 Thread,則是不可以 wait event/semaphore/mutex,但是可以 busy waiting。 而跑在 DIRQL 的 Thread,最好連 busy waiting 都不要。

Microsoft 已經訂出所有函式能夠執行的 IRQL,Driver 必須遵照指示。為甚麼會有 IRQL?我相信這是大多數人在看 Programming the microsoft windows driver model 這本書時, 一開始會有的疑問。這牽涉到 OS threading model。要知道,CPU 一次只能執行一個指令,這代表,CPU 一次只能執行一個 thread, 好吧,不要考慮雙 CPU 的情況,畢竟,SMP 的狀況,連 DDK 都講的不清不楚。而執行中的 thread,又有分重要跟不重要(處理 hardware interrupt 的 thread 一定比處理 software interrupt 跟 service call 的 thread 重要吧?)。

當重要的 thread 在處理事情時,一定不會希望被別人搶走 CPU 的執行權吧?而這就是 IRQL 的概念:IRQL 高的 thread 不會被 IRQL 低的 thread 搶走 CPU 使用權。 這其實很簡單,只是這跟 driver 有什麼關係?喔,driver 也者,被動呼叫也,所以它自己是不會去搶 CPU 的,只有某些 OS thread 需要你的 driver 的時候,才會呼叫你。

OS thread 有分重要跟不重要吧?當重要的 thread 呼叫你的時候,結果你卻跑去睡覺,或是不重要的 thread 呼叫你,結果你卻引起 page fault,這都是不被允許的。舉個比較明確的例子(DDK 都是用那些非常抽象的語法), 當 Windows 的某個重要的 thread 在 disable interrupt 之後,呼叫你的 driver,結果你卻在裡面睡大覺,結果就是沒有任何 interrupt 會被處理,OS 就跟當掉沒兩樣,因為它期待你很快就會結束,結果你卻不鳥它。

而另外一個例子,非常容易發生的例子,你一定會遇到的例子,『IRQL less than or equal』,這通常表示,某個不重要的 thread 呼叫你的 driver,可是你的 driver 卻存取一些不在實體記憶體內的資料。

什麼叫做『不在實體記憶體內的資料』?就是你要存取的記憶體位置是非法的,尚未被載入到 ram。有這種事嗎?有的,OS 課本提到的虛擬記憶體。虛擬記憶體的內容有可能是在 disk,或是 ram 內。 而一般而言,driver 直接存取在 disk 內的虛擬記憶體內容,都會產生 page fault,而很不幸的,某些 IRQL 不能允許 page fault 產生,因為它的 IRQL 比處理 page fault 的 thread 還要高,而 IRQL 高的 thread 是不會被 IRQL 低的 thread 搶走 CPU 使用權, 這表示一旦發生 page fault,沒人可以處理這個問題,BSOD 直接產生。所幸,BSOD 跟 kernel dump 會跟我們講問題發生點,所以這個問題很好解決。

基本上,Windows driver 是一堆 function 的集合,等著被呼叫。所以搞清楚每個 function 執行的 IRQL,跟每個 OS service call 的 IRQL 是很重要的。

No comments:

codeblock