64位内核开发第十讲,IRQL中断级别了解
目錄中斷級別IROL了解一丶IRQL1.了解什么是中斷2.IROL中斷級別.3.遵守IROL編程規范的方式
中斷級別IROL了解
一丶IRQL
1.了解什么是中斷
中斷就是產生的一個電信號.比如鍵盤.當按下就會產生電信號發送給CPU
而CPU就會停止當前處理.去執行電信號.他是根據IRQL中斷級別來進行處理的.
如下圖:
中斷說白了就是個電信號.打斷CPU執行的代碼. 去調用中斷處理函數.
此時CPU就處于硬件上下文.
2.IROL中斷級別.
因為會產生很多CPU電信號.所有硬件同是發送中斷處理級別怎么辦.所以需要為這些級別分一個優先級. CPU會先執行優先級高的.會把優先級低的給屏蔽掉.
當CPU處于中斷上下文的時候. CPU不能是阻塞的/阻塞. 沒有進程可以調度.
了解CPU的上下文.至少腦海需要有印象
| 上下文 | 說明 |
|---|---|
| 中斷上下文 | CPU代替硬件做某些事情. |
| 進程上下文 | CPU代替進程做某些事情. |
中斷級別了解
如下圖:
軟件中只會處理下面三種級別.
DISPATCH_LEVEL最高
APC_LEVEL 其次
PASSIVE_LEVEL最低
3.遵守IROL編程規范的方式
1.查詢MSDN.MSDN最下面有IRQL級別的說明.
運行在DISPATHCH_LEVEL級別的上下文.如何調用PASSIVE_LEVEL級別的函數.
如我們有一個需求.
當鍵盤按下的時候. 鍵盤的優先級最高. 會運行在DISPATCH_LEVEL級別.但是此時
按照我們Ring3編程的想法.你可能會調用ZwCreateFile這個函數進行將按鍵寫入到文件中.
但是此時我們如果查詢MSDN之后就會發現.其實ZwCreateFile是不能運行在DISPATCH級別的. 此時解決方法 就是創建一個 工作線程. 工作線程中完成
我們想要操作的事情.
3.在PASSIVE級別下.我們可以使用任何內存沒有限制.
首先了解下如下表格.
| 函數 | 運行級別 |
|---|---|
| DriverEntry | Passive級別. |
| 各種派遣函數 | Passive級別 |
| 完成函數 | Dispatch級別 |
| 各種NDIS回調函數 | Dispatch級別 |
PASSIVE級別是可以使用任何函數和內存
DISPATCH級別只能訪問能運行在DISPATCH級別內存.
非分頁內存
NONPAGEPOOL 內存是可以在任何級別使用的.
相關申請內存函數為:
ExAllocatePoolWithTag
PAGEDPOOL 分頁內存
只能在PASSIVE級別或者APC級別使用.
我們可以加入一個宏.來判斷當前的中斷級別.有沒有高于APC
產生一個斷言.如果當前級別大于APC級別就會報錯.
斷言宏的意思就是 我決定當前的事就是某事. 如果你不是我指定的.
那么對不起.報錯.
使用PAGE_CODE這個宏即可.
其實很簡單.宏站看看一下.
#define PAGED_CODE() PAGED_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
#if (NTDDI_VERSION >= NTDDI_VISTA)
#define PAGED_ASSERT( exp ) NT_ASSERT( exp )
#else
#define PAGED_ASSERT( exp ) ASSERT( exp )
#endif
往下跟很多.....
直到最終
#define NT_ASSERT_ACTION(_exp)
((!(_exp)) ?
(__annotation(L"Debug", L"AssertFail", L#_exp),
DbgRaiseAssertionFailure(), FALSE) :
TRUE)
其實很簡單. 首先調用 KeGetCurrentIrql() 這個函數來判斷是否小于等于 APC級別.
然后當參數傳遞給 PAGED_ASSERT(exp)宏. 里面就調用函數進行斷言
斷言宏只會在Debug版本中有效.讓我們盡快發現問題.
把 PAGE_CODE 放到我們代碼塊中即可.
總結
以上是生活随笔為你收集整理的64位内核开发第十讲,IRQL中断级别了解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 男孩起名字王鹏(取个好名字,给小王鹏起名
- 下一篇: 汇编之偏移地址几种常用写法