64位内核开发第十讲,IRQL中断级别了解
目錄中斷級(jí)別IROL了解一丶IRQL1.了解什么是中斷2.IROL中斷級(jí)別.3.遵守IROL編程規(guī)范的方式
中斷級(jí)別IROL了解
一丶IRQL
1.了解什么是中斷
中斷就是產(chǎn)生的一個(gè)電信號(hào).比如鍵盤(pán).當(dāng)按下就會(huì)產(chǎn)生電信號(hào)發(fā)送給CPU
而CPU就會(huì)停止當(dāng)前處理.去執(zhí)行電信號(hào).他是根據(jù)IRQL中斷級(jí)別來(lái)進(jìn)行處理的.
如下圖:
中斷說(shuō)白了就是個(gè)電信號(hào).打斷CPU執(zhí)行的代碼. 去調(diào)用中斷處理函數(shù).
此時(shí)CPU就處于硬件上下文.
2.IROL中斷級(jí)別.
因?yàn)闀?huì)產(chǎn)生很多CPU電信號(hào).所有硬件同是發(fā)送中斷處理級(jí)別怎么辦.所以需要為這些級(jí)別分一個(gè)優(yōu)先級(jí). CPU會(huì)先執(zhí)行優(yōu)先級(jí)高的.會(huì)把優(yōu)先級(jí)低的給屏蔽掉.
當(dāng)CPU處于中斷上下文的時(shí)候. CPU不能是阻塞的/阻塞. 沒(méi)有進(jìn)程可以調(diào)度.
了解CPU的上下文.至少腦海需要有印象
| 上下文 | 說(shuō)明 |
|---|---|
| 中斷上下文 | CPU代替硬件做某些事情. |
| 進(jìn)程上下文 | CPU代替進(jìn)程做某些事情. |
中斷級(jí)別了解
如下圖:
軟件中只會(huì)處理下面三種級(jí)別.
DISPATCH_LEVEL最高
APC_LEVEL 其次
PASSIVE_LEVEL最低
3.遵守IROL編程規(guī)范的方式
1.查詢MSDN.MSDN最下面有IRQL級(jí)別的說(shuō)明.
運(yùn)行在DISPATHCH_LEVEL級(jí)別的上下文.如何調(diào)用PASSIVE_LEVEL級(jí)別的函數(shù).
如我們有一個(gè)需求.
當(dāng)鍵盤(pán)按下的時(shí)候. 鍵盤(pán)的優(yōu)先級(jí)最高. 會(huì)運(yùn)行在DISPATCH_LEVEL級(jí)別.但是此時(shí)
按照我們Ring3編程的想法.你可能會(huì)調(diào)用ZwCreateFile這個(gè)函數(shù)進(jìn)行將按鍵寫(xiě)入到文件中.
但是此時(shí)我們?nèi)绻樵僊SDN之后就會(huì)發(fā)現(xiàn).其實(shí)ZwCreateFile是不能運(yùn)行在DISPATCH級(jí)別的. 此時(shí)解決方法 就是創(chuàng)建一個(gè) 工作線程. 工作線程中完成
我們想要操作的事情.
3.在PASSIVE級(jí)別下.我們可以使用任何內(nèi)存沒(méi)有限制.
首先了解下如下表格.
| 函數(shù) | 運(yùn)行級(jí)別 |
|---|---|
| DriverEntry | Passive級(jí)別. |
| 各種派遣函數(shù) | Passive級(jí)別 |
| 完成函數(shù) | Dispatch級(jí)別 |
| 各種NDIS回調(diào)函數(shù) | Dispatch級(jí)別 |
PASSIVE級(jí)別是可以使用任何函數(shù)和內(nèi)存
DISPATCH級(jí)別只能訪問(wèn)能運(yùn)行在DISPATCH級(jí)別內(nèi)存.
非分頁(yè)內(nèi)存
NONPAGEPOOL 內(nèi)存是可以在任何級(jí)別使用的.
相關(guān)申請(qǐng)內(nèi)存函數(shù)為:
ExAllocatePoolWithTag
PAGEDPOOL 分頁(yè)內(nèi)存
只能在PASSIVE級(jí)別或者APC級(jí)別使用.
我們可以加入一個(gè)宏.來(lái)判斷當(dāng)前的中斷級(jí)別.有沒(méi)有高于APC
產(chǎn)生一個(gè)斷言.如果當(dāng)前級(jí)別大于APC級(jí)別就會(huì)報(bào)錯(cuò).
斷言宏的意思就是 我決定當(dāng)前的事就是某事. 如果你不是我指定的.
那么對(duì)不起.報(bào)錯(cuò).
使用PAGE_CODE這個(gè)宏即可.
其實(shí)很簡(jiǎn)單.宏站看看一下.
#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)
其實(shí)很簡(jiǎn)單. 首先調(diào)用 KeGetCurrentIrql() 這個(gè)函數(shù)來(lái)判斷是否小于等于 APC級(jí)別.
然后當(dāng)參數(shù)傳遞給 PAGED_ASSERT(exp)宏. 里面就調(diào)用函數(shù)進(jìn)行斷言
斷言宏只會(huì)在Debug版本中有效.讓我們盡快發(fā)現(xiàn)問(wèn)題.
把 PAGE_CODE 放到我們代碼塊中即可.
總結(jié)
以上是生活随笔為你收集整理的64位内核开发第十讲,IRQL中断级别了解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 男孩起名字王鹏(取个好名字,给小王鹏起名
- 下一篇: 怎么创建具有真实纹理的CG场景岩石?