Professional Documents
Culture Documents
Lập Trình Hệ Thống
Lập Trình Hệ Thống
Bin tp bi:
Khoa CNTT HSP KT Hng Yn
LP TRNH H THNG
Bin tp bi:
Khoa CNTT HSP KT Hng Yn
Cc tc gi:
Khoa CNTT HSP KT Hng Yn
MC LC
1. Bi 1: TNG QUAN V LP TRNH H THNG
1.1. Khi nim v lp trnh h thng
1.2. Tng quan v lp trnh h thng
1.3. Lch s v lp trnh h thng
1.4. Cu trc tng quan lp trnh h thng
2. Bi 2: CNG C LP TRNH H THNG
2.1. Cc ngn ng lp trnh
2.2. Gii thiu v C++
2.3. Gii thiu v Visual C++
3. Bi 3: THC HNH MT S BI TP C BN TRN C++
3.1. Thc hnh mt s bi tp c bn trn C++
4. Bi 4: C BN V CU TRC V DRIVER
4.1. Tm lc lch s cc b iu khin thit b
4.2. Tng quan v cc H iu hnh (An Overview of the Operating Systems)
4.3. Cc kiu Driver
4.4. Tng quan v qun l v kim tra danh sch
5. Bi 5: THC HNH MT S BI TP C BN TRN VC++
5.1. Thc hnh mt s bi tp c bn trn VC++
6. Bi 6: CC K THUT LP TRNH C BN
6.1. Mi trng lp trnh kiu Kernel Mode
6.2. Trnh by li (Li x l)
6.3. Qun l b nh (Memory Management )
6.4. Trnh by chui (String Handling)
6.5. K thut lp trnh hn hp (Miscellaneous Programming Techniques )
7. Bi 7: THC HNH MT S BI TP TRN VC++
7.1. Thc hnh mt s bi tp c bn trn Visual C++
8. Bi 8: LP TRNH GIAO TIP QUA CNG LPT
8.1. Gii thiu cng LPT
8.2. Cu trc cng LPT
9. Bi 9: THC HNH VI CC CHNG TRNH GIAO TIP QUA CNG LPT
9.1. Thc hnh vi cc chng trnh giao tip qua cng LPT
10. Bi 10: THC HNH VI CC CHNG TRNH GIAO TIP QUA CNG
COM
10.1. Gii thiu cng COM
1/369
2/369
3/369
4/369
5/369
6/369
7/369
8/369
9/369
10/369
X l li: (error)
Khi miu t qu trnh to file thc thi t m ngun C++, ti b qua mt chi tit nh:
l li. Li l mt chuyn hay gp ca cc chng trnh my tnh. Lp trnh vin chnh
l ngi thng xuyn mc li nht. Ngay c lp trnh vin gii nht u c th mc li
ln th 1 (hoc nhiu hn) chy chng trnh. Lp trnh vin phi sa li v chy li
qu trnh to file thc thi. Sau y l mt vi loi li c bn bn thng mc phi khi
chy chng trnh:
Li bin dch (Compile Errors): N xy ra trong qu trnh bin dch. Kt qu, file object
khng c to ra. Li ny thng do li c php, c ngha l trnh bin dch khng hiu
ci g . N c th n gin nh g sai lnh chng hn, hay thiu du ;. Trnh bin
dch cn a ra nhng cnh bo (warning). Mc d bn thng khng cn phi ch
n warning, nhng bn nn gii quyt n nh l li, sa cha, sau bin dch li, y
l mt thi quen tt y ^^.
Li lin kt (Link Errors): N xy ra trong qu trnh kt ni v c th cho bit c vi th
m chng trnh lin kt n khng th tm thy. Li ny thng c gii quyt bng
cch t ng v tr cc lin kt v bt u qu trnh bin dch/kt ni ln na.
Li Run-time (Run-time errors): N xy ra khi ang chy file thc thi. Nu chng trnh
lm mt ci g khng hp l, n c th ph hy h thng. Nhng mt dng li tinh
vi, kh pht hin hn ca li run-time: logical error (li logic), c th lm chng trnh
lm nhng vic m ta khng nh trc. Nu bn tng chi game m trong nhn
vt c th bc trn khng kh (trong kch bn nhn vt khng th bc trn khng kh),
khi bn thy li logical trong hnh ng.
11/369
V d:
#include <stdio.h>
#include <conio.h>
void main()
{
printf(chao cac ban);
getch();
}
12/369
m n c th thc thi cho i tng khc. Quan im ny buc chng ta phi tp trung
vo ci nhn b ngoi ca i tng.
Chng ta gi ton b tp hp ca cc hot ng m mt client c th thi hnh cho mt
i tng, cng vi nhng cu lnh hp l m chng c th c gi l protocol. Mt
protocol biu th nhng cch thc m mt i tng c th hnh ng v phn ng, v
do vy c th cu thnh tng th b ngoi tnh v ng ca tru tng.
14/369
Vic phn chia chng trnh thnh nhng phn ring l c th lm gim phc tp.
ngn ng ny lp, i tng hnh thnh cu trc lun l ca h thng. Chng ta t
nhng tru tng ny trong modun to ra nhng kin trc vt l ca h thng.
i vi nhng vn nh, nh pht trin c th quyt nh vn khai bo tt c cc lp
v i tng trong cng mt gi. Ta thng nhm nhng lp v i tng c quan h
trong cng mt modun, v ch phi by nhng phn t m modun khc cn thy. Trong
cc h thng ln, th n c qu nhiu modun v tht l kh cho ngi s dng tm thy
nhng lp m h cn. Hn na , khi quyt nh thay i hng trm modun phi c
hiu chnh hoc bin dch li. Nh vy, modun ha i khi cng khng tt.
Modun phc v nh l nhng phn t v nhng n v khng th phn chia c ca
phn mm m c th s dng li c qua cc ng dng. Nh pht trin s chn cch
ng gi i tng thnh cc modun sao cho chng thun tin s dng li.
L tnh cht cho php mt tn c dng cho hai hoc nhiu mc ch khc nhau c
quan h v phng din k thut. Mc ch ca tnh a dng khi c p dng cho OOP
l cho php mt tn c dng ch r mt lp tc ng tng qut, mt tc ng c
th c xc nh bi loi data. V d, trong C, khng c h tr tnh a dng nn mt
tc ng gi tr tuyt i cn phi c ba hm khc nhau: abs(), labs(), v fabs(). Cc hm
ny tnh ton v ln lt tr v mt gi tr tuyt i ca s nguyn, mt s nguyn di,
mt gi tr du phy ng. Tuy nhin, trong C++ c c tnh a dng nn c hm abs().
Loi data c dng gi hm xc nh loi hm no thc s c dng. Trong C++
c th s dng mt tn hm cho nhiu mc ch khc nhau. iu ny c gi l qu ti
hm(function overloading).
Tng quan hn khi nim tnh a dng l tng mt giao din, nhiu phng php.
iu ny c ngha l c th thit k mt giao din chung cho mt nhm cc tc ng c
lin quan. Tuy nhin, tc ng c th c thi hnh ph thuc vo data. u im ca
tnh a dng l chng lm gim tnh phc tp bng cch cho php cng mt giao din
c s dng ghi r mt lp tc ng tng qut, chnh trnh bin dch s la chn
tc ng c th khi p dng cho tng trng hp. L ngi lp trnh ta khng phi thc
hin s la chn ny bng tay. Ta ch cn nh v s dng giao din chung.
Lin kt tnh v kin kt ng (Static and Dynamic Binding):
Khi nim trong typing v static typing lin kt tnh l hon ton khc nhau. Strong
typing cp ti s nht qun ca kiu. Stactic binding c ngha l kiu ca mi bin
v biu thc l c nh vo lc bin dch. Dynamic binding ngha l cc kiu ca mi
bin v biu thc khng cho bit cho ti khi chy chng trnh. Bi v Strong typing
v Dynamic binding l khi nim c lp cho nn mt ngn ng c th va Strong v
Static typing.
6. Bn cht ca i tng:
Mt i tng c trng thi, hnh vi, c tnh nhn dng; cu trc v hnh vi ca cc i
tng ging nhau c nh ngha trong mt lp chung ca chng, thut ng instance
v i tng l c th thay th ln nhau c.
Trng thi (state) : ca mt i tng bao gm tt c cc c tnh (thng l tnh) ca
i tng tr i gi tr hin ti ( thng l ng ) ca mi c tnh .
Hnh vi (behavior ) : l i tng hot ng v phn ng nh th no theo iu kin
trng thi ca n thay i v message truyn n.
Operations (hot ng) : l mt dch v m mt lp cung cp cho khch hng ca n.
Chng ta thy rng mt client thng thc thi nm loi opearation i tng. Ba loi
operation thng thng nht l :
16/369
17/369
Khi c multiple thread control, vic truyn thng tin gia cc i tng cn x l vn
multual exclusion trong h thng x l ng thi. Vn ng b ha cng phi xem
xt.
Aggregation: Aggregation c ngha l mt phn cp tng th / b phn, vi kh nng
iu khin t tng th ( cn gi l aggregate ) ti nhng b phn (c hiu l nhng
thuc tnh ca n).
8. Bn cht ca lp:
Class (lp) : l tp hp ca cc i tng c cng cu trc chung hay hnh vi chung.
Mt i tng n gin ch l mt instance ca lp.
Interface: ca mt lp cho thy bn ngoi ca i tng v do nhn mnh n vn
tru tng trong khi che du cu trc v hnh vi bn trong.
Implemention : ca mt lp l ci nhn bn trong ca n. Implemention ca mt lp
c bn bao gm tt c cc operation c nh ngha trong interface. Chng ta chia
interface ca lp thnh ba phn:
Public : l khai bo c truy xut n mi client.
Protected : l khai bo c truy xut ch chnh lp , lp con ca n, v lp friend.
Private: l khai bo c truy xut ch chnh lp v lp friend.
18/369
#include "stdafx.h"
#include "conio.h"
#include "stdio.h"
int main(int argc, char* argv[])
{
printf("chao");
getch();
return 0;
}
19/369
Bi 3: THC HNH MT S BI TP
C BN TRN C++
Thc hnh mt s bi tp c bn trn C++
Bi 1
Vit cu trc, cc kiu d liu, cc cu trciu kin, cu trc lp trong C ++
Bi 2
Vit chng trnh gii phng trnh bc 2 trn C++
20/369
Bi 4: C BN V CU TRC V
DRIVER
Tm lc lch s cc b iu khin thit b
Nhng th h PC u tin chy trn mt chip x l Intel cung cp kh nng
nh v cho 640KB ca b nh thc tgi nh vy bi v b nh l tht s
trong mu ca nhng chip nh m b x l trc tip hng vo bi nhng phng tin
ca mt a ch vt l 20 bit. Chnh b x l ngh cho ci ng kiu ca qu trnh
hot ng, ci gi l kiu thc t, ch no b x l kt hp thng tin t hai thanh
nghi 16-bit hnh thnh mt a ch b nh 20-bit cho mi ch dn b nh nhc n
. Kin trc my tnh bao gm khi nim ca nhng khe m rng m mt vng c th
nhng ngi dng bt chp vi nhng card mua ring r t bn thn my tnh. Nhng
card t chng thng xuyn n vi nhng ch th v lm sao t nhng cng tc
DIP (tr, cc jumper gia cc pin) th t to ra nhng thay i khng ng k cu
hnh Vo/ra. Bn phi gi mt s ca tt c s Vo/ra v nhng s n nh ngt cho
PC ca bn th t cho s ph hp ny. MS-DOS hp nht mt lc c s trn file
CONFIG.SYS nh h iu hnh h thng c th np vo nhng b iu khin thit
b kiu ch thc cho thit b nguyn bn v cho cc card thm vo. Chc chn, y
l nhng trnh iu khin theo hnh thc lp trnh ngn ng assembly v tin vo mt
phm vi ln hn hoc km hn trn ch th INT gi ti BIOS v ti nhng phc v h
thng bn trong bn thn MS-DOS. Nhng ngi dng kt thc bt buc hc lm sao
cu khn nhng ng dng qua cc lnh. Cc phn mm ng dng cn thit hc lm
sao lp trnh hin th video, bn phm, v con chut ngay lp tc bi v khng mt
MS-DOS no m BIOS h thng lm y nh vy.
Sau ny, IBM c gii thiu dng AT ca nhng my tnh c nhn t c s trn h vi
x l Intel 80286. B x l 286 thm mt kiu bo v ca thao tc ch nhng chng
trnh c th hng vo ln trn ti 16 MB ca b nh m rng v b nh chnh s dng
a ch on 24-bit (theo danh ngha gin tip qua mt b chn lc on mt thanh ghi
on 16-bit) v mt a ch offset 16-bit. Bn thn MS-DOS vn l mt H iu hnh
h thng ch thc, nh vy vi nh cung cp phn mm xy dng cc sn phm m
rng DOS ti cho php nhng ngi lp trnh di tr nhng ng dng kiu thc t ca
h ti kiu bo v v chp nhn li ch to tt c b nh m ang tr nn sn c trn th
trng. T MS-DOS ng yn v tr u ca my tnh, cng ngh iu khin
khng pht trin thi im ny.
S thay i bc ngot ca cng ngh PC xut hintrong tng quan ca ti, d sao i
nakhi m Intel a ra bn chip x l 80386. Dng 386 cho php nhng chng trnh
truy nhp ln trn ti 4 GB ca a ch b nh o gin tip qua cc bng trang nh, v
21/369
n cho php nhng chng trnh d dng s dng nhng s lng cho 32-bit s
hc v a ch. l mt cn gi mnh ca s hot ng trong th trng nhng cng
c phn mm nh nhng nh cung cp chng trnh bin dch v s cnh tranh gia cc
cng ty a ra bt khi lng tng trng lin tc khao kht nhng ng dng ln
hn cho tc x l v tc b nh. Nhng trnh iu khin thit b l vn cn vit ra
nhng chng trnh ch thc 16-bit trong ngn ng assembly v ci t qua tp
CONFIG.SYS, v nhng ngi dng cui vn cn cn cc card c nh cu hnh
iu khin bng tay.
K tip tin ti cc chip ca B vi x l ch yu trong vng ca s thc thi v dung
lng. Trong khi ti vit chng ny, nhng my tnh hot ng nhanh hn 1 GHz vi
nhng cng 50-GB v 512 MB (hoc hn) ca b nh l c rch v c th cung cp d
dng bng nhng phn on ln hn ca mu.
Song song vi s tin ha ca nn tng cng ngh my tnh, s tin ha khc ang xut
hin vi cng ngh h iu hnh. Hu ht mi ngi, thm ch bao gm nhng ngi
lp trnh ca phn mm h thng, thch nhng bin php trn nn ha ca nh hng
ln nhau vi cc my tnh ti nhng bin php trn nn vn bn. Microsoft mun ti
nhm H iu hnh haApple nh trng vi h Macintosh u tinnhng c
n v thng tr n vi gia nh Windows ca nhng H iu hnh. Trong s bt u,
Windows ch l mt tin ch ha cho MS-DOS kiu thc t. Trong c thi gian, mt
tp hp ca cc trnh iu khin Windows cho phn cng ph bin, k c mn hnh ,
bn phm, v chut, cho n s tn ti. Nhng b iu khin ny l nhng tp tin c th
thc hin vi mt ui m rng .DRV, v chng c vit u tin trong ngn ng
assembly.
n vi lp AT ca my tnh, Microsoft thit lp mt phin bn ch bo v ca
Windows. Microsoft mang chuyn cc trnh iu khin .DRV ch thc ch bo
v l tt nht. Phn cng khc hn nhng thit b Windows chun (mn hnh, bn phm,
v con chut) tip tc s c iu khin bng cc trnh iu khin MS-DOS ch
thc.
Kt lun li, mt khong thi gian sau cc PC vi cc b x l 386 tr nn sn
dng mi ni, Microsoft pht hnh Windows 3.0, ca ch tng cng cc thao
tc bt ly y s thun li ca cc kh nng b nh o. Thm ch nh vy, n vn
cn ng vi mi b phn mi ca nhu cu phn cng mt iu khin ch thc.
Nhng by gi n l mt vn ln. T mt s h tr a nhim ca cc ng dng MSDOS (mt nhu cu chp nhn cho ngi s dng cui ca Windows), Microsoft l
xy dng mt h iu hnh cho my o. Mi ng dng MS-DOS chy trong my o ca
chnh mnh, nh lm mi trng ha cho Windows. Nhng tt c cc ng dng
MS-DOS trc tip ang c gng ni ti phn cng bng s a ra cc cu trc IN v
OUT, b nh thit b c v ghi, v vic dng cc ngt t phn cng. Hn na, hai hoc
nhiu hn cc ng dng ang chia s thi gian x l c th ang a ra nhng ch dn
22/369
xung t ti phn cng. Chng chc chn xung t qua s s dng ca mn hnh, bn
phm, v con chut, ca qu trnh din bin.
Ti vic chp nhn cc ng dng phc tp ti vic chia s phn cng vt l, Microsoft
gii thiu khi nim ca mt b iu khin thit b o, mc ch rng ca ai ti thc
t mt thit b phn cng. Nhng b iu khin nh vy l khi qut gi l VxDs bi v
hu ht chng cho php nhng tn file ph hp vi nhng mu VxD.386, u ch
bo kiu ca thit b qun l chng. S dng khi nim ny, Windows 3.0 to s
xut hin ca trang b nhng c my o vi nhng th hin ring bit ca mt vi thit
b phn cng. Nhng t mnh nhng thit b tip tc, trong hu ht cc trng hp, ti
vic iu khin bng b iu khin MS-DOS ch thc. Mt vai tr ca VxD s iu
nh s truy cp ti phn cng bng vic chn ng u tin nhng s c gng ca cc
ng dng ti chi tit nh phn cng v kha chuyn i ngn gn B x l ti mt sp
xp ca ch thc gi cho ch 8086 o ti vic chy trnh iu khin MS-DOS.
khng t mt mt qu tinh t trn n, kha chuyn i ch chy nhng b
iu khin kiu thc t l mt s tn cng cng dng duy nht ca chng l chp nhn
n cho mt s tng tri chy hp l trong nn phn cng v h iu hnh. Windows
3.0 c mt vi hng hc tnh nng gc nguyn nhn l ci rt c trng ca cu
trc. Microsoft tr li l ti OS/2, khi n l ang pht trin s cn i ( l s
dng th k 20) vi IBM.
Microsoft c phin bn ca OS/2 tr thnh l Windows NT, phin bn dng chung u
tin ca chng l vo nhng nm 1990, khng lu sau Windows 3.1. Microsoft xy dng
Windows NT t trn nn vi nh ca vic to n mt cch lu bn v nn tng bo
m trn vic chy nhng h iu hnh. Nhng trnh iu khin cho Windows NT
s dng mt cng ngh nhn-kiu mi toanh l khng c chia s trn thc t vi
hai b cng ngh iu khin khc khi y ang c thnh hnh. Nhng trnh iu khin
Windows NT s dng gn nh ch ring ngn ng lp trnh C v vy chng c th
c bin dch li cho nhng cu trc CPU mi m khng yu cu bt k nhng s thay
i ngun no.
Vn khc xy ra dc theo khung thi gian v Windows 3.0 c mt s phn
nhnh quan trng cho chng ta hm nay. Windows 3.0 chnh thc b tch ra khi th gii
phn mm vo trong cc chng trnh User-mode v Kernel-mode. Nhng chng trnh
User-mode bao gm tt c cc chng trnh ng dng v cc tr chi mi ngi
mua cc my tnh chy, nhng chng l khng c lng tin giao du mnh (hoc
thm ch trung thc) vi phn cng hoc vi cc chng trnh khc. Nhng chng
trnh Kernel-mode k c chnh H iu hnh v tt c cc trnh iu khin thit b m
mi ngi thch bn v ti vit. Nhng chng trnh Kernel-mode l c th tin cn
c hon ton v c th chm bt k ti nguyn h thng no m chng thch. Mc d
vy Windows 3.0 tch ring cc chng trnh bng kiu ca h ca H iu hnh, khng
phin bn no ca Windows (khng ch l Window Me) tht s t s bo v b nh
23/369
24/369
Hnh 1-1 l mt tm tt cao s chc nng ca h iu hnh Windows XP, kha cnh
no ti nhn mnh nhng c trng m quan trng ti nhng ngi m vit nhng
b iu khin thit b. Mi nn tng m Windows XP chy h tr hai kiu ca s thi
hnh. Phn mm thc hin hay trong user-mode hoc trong kernel-mode. Mt chng
trnh user-mode iu mun ti, ni, c d liu no t mt thit b gi l mt giao
din lp trnh ng dng (API) nh ReadFile. Mt module h thng con nh nhng s
25/369
thi hnh KERNEL32.DLL API ny bng vic ko theo mt chc nng API bn ng nh
NtReadFile. cp ti kha cnh c thm thng tin v API bn ng.
Chng ti thng ni NtReadFile c gi l qun l Vo/ra. Thut ng qun l Vo/ra
l c th mt t lc ng bi v khng l bt k m un c th thc hin n no
vi tn . H iu hnh s giao tip vi thit b bng trnh iu khin ca ring mnh.
Nhiu th tc phc v nh NtReadFile. H vn hnh kernel-mode th t phc v
mt vi ng dng tng tc vi mt thit b trong cch no .
API gc
NtReadFile thuc API ca Windows XP. H iu hnh Windows NT bao gm mt s
h thng thc thi nhng ng ngha ca vi ci mi v nhng h iu hnh ang tn
ti. c mt h thng con OS/2, POSIX, v h thng con Win32. Nhng h thng con
c thc hin bng vic to m user-mode hng ti API gc, m chnh n c thc
hin trong kernel-mode.
Mt user-mode DLL c tn (rather redundantly, Ive always thought) NTDLL.DLL
nhng b sung API gc cho nhng i tng gi Win32. Mi mc vo trong DLL ny
l mt trnh bao bc mng xung quanh mt s gi ti mt chc nng kernel-mode maf
tht s thc hin chc nng. Vic gi s dng mt giao din cng tc h thng ph thuc
nn chuyn iu khin ngang qua ranh gii user-mode/kernel-mode. Trn nhng b
x l Intel mi hn, giao din cng tc h thng ny s dng ch dn SYSENTER. Trn
nhng b x l Intel c hn, nhng s s dng giao din cu trc INT vi vi chc nng
vit m 0 x2E. Trn nhng b x l khc, vn cn nhng c ch khc c s dng.
Mc d, bn v ti khng cn hiu nhng chi tit ca c ch vit nhng b iu khin
thit b. Tt c chng ti cn hiu l c ch cho php mt chng trnh c chy trong
user mode gi mt chng trnh con m thc hin kernel mode v nh dn dn
tr li ngi gi user-mode ca n. Khng c s chuyn mch ng cnh lung xut hin
trong thi gian x l: tt c nhng s thay i l mc c quyn ca thc hin m (cng
vi vi chi tit khc nhng lp trnh vin hp ng duy nht tng ch hoc quan tm
xung quanh).
H thng Win32 l mt trong a s nhng lp trnh vin ng dng quen thuc vi v n
thi hnh nhng chc nng mt trong nhng s kt hp ph bin vi h giao din ho
Windows.
Mt b iu khin thit b c th dn dn cn truy nhp tht s phn cng ca n
thc hin mt IRP. Trong nhng trng hp ca mt IRP_MJ_READ ti mt loi vo/
ra (PIO) c chng trnh ha ca thit b, s truy nhp c l a mu (dng) (ca)
mt thao tc c c nh hng i mt cng vo/ra hoc mt thanh ghi b nh c
ng k bng thit b. Nhng b phn iu khin, mc d h thc hin trong kernel-
26/369
27/369
Cc kiu Driver
Mt s loi ca mu cc trnh iu khin mt h thng XP Windows y . Hnh 1-4
nhng s ring bit ca chng.
28/369
Nhng trnh iu khin tp tin h thng thc thi mu tp tin h thng PC chun
(m bao gm nhng khi nim ca mt cu trc th mc phn cp vic cha
t tn nhng tp tin) trn nhng a cng a phng hay qua nhng kt ni
mng. y cng, l nhng trnh iu khin kernel-mode.
Nhng b iu khin thit b k tha l cc trnh iu khin kernel-mode m
trc tip kim sot mt thit b phn cng khng c tr gip t nhng trnh
iu khin khc. Phm tr ny thc cht bao gm nhng trnh iu khin cho
nhng phin bn trc ca Windows NT m ang chy khng c s thay
i trong Windows XP.
C mt s thit b, bn khng cn vit bt k trnh iu khin no bi v Microsoft
cung cp mt trnh iu khin chung m s lm vic vi thit b ca bn. y l mt vi
v d:
Thit b tn tr tin ln SCSI-compatible hoc ATAPI-compatible
Bt k thit b no ni ti mt cng USB m hon ton thch hp vi mt
thuyt minh ph chun, cung cp bn hnh phc vi bt k hn ch no
trong trnh iu khin Microsoft tiu chun
Cng tun t chun hay cng chut PS/2
Bn phm chun
Card iu hp video khng c gia tc hay nhng tnh nng c bit
Cng song song hay tun t chun
a mm chun
WDM Drivers
Cho a s nhng thit b m Microsoft khng trc tip s h tr, bn cn vit mt trnh
iu khin WDM. Bn s vit mt trnh iu khin chc nng nguyn khi, mt trnh
iu khin lc, hay n gin l mt trnh iu khin nh.
WDM minidrivers
Nu Microsoft vit mt trnh iu khin cho thit b, bn c gng cho thit b h
tr, bn cn phi vit mt Minidriver lm vic vi trnh iu khin lp . Minidriver
ca bn trn danh ngha trong vic ph trch ca, tr phi bn s gi nhng chng trnh
con trong trnh iu khin lp m v c bn ly li qun l ca phn cng v gi quay
tr li bn lm nhng th device-dependent khc nhau. S lng ca cng vic bn
cn lm mt minidriver thay i gh gm t mt lp ca thit b n thit b khc.
y l mt s v d ca nhng lp thit b m bn cn phi lp k hoch vit mt
minidriver:
29/369
30/369
32/369
33/369
Hai cch ca vic cung cp thng tin qun l bi nhng phng tin ca bn ghi s kin
h thng, y l b phn ca Windows NT t s bt u v m a cho nhng ngi
qun tr mt cch nhanh phm vi ca kin thc v nhng iu kin khc thng m
xut hin trong qu kh gn y. Trnh iu khin ca cc bn cn phi bo co nhng
s kin m mt ngi qun tr quan tm n v c th lm ci g . Ngi no m
lp trnh driver ca cc bn cn phi tranh lun vi vi mt qun tr h thng giu kinh
nghim quyt nh nhng bn ghi s kin no, nh nh vy trnh lm ba bn bn
ghi vi th tc v thng tin khng ni bt. Tp tin kh thi driver ca cc bn s cng c
l bao gm vn bn ca thng bo trong mt ti nguyn thng bo a ng c bit, v
n l mt tng tt c mt ngi vit c hun luyn bin son vn bn .
Cui cng, ng coi nhng trnh iu khin ca cc bn nh nhng chi tit khng quan
trng. Vic c mt driver tt vi mt s ci t phng l t nht quan trng nh v ngoi
ca sn phm. t n n gin, nu driver ca cc bn ph hy h iu hnh, nhng
nh ph bnh s cnh bo cng khai, v bt c ai khng c nhng tng quan s ni gin
ang tr li sn phm ca cc bn cho nhng ca hng. Bn khng chin thng c nhng
bt k s t hng li no t nhng ngi m c h thng ph hy, thm ch mt ln,
bi v driver ca cc bn. V th l mt quyt nh cn th ti s pht trin trnh iu
khin short-fund c th d dng c mt kch tnh, hiu ng tiu cc trn hng di
ca cc bn trong nhiu nm n. Li khuyn ny l mt cch c bit quan trng cho
nhng nh sn xut phn cng trong nhng nc ang pht trin, u nhng nh qun
l c mt xu hng tm kim mi cch kh d ct (xn, ngt) nhng chi ph. Ti
gi rng s pht trin driver l mt ch ni s ra quyt nh trn nn chi ph khng
thch hp.
Tng kt, lp k hoch d n ca cc bn vi nhng ct mc sau y trong tm tr:
S nh gi ca trnh iu khin v s chn lc ca i hi ti nng lp trnh
c t lp trnh cho phn cng hon thnh y cho cng vic trnh iu
khin bt u
Mu ban u phn cng sn sng cho s th driver
Driver v hardware/firmware hot ng cng nhau nh trc y c d nh
File ci t (INF) c kim tra trn tt c cc h iu hnh
Nhng bng iu khin v phn mm ph tr khc lm
WMI v s kin bn ghi chc nng c lm v kim tra
Nhng t th WHQL c i qua v quyt nh c lm
Chng trnh ci t ty chnh lm (khng phi quyt nh b phn ca
WHQL)
Sn sng t chy nhng a v sn phm ngh nghip!
34/369
Bi 5: THC HNH MT S BI TP
C BN TRN VC++
Thc hnh mt s bi tp c bn trn VC++
Bi 1
Cc to Project trn VC++
Bi 2
Vit c chng trbinh n gin trn VC++; cng 2 s
Bi 3
To chng trnh VC++, vit chng trnh gii phng trnh bc 2.
35/369
Bi 6: CC K THUT LP TRNH C
BN
Mi trng lp trnh kiu Kernel Mode
Hnh 3-1 minh ha mt s nhng thnh phn to ra h iu hnh XP Microsoft
Windows. Mi thnh phn hm dch v n c tn bt u vi mt tin t c bit 2- k
t, 3- k t:
Qun l vo/ra (Tin t Io) cha ng nhiu hm dch v m nhng trnh iu
khin s dng, v l iu m ti bn lun trong cun sch ny.
M un Cu trc Qu trnh (Tin t Ps ) to ra v qun l nhng lung kiu nhn. Mt
trnh iu khin WDM bnh thng c l s dng Mt lung c lp nhiu ln
ct ngn Mt thit b khng c kh nng ca vic pht sinh nhng ngt, v (cho) nhng
mc ch khc.
Qun l b nh ( Tin t Mm) iu khin nhng bng trang m nh ngha nh
x (ca) nhng a ch o ln trn b nh vt l.
Thi hnh ( Tin t Ex) cung cp qun l tt c cc dch v ng b ha. Ti s
bn ti cc vn thc hin cc ch lnh chng tip theo, bao hm nhng
dch v ng b ha.
Qun l i tng ( Tin t Ob ) cung cp kim sot tp trung qua nhiu i
tng d liu m khi Windows XP hot ng. Nhng iu khin WDM tin cy
trong qun l i tng lm cho mt tnh th li m ngn nga mt i
tng khng bin mt trong khi ngi no vn cn s dng n v chuyn
i phn i tng qua con tr ti nhng i tng i din.
Bo mt tham chiu m hnh ( Tin t Be) cho php iu khin h thng tp tin
thc hin nhng s kim tra bo mt. Mt vi iu khin khc th phn phi
vi nhng s lin quan bo mt trc thi gian mt yu cu vo/ra t n iu
khin WDM, v vy Ti ang bn lun nhng hm trong sch ny.
Thnh phn " th vin thc thi " ( Tin t Rtl) cha ng nhng chng trnh
thng dng, nh danh sch v nhng th tc qun l chui, nhng trnh iu
khin Kernel - mode c th s dng thay v ANSI- tiu chun bnh thng
nhng th tc th vin. Phn ln, thao tc nhng hm ny hin nhin thng qua
nhng tn ca n v nhng hiu bit ca bn khi s dng chng.
Windows XP thi hnh nhng ngn ng API ca Kernel - mode c gi khi s
dng nhng tn th tc m bt u vi tin t Zw. Nhng ti liu DDK dung
mt vi k hiu hn ZwXxx, Tc l l th m gn lin vi ni ng k v s
truy nhp h s. Nhng hm c bn lun trong chng ny.
36/369
37/369
38/369
Trnh by li (Li x l)
Li lun lun pht sinh trong chng trnh. Mt s ngi trong s h bt u vi chng
trnh li, hoc trong m ring ca chng ti hoc cc thnh vin trong-ch gi cc
ng dng m m ca chng ti. Mt s ngi trong s h lin quan n h thng np
hoc lm ngay trong tiu bang ca phn cng. Bt nguyn nhn, hon cnh khng bnh
thng l mt nhu cu linh hot ca chng ti phn hi t m
Trong phn ny, ti s m t ba kha cnh ca x l li: tnh trng m s, ngoi tr cu
trc x l, v kim tra li. Nhn chung, ch h tr ht nhn-thi quen bo co li
khng mong mun bng cch tr ra mt m trng thi, trong khi h bo co d kin cc
bin th bnh thng trong dng chy bng cch tr ra mt gi tr s Boolean hoc khc
hn l mt trng thi thc m
Cu trc x l ngoi l cung cp mt tiu chun nht dn sch sau khi thc s khng
mong mun cc s kin, chng hn nh dereferencing mt ngi dng khng hp lch tr, hoc trnh ng xe m cc h thng thng thng ensues sau khi nhng
s kin. Mt li kim tra ni b l tn gi cho mt tht bi thm cho l mt h thng
tt l ch cha khi.
Codes
Kernel_mode h tr thi quen (v m ca bn ,cho rng vn ) cho bit thnh cng
hay tht bi bng cch tr ra mt m trng thi ca h gi. NTSTATUS mt gi tr l
32-bit integer gm mt s subfields, nh minh ha trong hnh 3-2. Cao-bit 2 trt t biu
cc mc nghim trng ca cc iu kin c bo co-thnh cng, thng tin, cnh
bo, hoc li. Ti s gii thch s tc ng ca cc khch hng sm c
Cc thit b m cho bit thnh phn h thng ngun gc tin nhn v decouple c bn
phc v pht trin cc nhm t mi khi ni n s in thoi gn m. Trong phn
cn li trong tnh trng m 16-bit 'gi tr-cho bit chnh xc iu kin c bo co.
39/369
Bn nn lun lun kim tra tnh trng tra ra t th tc m h cung cp. Ti ang dng
kt qu nguyn tc ny thng xuyn trong mt s cc on m ti cho bn bi v bao
gm tt c cc li cn thit x l m thng xuyn che lp cc expository
ch ca on ny. Nhng bn khng m phng thc hnh ng
Nu bit-cao, trt t ca mt m trng thi l 0, bt k s bit cn li c th c thit
lp v cc m vn cn cho bit s thnh cng. Do , khng bao gi cn so snh vi
tnh trng m s 0 xem liu bn ang i ph vi s thnh cng-thay v, s dng cc
macro NT_SUCCESS:
NTSTATUS status = SomeFunction(...);
if (!NT_SUCCESS(status))
{
//handle error
}
Khng ch lm bn mun kim tra tnh trng m s m bn nhn c t thi quen
bn gi , nhng bn cng mun tr ra trng thi m s th tc bn gi. Trong chng
trc, ti x l vi hai trnh iu khin subroutines-DriverEntry v AddDevice-c
nh ngha l c hai li NTSTATUS m
Nh ti tho lun, bn mun tr v STATUS_SUCCESS nh s thnh cng t nhng
thi quen. Nu c g sai, bn thng mun tr ra mt m trng thi thch hp, m
40/369
41/369
42/369
M s mu
Cc SEHTEST mu minh ho driver c kh ca cc cu trc ngoi l trong mt trnh
iu khin WDM. Ngoi l no c th tr thnh trapped
Gary Nebbett nghin cu cc cu hi trong c trng hp ngoi l c th c
trapped vi cc cu trc ngoi tr c ch v bo co kt qu ca mnh trong mt
newsgroup ng bi nhiu nm trc y. SEHTEST cc mu hp nhng g ng c
hc. Ni tm li, cc trng hp ngoi l sau y s c khi h b bt li xy ra ti
IRQL nh hn hoc bng DISPATCH_LEVEL (lu rng mt s trong s ny l c th
cho cc b x l Intel x86):
Bt k k do ExRaiseStatus v lin quan hm li d
43/369
44/369
Hnh 3-3. Kim sot dng chy ca trong mt th-cui cng khi.
y l mt trong rt n gin Illustration:
LONG counter = 0;
__try
{
++counter;
}
__finally
{
--counter;
}
KdPrint(("%d\n", counter));
Guarded u tin trong c th v thi increments quy bin t 0 n 1. Khi kim sot "b
qua" quyn brace cui ca guarded c th, chm dt handler thi v decrements cp
quay li 0. Gi tr do s c in ra 0. y l bin th hi phc tp hn:
VOID RandomFunction(PLONG pcounter)
{
45/369
__try
{
++*pcounter;
return;
}
__finally
{
--*pcounter;
}
}
Kt qu ca hm ny, khng c thay i cc nguyn cui ca pcounter tr: bt c
khi no kim sot cc l guarded c th cho bt c l do g, bao gm mt tuyn b tr
li hoc mt goto, chm dt handler thi. y l nhng s tng dn thn trng trong c
th truy cp v thc hin mt tr li.
static LONG counter = 0;
__try
{
++counter;
BadActor();
}
__finally
{
--counter;
}
46/369
47/369
48/369
49/369
{
--counter;
}
Chng ta gi y l mt hm, BadActor, n s xut hin mt vi s sp xp ca ngoi l
kch hot mt stack hot ng. Nh mt phn ca tin trnh ngh thc hin v ngoi l
ngn xp, h iu hnh s gi m code ca chng ta khi phc li bin m ti gi tr
trc n. h thng s tip tc gii phng stack, v vy bt c cu lnh no vit sau khi
finally s khng c thc hin.
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("Exception was caught\n"));
}
KdPrint(("Program kept control after exception\n"));
ProbeForWrite kim tra mt vng d liu cho tnh hp l. v d ny, n s gy ra mt
ngoi l bi v con tr m chng ta cung cp cha c lin kt ti 4 byte. Vic x l
ngoi l tng tc iu khin. iu khin sau s thc hin cu lnh sau x l ngoi l
v tip tc chng trnh ca bn.
Trong v d trc, c bn c tr ra gi tr EXCEPTION_CONTINUE_SEARCH,
h iu hnh tip tc gii phng stack tm kim mt x l ngoi l. Khng c m
code x l ngoi l ca bn cng khng c m sau n c thc thi: Mi h thng
s b ph hu hoc s c x l ngoi l mc cao hn. Bn khng nn tr v
EXCEPTION_CONTINUE_EXECUTION trong phn nhn v bn khng c cch no
d thay i nhng nguyn nhn gy ra ngoi l cho php th li.
Ch rng bn khng th by nhng ngoi l s hc, hoc nhng trang li lin kt mt
con tr kiu nhn sai, bng vic s dng cu trc ngoi l. Bn ch cn vit m khng
pht sinh nhng ngoi l nh vy. l lm th no trnh chia cho 0.
Nh v d sau y.
ULONG numerator, denominator; // <== numbers someone gives you
ULONG quotient;
if (!denominator)
<handle error>else
quotient = numerator / denominator;
Nhng lm th no con tr c th n ti bn t phn khc ca nhn? khng phi
l hm m bn c th s dng kim tra gi tr ca mt nhn con tr. Bn cn ch
nhng quy tc di y:
52/369
Theo cch thng thng, gi tr thc m mt nhn thnh phn a cho bn.
Ti khng cho rng bn khng nn chia nh on m ca bn vi cu lnh ASSERT bn nn bi v bn c th khng hiu tt c bn trong v bn ngoi cch lm vic ca
thnh phn nhn khc nh th no. Ti cho rng bn khng cn nng trnh iu khin
ca bn vi s phng th qu mc chng li li ch khc, c kim tra k, mt phn
ca h thng tr khi bn cn lm vic xung quanh mt li.
V nhng hn ch trn bn s dng hai biu thc ny nh th no trong chng trnh
ca bn, bn s hu nh chc chn mun s dng chng trong mt hm gi mt vi
hm iu kin, ging nh:
LONG EvaluateException(NTSTATUS status, PEXCEPTION_POINTERS xp)
{
.
.
.
}
.
.
.
__except(EvaluateException(GetExceptionCode(),
GetExceptionInformation()))
a ra ngoi l
Chng trnh li l mt cch bn c th a ra ngoi l m gi cu trc x l ngoi l.
Chng trnh ng dng l quen thuc vi Win32 hm API a ra ngoi l, ci m cho
php bn to ra mt ci g ngoi l cho chnh bn. trnh iu khin WDM bn c
th gi tin trnh lng nghe trong bng 3-2. ti khng a cho bn mt v d c th
gi hm ny bi v nhng l do sau:
Ni c th, a ra ngoi l khng phi l cch tt ni cho i tng gi ca bn thng
tin m bn khm ph ra trong vic x l cc tin trnh thng thng. N tt hn nhiu
53/369
Description
ExRaiseStatus
ExRaiseAccessViolation
Raise STATUS_ACCESS_VIOLATION
ExRaiseDatatypeMisalignment
Raise
STATUS_DATATYPE_MISALIGNMENT
V d thc t
Mc d ph tn ca vic ci t ln v ph hng mt ngoi l, bn phi s dng quy tc
cu trc ngoi l trong mt trnh iu khin trong trng hp c bit.
Mt trong nhng ln bn phi thit lp mt x l ngoi l l khi bn gi
MmProbeAndLockPages tm kim trang cho mt b nh danh sch mieu t(MDL)
bn to ra:
PMDL mdl = MmCreateMdl(...);
__try
{
MmProbeAndLockPages(mdl, ...);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS status = GetExceptionCode();
IoFreeMdl(mdl);
return CompleteRequest(Irp, status, 0);
54/369
}
(CompleteRequest l mt hm gip ti s dng x l i hi hon thnh I/O.
Chng 5 gii thch tt c v yu cu I/O v hon thnh chng.)
Ln khc khi s dng mt x l ngoi l l khi bn mun truy cp b nh ngi dng
s dng mt con tr t ngun khng ng tin. Trong v d di y, cho rng bn thu
c con tr p t mt chng trnh ngi dng v chc chn n tr ti mt s nguyn:
PLONG p;
// from user-mode
__try
{
ProbeForRead(p, 4, 4);
LONG x = *p;
.
.
.
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS status = GetExceptionCode();
.
.
.
}
Bug Checks
55/369
explanation of the codes and their various parameters can be found in Knowledge Base
article Q103059, Descriptions of Bug Codes for Windows NT, ci m c sn trong
MSDN, gia nhng ch khc.
V d
V d iu khin BUGCHECK cung cp cch lm th no gi KeBugCheckEx. Ti
s dng n pht sinh hnh nh hnh 3-5.
Bn c th to debug-check cho chnh bn nu bn mun. Nhng gi tr ca Microsoft l
nhng gi tr n gin bt du t 1(APC_INDEX_MISMATCH) v (hin gi) m rng
dn 0xF6 (PCI_VERIFIER_DETECTED_VIOLATION), cng vi mt s ci khc.
to ra m kim tra ca mnh, dnh ngha mt hng s s nguyn nh nu bn trng
thi STATUS_SEVERITY_SUCCESS , nhng nhng yu cu khc ca khch hng
hoc mt m khc khng.
V d:
#define MY_BUGCHECK_CODE 0x002A0001
KeBugCheckEx(MY_BUGCHECK_CODE, 0, 0, 0, 0);
Bn s dng mt m trng thi khc 0 (42 trong v d) hoc c ca khch hng(ci m
ti vit 0 trong v d ny) v vy m bn c th thng bo chnh m ca bn t mt ngi
s dng Microsoft.
By gi ti ni cho bn cch lm th no to BSOD cho chnh bn, cho php ti ni khi
no bn lm n: khng bao gi. Hoc trong khi xy dng kim tra ca trnh iu khin
s dng trong sut bn trong qu trnh g ri. Bn v ti u khng chc chn vit
mt trnh diu khin m s pht hin mt li nghim tc n ni ly xung h thng l
cch gii quyt duy nht. N s tt hn nhiu g li( s dng g li ti s m t trong
chng 14 ) v tr ra mt m tnh trng.
Ch rng ngi dng cui c th cu hnh hnh ng ca KeBugCheckEx trong nhng
s thit lp cho my tnh ca ti. Ngi s dng c th chn khi ng mt cch t
ng hoc pht sinh BSOD. Ngi dng cui c th nh vy chn vi mc ca chi tit(
k c khng) cho mt file.
57/369
trnh. Mt phn ca cng vic trong khu chuyn i l thay i cc trang bng c
s dng bi mt x l h gii thiu n cc lung ca qu trnh bi cnh. It's thng
khng WDM , mt driver s thc hin trong cng mt bi cnh nh l si xng ca
I / O yu cu n x l.
Chng ta ni rng chng ti ang chy trong bi cnh arbitrary si, nu chng ta khng
bit chc chn s cho qu trnh m hin nay ngi s dng ch a ch bi cnh thuc.
Trong bi cnh arbitrary si, chng ti ch n gin c th khng c s dng mt a
ch m o thuc vi ngi s dng ch bi v chng ti c th khng c bt k
tng vi nhng g vt l b nh n c th im. Trong s ny xem khng chc chn,
nhn chung chng ti phi tun theo cc quy nh sau y trong mt chng trnh driver:
Khng bao gi (tt, my khi) ngi trc tip tham chiu-ch b nh
Ni cch khc, khng c mt a ch m mt ngi s dng ch -cung cp cc
ng dng v cha tr cho rng nh l mt a ch tr rng chng ti c th trc tip
dereference. Ti s tho lun trong chng sau mt vi k thut truy cp d liu m
m bt ngun ch ngi dng. Tt c chng ti cn phi bit ngay by gi, tuy
nhin, chng ti ang l (gn nh) lun lun c c bng cch s dng ht nhn-ch
a ch o bt c khi no chng ti mun truy cp vo b nh ca my tnh. Bao ln
C mt trang?
Trong mt h thng b nh o, h iu hnh t chc vt l b nh v cc vng trao i
vo tp tin nh-kch thc trang khung. Trong mt WDM trnh iu khin, bn c th
s dng t c PAGE_SIZE cho bn bit lm th no l mt trang ln. Trong mt s
my tnh Windows XP, mt trang l 4096 bytes di; trong nhng ngi khc, it's 8192
bytes di. A lin quan n vic t tn PAGE_SHIFT kch thc bng cc trang nh l
mt sc mnh ca 2. l:
PAGE_SIZE == 1 << PAGE_SHIFT
Cho s tin nghi ca bn, bn c th s dng mt vi preprocessor macros m ca bn
trong khi bn ang lm vic vi cc kch thc ca mt trang web:
ROUND_TO_PAGES trong vng mt kch thc byte n trang k tip cao hn-ranh
gii. V d, ROUND_TO_PAGES (1) l 4.096 trn mt 4-KB-trang my tnh.
BYTES_TO_PAGES xc nh bao nhiu trang c yu cu t chc mt s byte, bt
u t bt u ca mt trang. V d, BYTES_TO_PAGES (42) s l 1 trn tt c cc nn
tng, v BYTES_TO_PAGES (5000) s l 2 trn mt s nn tng v 1 v nhng ngi
khc. BYTE_OFFSET s tr v byte b p phn ca mt a ch o. l, tnh ton
ca n bt u b p trong vng mt s trang khung ca mt a ch. Ngy 4-KB-trang,
my tnh, BYTE_OFFSET (0x12345678) s c 0x678
59/369
nh s trang v nh s trang B nh
Ton b s im ca mt h thng b nh o l bn c th c c mt khng gian a
ch o l nhiu ln hn s lng b nh vt l trn my tnh. thc hin iu ny
feat, Trng i din cc B nh nhu cu trao i trang khung trong v ngoi ca vt
l b nh.
Cc th loi "phi c c dn" cng c rng ln hn nhiu hn l ch cc trang li x
l. Windows XP cho php phn cng interrupts xy ra gn bt k lc no, bao gm
mt trang li trong khi ang c phc v. Nu iu ny khng c nh vy, cc trang
li handler s khng th c hoc vit trang t mt thit b s dng mt gin on
V vy, mi phn cng gin on dch v thng phi c nonpaged trong b nh.
Cc thit k ca Windows NT, bao gm cc quyt nh ngay c thm thi quen trong
nonpaged danh mc bng cch s dng mt nguyn tc n gin: M thi hnh ti hoc
gin on trn mc yu cu (IRQL) DISPATCH_LEVEL trang c th khng gy ra
li lm.
Ti s xy dng trn nguyn tc ny trong chng k tip. Bn c th s dng
PAGED_CODE preprocessor v m (trong wdm.h) gip bn khm ph cc hnh vi
vi phm cc quy nh ny trong kim tra xy dng ca driver ca bn. V d:
NTSTATUS DispatchPower(PDEVICE_OBJECT fdo, PIRP Irp)
{
PAGED_CODE()
}
PAGED_CODE cha cc iu kin bin son. Trong khi kim tra-xy dng, mi
trng, n in mt tin nhn v to ra mt ng tht bi nu IRQL hin nay l qu cao.
Trong min ph-xy dng, mi trng, n khng lm bt c iu g. hiu l do ti
sao PAGED_CODE rt hu ch, tng tng rng DispatchPower nhu cu cho mt s
l do c nonpaged nhng b nh rng bn c misplaced n trong b nh paged
60/369
Ch :
Win32 executable file, bao gm c ht nhn-ch iu khin, ang c ni b thnh t
mt hay nhiu phn. Mt phn c th cha d liu v m hay, ni chung, c thm thuc
tnh nh l ang c c, ghi, shareable, thi hanh, v nh vy trn. Mt phn nh cng
l n v m bn c th ch khi bn xc nh kh nng trang
Khi driver ti mt hnh nh, h thng nhn phn ch c tn bt u vi Trang hay.
Eda (bt u. EDATA) vo paged pool, tr khi DisablePagingExecutive gi tr trong
HKLM \ System \ CurrentControlSet \ Control \ Session Manager \ Memory Qun l
ch cht s xy ra c thit lp (trong c trng hp khng c bng driver paging
xy ra).
). Lu rng cc tn ny l trng hp nhy cm! Trong mt trong nhng twists t
c nh hng n s phn ca chng ti tt c theo thi gian, chy mm-Ice / W trn
Windows XP yu cu bn v hiu ha ht nhn trong paging bng cch ny. iu ny
61/369
{
hPageIdleSection = MmLockPagableCodeSection((PVOID)
DispatchRead);
}
Khi bn gi MmLockPagableCodeSection, bn ch nh bt k tt c cc a ch trong
phn bn ang c gng kha. Thc s nhm mc ch thc hin cuc gi trong thi
gian ny DriverEntry c x l c c gi tr ca n tr v, ti hin th m bn
tit kim trong ton cu mt bin tn hPageIdleSection. Bn s s dng nhiu x l sau
ny, khi bn quyt nh bn khng cn mt phn trong b nh cho mt trong khi:
MmUnlockPagableImageSection(hPageIdleSection);
iu ny s m kha gi cc trang web c cha cc PAGEIDLE phn v cho php h
di chuyn ra v vo b nh theo yu cu. Nu bn sau ny khm ph rng bn cn
nhng trang li mt ln na, bn thc hin cuc gi ny:
MmLockPagableSectionByHandle(hPageIdleSection);
Sau y gi ny, cc PAGEIDLE phn s li mt ln na c nonpaged trong b nh
(nhng khng nht thit phi l cng mt vt l b nh nh trc ). Lu rng hm
ny gi l c sn cho bn ch trong Windows 2000 v Windows XP, v sau ch nu
bn bao gm ntddk.h thay v wdm.h. Trong nhng tnh hung khc, bn s phi gi
li MmLockPagableCodeSection
Bn c th lm g tng t t d liu vo cc i tng pageable phn
PVOID hPageDataSection;
#pragma data_seg("PAGE")
ULONG ulSomething;
#pragma data_seg()
hPageDataSection = MmLockPagableDataSection((PVOID)
&ulSomething);
MmUnlockPagableImageSection(hPageDataSection);
64/369
MmLockPagableSectionByHandle(hPageDataSection);
Ti pht nhanh v loose vi c php ca ti y-nhng ti liu s xut hin trong
rng ri b tch phn ca trnh iu khin ca bn. Nhng tng ng sau nhng dch
v hm qun l b nh ti ch cn c m t l bn s bc u kha mt phn c cha
mt hoc nhiu trang web v c c mt x l cho s dng trong cc cuc gi.Bottom
of Form
Sau bn c th m kha cc trang trong mt phn bng cch gi in thoi qua
MmUnlockPagableImageSection v x l tng ng. Relocking phn sau ny i hi
mt cuc gi n MmLockPagableSectionByHandle.
A nhanh chng tt hin c sn nu bn chc chn rng khng c phn ca driver ca
bn s cn phi c cho c dn trong mt thi gian. MmPageEntireDriver s nh du
tt c cc phn trong mt hnh nh nh bng driver ang c pageable. Ngc li,
MmResetDriverPaging s khi phc li cc bin-thi gian pageability thuc tnh cho
ton b trnh iu khin. gi nhng thi quen, bn ch cn a ch ca mt s on
m hoc d liu trong trnh iu khin. V d:
MmPageEntireDriver((PVOID) DriverEntry);
MmResetDriverPaging((PVOID) DriverEntry);
Bottom of Form
V d:
#define DRIVERTAG ''KNUJ''
PVOID p = ExAllocatePoolWithTag(PagedPool, 42, DRIVERTAG);
khng nn phn b b nh bng cch s dng mt trong nhng thnh cng phispecifiers. iu ny l do mt driver c th gn nh lun lun tht bi no l hot ng
theo cch
Gy ra mt h thng sp trong mt b nh thp-tnh hnh khng phi l ci g lm
nn mt driver. Hn na, ch c mt gii hn pool phi-thnh cng ca b nh tn ti
trong ton b h thng, v h iu hnh c th khng c kh nng phn b b nh cn
thit c th gi cho cc my tnh chy nu trnh iu khin ln mt s.
Nu bn HOC gi tr POOL_RAISE_IF_ALLOCATION_FAILURE (0x00000010)
vo
pool
loi
m,
cc
heap
allocator
s
tng
mt
STATUS_INSUFFICIENT_RESOURCES ngoi tr thay v tr v NULL nu khng c
b nh. Bn nn s dng mt cu trc ngoi tr khung nm bt nh mt ngoi l.
V d:
#ifndef POOL_RAISE_IF_ALLOCATION_FAILURE
#define POOL_RAISE_IF_ALLOCATION_FAILURE 16
#endif
#define PagedPoolRaiseException (POOL_TYPE) \
(PagedPool POOL_RAISE_IF_ALLOCATION_FAILURE)
#define NonPagedPoolRaiseException (POOL_TYPE) \
(NonPagedPool POOL_RAISE_IF_ALLOCATION_FAILURE)
NTSTATUS SomeFunction()
{
NTSTATUS status;
__try
{
PMYSTUFF p = (PMYSTUFF)
ExAllocatePoolWithTag(PagedPoolRaiseException,
sizeof(MYSTUFF), DRIVERTAG);
66/369
67/369
68/369
69/369
SINGLE_LIST_ENTRY SingleHead;
SingleHead.Next = NULL;
PONEWAY psElement = (PONEWAY) ExAllocatePool(PagedPool,
sizeof(ONEWAY));
PushEntryList(&SingleHead, &psElement->linkfield);
SINGLE_LIST_ENTRY psLink = PopEntryList(&SingleHead);
if (psLink)
{
psElement = CONTAINING_RECORD(psLink, ONEWAY, linkfield);
ExFreePool(psElement);
}
1. Thay v vic ko theo mt hm dch v vn hnh khi to phn u danh sch lin
kt n, ch thit lp trng k tip hng ti NULL.. Ch s thiu vng ca mt hm
dch v cho vic th nghim liu danh sch ny trng rng; ch kim tra chnh phn t
k tip PushEntryList t mt phn t ti u ca danh sch, m n l phn duy nht ca
danh sch c th trc tip tip cn
2. PushEntryList nhn mt yu t ti cc u trong danh sch, ch l mt phn ca
danh sch l c th truy cp trc tip. Thng bo m bn ch nh a ch ca nhng
thay v cc lnh vc lin kt ring ca bn ONEWAY c cu.
3. PopEntryList loi b nhng mc u tin trong danh sch v s mang li cho bn mt
tr li cc lnh vc lin kt bn trong n. Ngc li vi danh sch lin kt-gp i,
mt gi tr NULL cho thy rng trong danh sch l khng c sn phm no. Trong thc
t, khng c nc IsListEmpty s dng vi mt danh sch lin kt-singly.
Lookaside Lists
Thm ch tt nht c th s dng cc thut ton, mt ngi qun l heap ngu nhin m
chng ti kinh doanh vi kch c khi b nh s yu cu mt s him thi gian x l
coalesce lin k min ph t cc khi thi gian. Hnh 3-10 minh ho nh th no, ci g
khi tr v khi B vo heap ti mt thi gian khi khi A v C v ang min ph, cc
heap qun l c th kt hp khi A, B, v C to thnh mt khi duy ln
70/369
71/369
72/369
To put a block back onto the list, call the appropriate FreeTo function:
ExFreeToPagedLookasideList(pagedlist, p);
ExFreeToNPagedLookasideList(nonpagedlist, q);
Finally, to destroy a list, call the appropriate Delete function:
ExDeletePagedLookasidelist(pagedlist);
ExDeleteNPagedLookasideList(nonpagedlist);
Nu bn thc hin li ny, trong thi gian ti cc h thng chy qua, mt lot cc danh
sch cc lookaside iu chnh cc danh sch ca h su, n s t chn xung ti ch,
ni i tng danh sch ca bn c s dng c, c l vi kt qu xu.
73/369
74/369
Trong phn ny, ti s tho lun, trong s nhng th khc, cc gia nh ca ZwXxx
thi quen v RtlDeleteRegistryValue, m cung cp cc chc nng c bn ng k rng
suffices cho hu ht cc trnh iu khin WDM.
75/369
M ra mt registry key
Trc khi bn c th interrogate gi tr trong vic ng k, bn cn phi m cc kho
c cha chng. Bn s dng vo ZwOpenKey m mt cha kha hin ti. ZwCreateKey
bn s dng m hoc mt trng im hin ti hoc to ra mt kho mi. Hoc
chc nng cn thit bn u tin khi to mt OBJECT_ATTRIBUTES c cu vi tn
ca ch cht v (c l) cc thng tin khc. OBJECT_ATTRIBUTES cc cu trc
cng b sau y:
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
Hn l khi to mt d ca cu trc ny bng tay, n d s dng
InitializeObjectAttributes v m, m ti tin v bn hin th.
Gi, v d, rng chng ti mun m cc dch v ch cht cho cc driver ca chng
ti. The I / O Trng i din cho chng ti tn ca kho ny nh l mt tham s
DriverEntry. V vy, chng ti c th vit m nh sau:
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, RegistryPath, OBJ_KERNEL_HANDLE
OBJ_CASE_INSENSITIVE, NULL, NULL);
76/369
HANDLE hkey;
status = ZwOpenKey(&hkey, KEY_READ, &oa);
if (NT_SUCCESS(status))
{
ZwClose(hkey);
}
}
1. Chng ti ang bt u cc i tng thuc tnh c cu pathname ng k vi chng
ti bng cch cung cp cho cc I / O Trng i din v bo mt vi mt NULL
descriptor. ZwOpenKey s b qua cc an ninh descriptor anyway-bn c th xc nh
thuc tnh bo mt ch khi bn to mt cha kha cho ln u tin.
2. ZwOpenKey s m kho cho c v lu tr cc kt qu x l ca chng ti trong
hkey bin.
3. ZwClose l mt thi quen chung cho ng mt x l mt ht nhn-ch i
tng. y, chng ti s dng n ng trnh x l chng ti ng k vo cha
kha.
Cc OBJ_KERNEL_HANDLE c, hin th trong mu m trc, l rt quan trng cho
cc h thng tch hp. Nu bn ang chy trong bi cnh ca mt ngi dng si khi
bn gi ZwOpenKey, v nu bn khng cung cp ny bit, c, cc bn s c c x l
s c sn sng cho ngi s dng ch x l. N thm ch c th xy ra rng ngi
s dng ch -m s ng trnh x l mi v m ra mt i tng, li nhn c cng
mt s gi tr. All of a sudden, cc cuc gi ca bn ng k chc nng s c giao
dch vi cc sai loi x l. Nhng cch khc m registry phm
Ngoi ra vo ZwOpenKey, Windows XP cung cp hai chc nng cho cc phm m ng
k.
IoOpenDeviceRegistryKey cho php bn m mt trong nhng phm c bit ng k
lin kt vi mt i tng in thoi:
HANDLE hkey;
Status = IoOpenDeviceRegistryKey(pdo, flag, access, &hkey);
77/369
78/369
size = 0;
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation,
NULL, 0, &size);
if (status == STATUS_OBJECT_NAME_NOT_FOUND size == 0)
<handle error>;
size = min(size, PAGE_SIZE);
PKEY_VALUE_PARTIAL_INFORMATION vpip =
PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(PagedPool, size);
if (!vpip)
<handle error>;
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation,
vpip, size, &size);
if (!NT_SUCCESS(status))
<handle error>;
<do something with vpip->Data>ExFreePool(vpip);
y, chng ti thc hin hai cuc gi ZwQueryValueKey. Mc ch ca cuc gi
u tin l xc nh bao nhiu khng gian, chng ti cn phi phn b cho cc c cu
KEY_VALUE_PARTIAL_INFORMATION chng ti ang c gng ly. Th hai,
gi truy thng tin. Ti cn li kim tra cc li trong m ny fragment li v khng lm
vic trong thc t ra con ng cho chng ti mong i. c bit, ti on rng cc bc
u tin gi ZwQueryValueKey s tr li STATUS_BUFFER_TOO_SMALL (k t
khi ti qua n khng-mt chiu di m). N khng lm iu , mc d. Quan trng l
STATUS_OBJECT_NAME_NOT_FOUND m khng thnh cng, cho thy gi tr thc
s khng tn ti. V vy, ti kim tra cho rng ch c gi tr. Nu c mt s li khc
ngn cn ZwQueryValueKey t lm vic, cc cuc gi th hai s uncover n.
Ci c gi l "mt phn" thng tin trong c cu bn ly bng cch ny cha cc gi
tr ca d liu v mt m t v mt lot cc d liu dng:
79/369
80/369
81/369
82/369
ULONG MaxNameLen;
ULONG MaxClassLen;
ULONG Values;
ULONG MaxValueNameLen;
ULONG MaxValueDataLen;
WCHAR Class[1];
} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION;
y thc s l c cu ca bin chiu di t Lp [0] ch l nhng k t u tin ca tn
lp hc. It's phong tc thc hin mt cuc gi tm hiu cch thc ln, mt buffer
bn cn phi phn b v mt cuc gi th hai c c nhng d liu, nh sau:
ULONG size;
ZwQueryKey(hkey, KeyFullInformation, NULL, 0, &size);
size = min(size, PAGE_SIZE);
PKEY_FULL_INFORMATION fip = (PKEY_FULL_INFORMATION)
ExAllocatePool(PagedPool, size);
ZwQueryKey(hkey, KeyFullInformation, fip, size, &size);
By gi bn c quan tm trong subkeys ng ky ca bn, bn c th thc hin
trong vng lp sau y gi ZwEnumerateKey:
for (ULONG i = 0; i < fip->SubKeys; ++i)
{
ZwEnumerateKey(hkey, i, KeyBasicInformation, NULL, 0, &size);
size = min(size, PAGE_SIZE);
PKEY_BASIC_INFORMATION bip = (PKEY_BASIC_INFORMATION)
ExAllocatePool(PagedPool, size);
83/369
84/369
{
ZwEnumerateValueKey(hkey, i, KeyValueBasicInformation, vip,
maxlen, &size);
<do something with vip->Name>
}
ExFreePool(vip);
Cp
cho
khng
gian
ln
nht
c
th
c
cu
trc
KEY_VALUE_BASIC_INFORMATION
rng
bn
s
lun
lun
ly
MaxValueNameLen da trn cc thnh vin ca KEY_FULL_INFORMATION c cu.
Bn trong vng trn, bn s thy mun lm ci g vi tn ca gi tr, m s n vi bn
nh l mt chui Unicode tnh trong cu trc ny:
typedef struct _KEY_VALUE_BASIC_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG NameLength;
WCHAR Name[1];
} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
Mt ln na, c tn ca mt gi tr v m x l cc ph huynh l cha kha ch cn
nhng g bn cn ly li gi tr, nh c hin th trong phn trc.
Hin c cc bin th trn ZwQueryKey v trn hai Enumeration chc nng m ti
khng c tho lun. Bn c th, v d, c c y thng tin v mt subkey khi
bn gi ZwEnumerateKey. Ti ch cho bn lm th no c c nhng thng tin c
bn bao gm cc tn. Bn c th ti d liu ch c gi tr, hoc tn cng vi d liu gi
tr, t ZwEnumerateValueKey. Ti ch cho bn lm th no c c tn ca mt gi
tr.
Truy cp tp tin
It's i khi hu ch c th c v vit thng xuyn a file t bn trong mt trnh
iu khin WDM. C l bn cn phi ti v mt s tin ln ca microcode vi phn
85/369
86/369
87/369
88/369
Hnh 3-14 minh ho vic ban u thut s trang. Ti khuyn bn nn kim tra cc To
chnh Ci t (i vi M s pht trin) la chn. iu ny s cho php bn la chn
xc nh chi tit Driver Verifier tu chn m bn mun tham gia.
89/369
90/369
92/369
Hnh 3-17. iu khin la chn cho cc trang Driver Verifier. Driver Verifier tht bi
l li kim tra bng cch ny. Bn s cn phi c chy mt ht nhn hay debugger
phn tch cc bi cha, sau khi ng xe thc t isolate nguyn nhn ca tht bi.
93/369
Bi 7: THC HNH MT S BI TP
TRN VC++
Thc hnh mt s bi tp c bn trn Visual C++
Bi 1
Luyn tp VC++, hon thnh bi tp bui thc hnh trc
Bi 2
To 1 driver c bn, example.
94/369
95/369
y l cu hnh c thng nht trong cng ngh vi tnh v c cng nhn bi IEEE
(vn l mt t chc ln nht v qui nh hardware quc t). Bn c th kim tra li cc
s pin v nh du bng cch nhn r hn vo cc dy parallel port cng nh parallel
port pha sau my vi tnh ca bn.
Vi v d cho hot ng ca parallel port
96/369
97/369
98/369
int a;
ptraddr = (unsigned int far *)0x00000408;
for (a = 0; a < 3; a++)
{address = *ptraddr;
if (address == 0)
printf("No port found for LPT%d \n", a+1);
elseprintf("Address assigned to LPT%d is %Xh\n",
a+1, address);
*ptraddr++;}}
Chng trnh C ny n gin l tm n i ch 0000:0408h v d tm xem c port no
tn ti hay khng. N s d t 0000:0408h n 0000:040Dh kim tra LPT1, LPT2,
v LPT3. Bn nn nh mi base address s c 2 bytes (sizeof(unsigned int) = 2 bytes!).
Nh ti m t pha trn, Base+1, Base+2...chng qua l li gi ph thng trong cch lp
trnh. Chng hn bn kim tra nh s 10, 11, 12. Bn c th kim tra nh s 10 sau
nh s 10 +1 = 11 vn vn...
ng dng ca vic iu khin parallel port
Vic hiu hot ng v bit iu khin parallel port l ti cn thit cho cc bn i chuyn
su trong cc k ngh hardware. Hu ht cc dng c tn tin thi nay iu lin quan
n vic dng software vn hnh hardware, v d nh bn c th gi mt lnh t
my vi tnh lm cho tn la phng i, shutdown computer...iu thuc dng software
iu khin hardware. V vi trch nhim mt trnh iu khin n, bn phi thu hiu tt
c. Mt v d n gin khc trong iu khin hc nh iu khin robot, nu bn dng
software t my vi tnh kch hot mt pin no ca cng parallel v gi ti robot nh
mnh lnh, chng hn i ti pha trc, quay qua bn tri....
Cu trc o su bn trong ca Parallel port
Di y l lit k 25 chn ca parallel port vi tn gi (hardware v software) v th
t ca tng chn.
Chn tn signal (dng cho hardware)
99/369
100/369
101/369
Bi 2.
M phng bt, tt LED khi s dng VB6 iu khin.
102/369
103/369
104/369
Khi khng truyn d liu, ng truyn s trng thi mark (in p -10V). Khi bt u
truyn, DTE s a ra xung Start (space: 10V) v sau ln lt truyn t D0 n D7
v Parity, cui cng l xung Stop (mark: -10V) khi phc trng thi ng truyn.
Dng tn hiu truyn m t nh sau (truyn k t A):
Hnh4.1Tnhiutruyncakt A Cc c tnh k thut ca chun RS-232 nh sau:
Chiu di cable cc i 15m
Tc d liu cc i
20 Kbps
in p ng ra cc i 25V
in p ng ra c ti
5V n 15V
Tr khng ti
3K n 7K
in p ng vo
15V
nhy ng vo
3V
Tr khng ng vo
3K n 7K
Cc tc truyn d liu thng dng trong cng ni tip l: 1200 bps, 4800 bps,
9600 bps v 19200 bps.
? Schn:
105/369
H n h 4 .2 S c h n c ng n i t i p
B tr chn ca cng COM
Tnh
iu
H ng
tru y n
M t
Protected ground: ni t bo v
TxD
RxD
RTS
CTS
DSR
GND
DCD
20
DTR
Ground: ni t (0V)
106/369
22
RI
23
DSRD
24
TSET
DTEDCE
15
TSET
DCEDTE
17
RSET
DCEDTE
18
LL
21
RL
DCEDTE
14
STxD
16
SRxD
19
SRTS
13
SCTS
12
25
TM
10
11
Test Mode
Khng dng
107/369
Bi 2.
M phng chy ng c khi s dng VB6 iu khin.
108/369
Bi 12: VN NG B
Vn ng b ha nguyn mu (An Archetypal
Synchronization Problem )
Gi thit v sau iu bn tng dn bin ny khi bn nhn c mt yu cu v s
gim bt n khi bn sau hon thnh yu cu:
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)
{
++lActiveRequests;
... // process PNP request
--lActiveRequests;
}
Ti chc chn l bn on nhn mt my m nh n phi khng phi l mt bin
tnh: n cn phi l mt b phn ca thit b m rng ca cc bn v th mi i tng
thit b c my m duy nht ca n. R sang vi ti, v gi v rng trnh iu khin
ca cc bn lun lun ch qun l mt thit b n. lm v d y ngha hn, gi
thit cui cng mt chc nng trong trnh iu khin ca cc bn s c gi l khi
no thi gian ca n xa i tng thit b ca cc bn. Bn c l mun tr hon
thao tc cho n khi khng c nhiu yu cu l ni bt hn, v th bn c l chn mt
s th ca my m:
NTSTATUS HandleRemoveDevice(PDEVICE_OBJECT fdo, PIRP Irp)
{
if (lActiveRequests)
<wait for all requests to complete>
IoDeleteDevice(fdo);
}
109/369
110/369
111/369
; --lActiveRequests;
dec lActiveRequests
Trn mt Intel x86, nhng ch dn INC v DEC khng th c ngt, nh vy s
cha bao gi l mt trng hp trong mt lung c th c chn trc trong im
gia ca vic cp nht my m. Trong khi n ng, mc d, m ny cn l khng chc
chn trong mt mi trng b a x l bi v INC v DEC c thc hin trong vi
bc vi m. Kh d ca n cho 2 CPU khc nhau ang thc hin vi m ca h ch yu
t ra khi bc sao cho mt trong s h kt thc ln trn cp nht mt gi tr c. Vn
Multi-CPU c th cng c trnh trong kin trc x86 bng cch s dng mt tin t
LOCK:
; ++lActiveRequests;
lock inc lActiveRequests
; --lActiveRequests;
lock dec lActiveRequests
Ch dn LOCK thm vo u nhng s kha ngoi tt c CPU khc trong khi vi m cho
ch dn hin thi thc hin, do bo m s ton vn d liu.
Mt cch ng tic, khng phi tt c vn ng b ha c mt gii php d dng nh
vy. im ca v d ny l khng c cch gii quyt nh th no gii quyt mt vn
n gin trn mt trong nhng nn tng ni Windows XP chy nhng phn no
minh ha hai ngun ca kh khn: quyn u tin mua ca mt lung bi k khc trong
im gia ca mt s thay i trng thi v s thc hin ng thi ca nhng thao tc
state-change tng phn. Chng ti c th trnh kh khn bng vic thn trng s dng
nhng nguyn thy ng b ha, nhng i tng loi tr nh ln nhau nh vy,
ngn chn nhng lung khc trong khi d liu dng chung nhng truy nhp lung ca
chng ta. i khi khi s kha lung l khng cho php, chng ti c th trnh quyn
u tin bng cch s dng s quyn u tin IRQL, v chng ti c th ngn nga s
thc hin ng thi bng vic thn trng s dng nhng s kha xuay vng.
112/369
chy khi quyt nh chy lung no k tip. (Thu pht lung chy SYNCH_LEVEL,
nu bn quan tm. y l cng nh DISPATCH_LEVEL trn mt my b x l n,
nu bn tht s quan tm.)
Gia DISPATCH_LEVEL v PROFILE_LEVEL l phng cho nhng mc ngt phn
cng khc nhau. Ni chung, mi thit b m pht sinh nhng ngt c mt IRQL m nh
ngha th t u tin ngt vis- as vis ca n i din nhng thit b khc. Mt driver
WDM khm ph IRQL ch) ngt ca n khi n nhn c mt yu cu IRP_MJ_PNP
vi m IRP_MN_START_DEVICE chc nng ph. Mc ngt ca thit b l mt trong
s nhiu tit mc ca thng tin cu hnh c i qua nh mt tham s ti yu cu ny.
Chng ti thng tham chiu ti mc ny nh thit b IRQL, hay DIRQL cho ngn.
DIRQL khng l mt mc yu cu n. Kh hn, n l IRQL cho ngt c lin h vi
thit b no di tho lun lc .
Tng kt, nhng driver c quan tm vi ba yu cu ngt nhng mc bnh thng:
PASSIVE_LEVEL, ti nhiu s lin lc no m nhng th tc v mt vi th
tc c bit thc hin
DISPATCH_LEVEL, ti StartIo v DPC no m nhng th tc thc hin
DIRQL, ti mt ngt dch v th tc thc hin
IRQL trong Thao tc
minh ha s quan trng ca IRQL, tham chiu ti Hnh 4-2, m minh ha mt trnh
t thi gian hp l ca nhng s kin trn mt CPU n. Ti s bt u ca chui,
CPU thc hin PASSIVE_LEVEL. thi gian t1, mt ngt n th tc dch v thc
hin IRQL-1, mt trong nhng mc gia DISPATCH_LEVEL v PROFILE_LEVEL.
Ri, thi gian t2, ngt khc n th tc dch v thc hin IRQL-2, m l t hn
IRQL-1. V quy tc c bn lun, CPU tip tc dch v ngt u tin. Khi u tin
ngt th tc dch v hon thnh thi gian t3, n c l i hi mt DPC. Nhng th
tc DPC thc hin DISPATCH_LEVEL. Vy th, quyn u tin cao nht ang xem
xt hot ng l th tc dch v cho ngt th 2, m bi vy thc hin tip theo. Khi n
kt thc t4, gi nh khng c g khc xut hin trong khi ch i, DPC s chy
DISPATCH_LEVEL. Khi nhng kt thc thng l DPC t5, IRQL c th b li
PASSIVE_LEVEL.
114/369
115/369
Ti liu DDK r rng pht biu nhng s hn ch IRQL trn nhng th tc h tr. Chng
hn, mc vo cho KeWaitForSingleObject ch bo hai s hn ch:
i trng gi phi c chy ti hoc di DISPATCH_LEVEL.
Nu gi nonzero mt thi gian ch l khong thi gian xc nh trong cuc gi,
i tng gi phi c chy chnh xc di DISPATCH_LEVEL.
Kim sot hon ton IRQL(Implicitly Controlling IRQL)
Hu ht thi gian, h thng gi nhng th tc trong trnh iu khin ca cc bn ti
IRQL ng cho nhng hot ng bn gi nh thc hin. Mc d ti khng bn lun
chi tit nhiu nhng th tc ny, ti mun a cho bn mt v d ca iu m ti thy
c ngha. Bt gp u tin ca cc bn vi mt yu cu vo/ra mi xut hin khi qun
l vo/ra gi l mt trong s nhng th tc lin lc ca cc bn x l mt IRP. S
gi thng thng xut hin ti PASSIVE_LEVEL bi v bn c l cn n vic ngn
chn lung gi hng ti v bn c l cn gi l bt k th tc h tr no. Bn c
th khng ngn chn mt lung mt IRQL bc cao, tt nhin, v PASSIVE_LEVEL
l mc m c nhng s hn ch t nht trn nhng th tc h tr bn c th gi.
Mc d n l kh d cho bn r rng kim sot IRQL (v ti s gii thch nh th no
trong mc tip theo), him khi c bt c l do g lm nh th, v trong th gia cc
nhu cu ca bn v mc m cc h thng cc cuc gi bn. Vy th, bn khng cn phi
nhn c treo ln trn IRQL m bn ang thi hnh ti thi im t khong thi gian rt
ngn : iu gn nh chc chn mc chnh xc cho cng vic bn ang v phi
lm ngay sau .
Kim sot r rng IRQL (Explicitly Controlling IRQL )
Khi cn thit, bn c th tng v sau ny h thp xung IRQL trn b x l hin thi
bng vic gi l KeRaiseIrql v KeLowerIrql. Chng hn, t vic bn trong mt th tc
chy PASSIVE_LEVEL:
KIRQL oldirql;
KeRaiseIrql(DISPATCH_LEVEL, &oldirql);
116/369
KeLowerIrql(oldirql);
1. KIRQL l tn typedef cho mt s nguyn m gi mt gi tr IRQL. Chng ti
s cn mt bin gi IRQL hin thi, v th chng ti khai bo n cch ny.
2. iu ny th hin khng nh mt iu kin cn thit gi KeRaiseIrql: IRQL
mi phi ln hn hoc bng mc hin ti. Nu quan h l khng ng,
KeRaiseIrql s bugcheck (iu , bo co mt li thng qua mt mn hnh
mu xanh ca s cht).
3. KeRaiseIrql nng IRQL hin thi ti mc c ch r bi i s u tin. N
cng ct gi IRQL hin thi ti v tr c tr vo bi i s th hai. Trong v
d ny, chng ti l nng IRQL ti DISPATCH_LEVEL v ct gi mc hin
thi oldirql.
4. Sau khi thc hin d m no chng ti c mun thc hin ti IRQL cao,
chng ti h thp xung mc yu cu quay tr li gi tr trc y ca n bng
vic gi l KeLowerIrql v ch r gi tr oldirql trc c tr li bi
KeRaiseIrql.
Sau khi nng IRQL, bn cn phi dn dn khi phc n ti gi tr ban u. Cch khc,
nhng s gi thit khc nhau lm bi m bn gi sau hoc bng cch gi l m m
bn c th bt ra sau ny c khng chnh xc. Ti liu DDK ni rng bn phi
lun lun gi cho KeLowerIrqlwith cng gi tr nh m tr li bi vic gi ngay lp
tc KeRaiseIrql, tr phi thng tin ny khng tht s chnh xc. Quy tc duy nht m
KeLowerIrql tht s p dng l IRQL mi phi l t hn hoc bng vi mt IRQL hin
hnh. Bn c th h thp xung IRQL trong nhng bc nu bn mun.
117/369
Khi no CPU-A phin bn kha ti thi gian t3, CPU-B tm thy kha t do v nhng
quyn i n. CPU-B gii phng s truy nhp ti ti nguyn. Cui cng, thi gian
t4, CPU-B kt thc s truy nhp ca n v gii phng kha CPU-B.
Vic thu nhn mt kha xoay vng nng IRQL ti DISPATCH_LEVEL t ng. Vy
th, m m thu nhn mt kha phi c nh s trang b nh v khng phi ngn chn
lung m trong n chy. (C mt ngoi l trong Windows XP v nhng h thng sau.
KeAcquireInterruptSpinLock nng IRQL ti DIRQL cho mt ngt v i hi kha xoay
vng lin quan n ngt.)
Nh mt h qu hin nhin thc t trc y, bn c th i hi mt kha xoay vng ch
khi bn ang chy ti hoc di DISPATCH_LEVEL. Ni ti, kernel th c th thu
nhn nhng s kha quay trn mt IRQL cao hn DISPATCH_LEVEL, nhng bn
v ti khng c kh nng hon thnh chin cng .
Thc t khc v nhng kha xoay vng l rt t cng c ch xut hin trn mt CPU iu
i mt kha xoay vng. S xoay vng xy ra DISPATCH_LEVEL vi nhng
ngt c cho php, v vy mt CPU l vic i mt kha xoay vng c th dch
v nhng ngt phn cng. Nhng trnh lm hi s thc hin, bn cn ti gin s
lng ca cng vic bn trong khi gi mt quay trn kha CPU khc no thch hp
mun.
Nhn tin, hai CPUs c th ng thi gi hai kha quay trn khc nhau. S sp t ny
c ngha: bn lin tng mt s kha quay trn vi mt ti nguyn dng chung nht
nh, hay tp hp no ca nhng ti nguyn dng chung. l khng c lp lun
a ln x l lin quan n nhng ti nguyn khc nhau bo v bi nhng kha quay
trn khc nhau.
Lm vic vi nhng s kha Quay trn
s dng mt s kha quay trn r rng, nh phn lu tr cho mt i tng
KSPIN_LOCK trong nh s trang k c. Ri gi l KeInitializeSpinLock khi to
i tng. Mun hn, trong lc vic chy ti hoc di DISPATCH_LEVEL, thu
nhn kha, thc hin cng vic m cn c bo v t s giao thoa, v sau gii phng
kha. Chng hn, gi thit m rng thit b ca cc bn cha ng mt QLock c tn
kha quay trn m bn s dng bo v s truy nhp ti mt hng i IRP c bit
bn c thit lp. Bn s khi to s kha ny trong chc nng AddDevice ca cc bn:
typedef struct _DEVICE_EXTENSION {
KSPIN_LOCK QLock;
119/369
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
{
}
Ni khc trong trnh iu khin ca cc bn, li ni trong chc nng lin lc cho kiu
IRP no , bn c th i hi ( v nhanh l phin bn) s kha xung quanh s thao tc
hng i no m bn cn thc hin. Ch rng chc nng phi trong nh s trang
k c v n thc hin trong mt thi gian ti mt IRQL cao.
NTSTATUS DispatchSomething(...)
{
KIRQL oldirql;
PDEVICE_EXTENSION pdx = ...;
KeAcquireSpinLock(&pdx->QLock, &oldirql);
KeReleaseSpinLock(&pdx->QLock, oldirql);
}
120/369
1. Khi KeAcquireSpinLock thu nhn s kha quay trn, n cng nng IRQL ti
DISPATCH_LEVEL v quay tr li mc hin hnh trong bin ti nhng im
i s th hai.
2. Khi KeReleaseSpinLock gii phng s kha quay trn, n cng h thp xung
IRQL quay tr li gi tr c ch r trong i s th hai.
Nu bn bit bn thc hin DISPATCH_LEVEL, bn c th ct gi mt t thi gian
bng vic gi l hai th tc c bit. K thut ny l thch hp, chng hn, trong DPC,
StartIo, v nhng th tc trnh iu khin khc thc hin DISPATCH_LEVEL:
KeAcquireSpinLockAtDpcLevel(&pdx->QLock);
KeReleaseSpinLockFromDpcLevel(&pdx->QLock);
121/369
Kiu d liu
M t
Event
KEVENT
Semaphore
Mutex
KMUTEX
Timer
KTIMER
Thread
KTHREAD
122/369
123/369
124/369
M t
KeClearEvent
KeInitializeEvent
KeReadStateEvent
KeResetEvent
KeSetEvent
CH :
Trong dy ny ca nhng mc trn nhng nguyn thy ng b ha, ti lp li
nhng s hn ch IRQL m ti liu DDK m t. Trong phin bn hin thi ca
Microsoft Windows XP, DDK i khi hn ch hn h iu hnh tht s. Chng hn,
KeClearEvent c th c gi l ti bt k IRQL no, khng phi ch ti hoc di
DISPATCH_LEVEL. KeInitializeEvent c th c gi bt k IRQL no, khng phi
ch PASSIVE_LEVEL. Tuy nhin, bn cn phi lu tm ti nhng s pht biu trong
DDK nh tng ng ti vic ni m Microsoft c l mt ngy no p t ly
s hn ch ti liu, no phi khng c nhng c gng bo co trng thi tht s ca
nhng vn .
Bn c th gi KeSetEvent t mt s kin trng thi bo hiu:
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
LONG wassignaled = KeSetEvent(event, boost, wait);
126/369
127/369
KEVENT lock;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
Initialize it as a synchronization event in the signaled state:
KeInitializeEvent(&pdx->lock, SynchronizationEvent, TRUE);
Vo tit din ti hn lightweight ca cc bn bng vic i trn s kin. li bi s
thit t s kin.
KeWaitForSingleObject(&pdx->lock, Executive, KernelMode,
FALSE, NULL);
128/369
kernel cung cp ba chc nng dch v kim sot trng thi ca mt i tng
n hiu. (Xem bng 4-3.) Bn khi to mt n hiu bng vic gi chc nng
PASSIVE_LEVEL sau y:
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
KeInitializeSemaphore(semaphore, count, limit);
Trong s gi ny, n hiu tr vo mt i tng KSEMAPHORE nh s trang k c.
Bin m l gi tr ban u ca my m, v gii hn ca tr s cc i m my m s
c cho php m nhim, m phi ln nh s m ban u.
Bng 4-3. Nhng chc nng dch v cho s s
dng vi nhng i tng nh tn hiu Kernel
Service Function
M t
KeInitializeSemaphore
KeReadStateSemaphore
KeReleaseSemaphore
129/369
130/369
M t
KeCancelTimer
Hy b mt thit b bm gi tch cc
KeInitializeTimer
KeInitializeTimerEx
KeReadStateTimer
KeSetTimer
KeSetTimerEx
C vi kch bn cch dng khc nhau cho nhng thit b bm gi, ti m t trong trong
vi mc tip theo:
Thit b bm gi c dng nh mt s kin t bo hiu
Thit b bm gi vi mt DPC thng l s c gi l khi mt thit b bm
gi ht hn
Thit b bm gi tun hon thng gi trn mt DPC thng l v trn mt ln
na
Nhng thit b bm gi thng bo c dng nh nhng s kin(Notification
Timers Used like Events):
Trong kch bn ny, chng ti s to ra mt i tng thit b bm gi thng bo v ch
i cho n khi n ht hn. u tin cp pht mt i tng KTIMER trong vic nh
s trang k c. Ri, chy ti hoc di DISPATCH_LEVEL, khi to i tng thit
b bm gi, nh c cho thy y:
PKTIMER timer;
LARGE_INTEGER duetime;
BOOLEAN wascounting = KeSetTimerEx(timer, duetime, 0, NULL);
Ti s gii thch xa hn na trong chng ny mc ch ca nhng tham s thm trong
nhng phin bn m rng ny ca cng tc vn hnh.
Mt ln thit b bm gi l s m xung, n l s yn tnh c xem xt not-signaled
cho n khi thi gian n hn xc nh n. Ti im , i tng tr nn c bo
hiu, v tt c cc lung ch i u c gii phng. Nhng bo m h thng duy nht
s ht hn ca thit b bm gi s c ch khng c sm hn thi gian n hn bn
ch nh. Phi chng bn ch r mt thi gian n hn vi mt l tinh luyn chnh xc
so vi ht ca thit b bm gi h thng ( Bn khng c th iu khin), timeout s
c ch sau chc lt chnh xc bn ch r. Bn c th gi KeQueryTimeIncrement
xc nh ht ca ng h h thng.
Nhng thit b bm gi Thng bo c s dng vi mt DPC (Notification Timers
Used with a DPC):
Trong kch bn ny, chng ti mun s ht hn ca thit b bm gi thc y mt DPC.
Bn chn phng php ny ca thao tc nu bn mun c chc chn rng bn c th
gip timeout khng vn mc u tin g c c lung ca cc bn. (T bn c th
ch i di DISPATCH_LEVEL, vic chim li iu khin ca CPU sau thit b bm
gi ht hn ty thuc vo nhng tnh bt bnh thng ca s lp lch lung. Tuy nhin,
DPC thc hin ti IRQL cao v do c hiu qu chn trc tt c cc lung.)
Chng ti khi to i tng thit b bm gi trong cng cch. Chng ti cng khi
to mt i tng KDPC m ci chng ti cp pht nh s trang k c. Chng hn:
PKDPC dpc; // <== points to KDPC you've allocated
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
KeInitializeTimer(timer);
KeInitializeDpc(dpc, DpcRoutine, context);
Bn c th khi to i tng thit b bm gi bng cch s dng hoc
KeInitializeTimer hoc KeInitializeTimerEx , n khi bn vui lng. DpcRoutine l a
ch ca mt s gi th tc c hon li thng l, iu ny bt buc nh s trang k
c. Tham s vn cnh l mt gi tr 32-bit ty ( kiu nh mt PVOID ) m s c i
qua nh mt i s ti th tc DPC. i s dpc l mt con tr ti mt i tng KDPC
m cho ci bn cung cp c nh s trang lu tr. (N c l trong m rng thit
b ca cc bn, chng hn.)
133/369
134/369
135/369
KeInitializeTimerEx(&timer, SynchronizationTimer);
PVOID pollevents[] = {
(PVOID) &pdx->evKill,
(PVOID) &timer,
};
C_ASSERT(arraysize(pollevents) <= THREAD_WAIT_OBJECTS);
136/369
status = KeWaitForMultipleObjects(arraysize(pollevents),
pollevents, WaitAny, Executive, KernelMode, FALSE,
NULL, NULL);
if (status == STATUS_WAIT_0)
break;
137/369
139/369
M t
ExAcquireFastMutex
ExAcquireFastMutexUnsafe
ExInitializeFastMutex
ExReleaseFastMutex
ExReleaseFastMutexUnsafe
ExTryToAcquireFastMutex
hn thu nhn v gii phng nu thc t khng c s tranh chp cho n. Trn
cnh tr, mt lung m thu nhn mt mutex nhanh s khng c kh nng nhn c
nhng kiu nht nh ca s gi th tc khng ng b, ph thuc vo nhng chc nng
chnh xc m bn gi, v s rng buc lm sao bn gi IRPs cho nhng trnh iu khin
khc.
Bng 4-7. So snh Kernel v nhng i
tng Mutex nhanh
Kernel Mutex
Fast Mutex
ExAcquireFastMutex(FastMutex);
or
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
ExAcquireFastMutexUnsafe(FastMutex);
Nhng chc nng u tin ny i mutex tr nn sn c, gn quyn s hu ti lung
gi, v sau nng b x l IRQL hin thi ti APC_LEVEL. Vic nng IRQL c
hiu ng ca s kt khi ca tt c APCs. Nhng chc nng th hai ny khng thay i
IRQL.
S b tc kh d khc c th xut hin vi mt trnh iu khin trong ng dn
trang-trong t khc, mt trnh iu khin m c gi gip qun l k c x
l mt li trang. Gi thit bn n gin gi KeEnterCriticalRegion v sau
ExAcquireFastMutexUnsafe. By gi gi thit h thng th thc hin mt kernelmode APC c bit trong cng lung, m kh d v KeEnterCriticalRegion khng chn
trc nhn APCs c bit. APC thng l c l nh s trang li, m c l
dn dt ti bn l reentered v b tc vo mt giy th i hi cng mutex. Bn
trnh hon cnh ny bng vic nng IRQL ti APC_LEVEL trc khi thu nhn mutex
trong ch u tin hay, n gin hn, bng cch s dng KeAcquireFastMutex thay v
KeAcquireFastMutexUnsafe. Cng vn c th nu bn s dng mt KMUTEX bnh
thng hay mt s kin ng b ha, tt nhin.
Nu bn khng mun i nu mutex khng ngay lp tc sn c, s s dng " s th
thu nhn " vn hnh:
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
BOOLEAN acquired = ExTryToAcquireFastMutex(FastMutex);
Nu gi tr tr li l TRUE, bn by gi s hu mutex. Nu n l FALSE, mt ngi
khc s hu mutex v cn tr bn thu nhn n. gii phng iu khin ca mt
mutex nhanh v cho php lung khc no i hi n, gi cho phin bn chc nng
tng ng i vi cch m bn thu nhn nhanh mutex:
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
ExReleaseFastMutex(FastMutex);
or
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
142/369
ExReleaseFastMutexUnsafe(FastMutex);
Mt mutex nhanh nhanh bi v s thu nhn v nhng bc phin bn c ti u ha
cho trng hp thng thng trong khng c tranh dnh no cho mutex. Bc ph
bnh trong vic thu nhn mutex ti mt cch nguyn t s gim bt v kim tra nhng
my m s nguyn m ch bo bao nhiu lung hay s hu hay ang i mutex. Nu
s th ch bo khng c lung khc no S hu mutex, khng c cng vic b sung
c yu cu. Nu s th ch bo lung khc m s hu mutex, Nhng khi lung hin
thi trn mt s kin ng b ha l i tng b phn ca FAST_MUTEX. Gii
phng nhng th tp mutex mt cch nguyn t l tng v kim tra my m. Nu s
th ch bo rng khng c lung hin thi ang i, khng c cng vic b sung c
yu cu. Nu lung khc ang i, tuy nhin, ch nhn gi l KeSetEvent gii phng
mt trong nhng ch i.
Interlocked Arithmetic
Bn c th gi cho vi chc nng cng tc trong mt trnh iu khin WDM thc
hin s hc trong mt cch l lung- an ton v b a x l- an ton. (Xem Bng
4-8.) Nhng th tc ny ti hai hng v. Kiu u tin ca th tc c mt tn bt u
vi Interlocked v thc hin mt thao tc nguyn t trong mt cch nh vy m khng
c lung khc no hay CPU c th can thip. Hng v khc cho php mt tn bt u
vi ExInterlocked v s dng mt s kha quay trn.
Bng 4-8. Nhng chc nng dch v cho
kha lng s hc
Chc nng dch v
M t
InterlockedCompareExchange
InterlockedDecrement
Tr 1 t mt s nguyn
InterlockedExchange
Trao i hai gi tr
InterlockedExchangeAdd
InterlockedIncrement
Thm 1 vo mt s nguyn
InterlockedOr
InterlockedAnd
InterlockedXor
ExInterlockedAddLargeInteger
143/369
ExInterlockedAddLargeStatistic
Thm gi tr vo ULONG
ExInterlockedAddUlong
ExInterlockedCompareExchange64
146/369
147/369
Initialization
Bn c th khi to nhng danh sch ny nh c cho thy y:
148/369
LIST_ENTRY DoubleHead;
SINGLE_LIST_ENTRY SingleHead;
SLIST_HEADER SListHead;
InitializeListHead(&DoubleHead);
SingleHead.Next = NULL;
ExInitializeSListHead(&SListHead);
ng qun rng bn cng phi cp pht v khi to mt s kha quay trn cho mi danh
sch. Hn na, lu gi cho nhng danh sch u v tt c cc tit mc bn t vo trong
nhng danh sch phi n t vic nh s trang k c bi v nhng th tc h tr thc
hin nhng s truy nhp ca chng ti IRQL cao. Ch rng s quay trn khng c
dng trong vic khi to ca danh sch u v n khng lm bt k ngha no cho
php tranh dnh cho s truy nhp danh sch trc khi danh sch c khi to.
Inserting Items
Bn c th chn nhng tit mc ti u v ui ca gp hai mt bn k lin kt v ti
ci u ca mt n c - bn k lin kt hay mt S-List:
PLIST_ENTRY pdElement, pdPrevHead, pdPrevTail;
PSINGLE_LIST_ENTRY psElement, psPrevHead;
PKSPIN_LOCK spinlock;
pdPrevHead = ExInterlockedInsertHeadList(&DoubleHead,
pdElement, spinlock);
pdPrevTail = ExInterlockedInsertTailList(&DoubleHead,
pdElement, spinlock);
psPrevHead = ExInterlockedPushEntryList(&SingleHead,
psElement, spinlock);
psPrevHead = ExInterlockedPushEntrySList(&SListHead,
149/369
psElement, spinlock);
Nhng gi tr tr li l nhng a ch ca nhng phn t trc ti ci u (hay ci
ui) ca danh sch trong cu hi. Ghi nh nhng a ch phn t m bn s dng vi
nhng chc nng ny l nhng a ch ca nhng cu trc mc vo danh sch m thng
thng nhng trong nhng cu trc ln hn ca cch thc no , v bn s cn s dng
CONTAINING_RECORD v m khi phc a ch ca cu trc ln cn.
Removing Items
Bn c th loi b nhng tit mc t ci u ca bt k danh sch no:
pdElement = ExInterlockedRemoveHeadList(&DoubleHead, spinlock);
psElement = ExInterlockedPopEntryList(&SingleHead, spinlock);
psElement = ExInterlockedPopEntrySList(&SListHead, spinlock);
Nhng gi tr tr li l NULL nu nhng danh sch tng ng trng rng. Chc chn
kim tra gi tr tr li cho NULL trc khi p dng CONTAINING_RECORD v m
phc hi mt con tr cha cu trc.
IRQL Restrictions
Bn c th gi l S - List ch vn hnh trong khi chy ti hoc di
DISPATCH_LEVEL. Nhng chc nng ExInterlockedXxx cho truy nhp gp hai c lin kt hay n c- Nhng bn k lin kt c th c gh thm bt k IRQL
no di nh tt c cc s tham kho ti danh sch s dng mt s gi ExInterlockedXxx.
L do khng cho nhng s hn ch IRQL no l nhng s thi hnh ca nhng chc nng
ny v hiu ha nhng ngt, m tng ng nng IRQL ti mc kh d cao nht.
Ch mt ln ngt l lm mt kh nng hot ng, nhng chc nng ny ri thu nhn s
kha quay trn bn c ch r. Khng t m khc no c th kim c iu khin trn
cng CPU, v k t khi khng c m no trn CPU khc c th thu nhn s kha quay
trn, nhng danh sch ca cc bn c bo v.
N hon ho OK cho bn s dng ExInterlockedXxx gi ti s truy nhp mt n
c - lin kt hay gp hai - bn k lin kt ( nhng khng phi mt S -List) trong mt
s phn ca m ca cc bn v s dng khng kha lng vn hnh (InsertHeadList
v vn vn) trong nhng phn khc ca m ca cc bn nu bn i theo sau mt quy tc
n gin. Trc khi s dng mt nguyn thy khng kha lng, thu nhn cng s kha
quay trn m kha vo nhau ca cc bn gi l s s dng. Hn na, hn ch s truy
nhp danh sch ti m chy ti hoc di DISPATCH_LEVEL. Chng hn:
150/369
KeReleaseSpinLock(spinlock, oldirql);
}
// Access list using interlocked calls:
VOID Function2()
{
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
ExInterlockedInsertTailList(..., spinlock);
}
Chc nng u tin phi c chy ti hoc di DISPATCH_LEVEL v l mt
yu cu ca gi hng ti KeAcquireSpinLock. L do cho s hn ch IRQL trn nhng
s gi kha lng vo giy vn hnh nh sau: Suppose Function1 thu nhn s kha quay
trn trong s chun b thc hin mt s s truy nhp danh sch Vic thu nhn s
kha quay trn nng IRQL ti DISPATCH_LEVEL. By gi gi thit mt ngt xut
hin trn cng CPU mt bc cao IRQL v nhng s iu chnh tng ch Function2
s dng mt trong nhng th tc ExInterlockedXxx. Nhn by gi s th thu nhn
cng s kha quay trn , v CPU s nh tr hon ton. Vn ny xut hin t vic cho
php m chy ti hai IRQLs khc nhau s dng cng s kha quay trn: Function1
151/369
152/369
Bi 2
To thit b cng LPT o - xut hin trong Device Manager.
153/369
Bi 14: GI D LIU VO RA
Cc cu trc d liu (Data Structures )
Two data structures are crucial to the handling of I/O requests: the I/O request packet
itself and the IO_STACK_LOCATION structure. Ill describe both structures in this
section.
Structure of an IRP
Figure 5-1 illustrates the IRP data structure, with opaque fields shaded in the usual
convention of this book. A brief description of the important fields follows.
154/369
155/369
156/369
157/369
IRP_MJ_READ IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IoBuildSynchronousFsdRequest IRP_MJ_SHUTDOWN IRP_MJ_PNP
IRP_MJ_POWER (but only for
IRP_MN_POWER_SEQUENCE)
IoBuildDeviceIoControlRequest
IRP_MJ_DEVICE_CONTROL
IRP_MJ_INTERNAL_DEVICE_CONTROL
158/369
creating thread, and the I/O Manager doesnt schedule an APC and doesnt clean up
when the IRP completes. Consequently:
When a thread terminates, the I/O Manager doesnt try to cancel any
asynchronous IRPs that you happen to have created in that thread.
Its OK to create asynchronous IRPs in an arbitrary or nonarbitrary thread.
Because the I/O Manager doesnt do any cleanup when the IRP completes, you
must provide a completion routine that will release buffers and call IoFreeIrp to
release the memory used by the IRP.
Because the I/O Manager doesnt automatically cancel asynchronous IRPs, you
might have to provide code to do that when you no longer want the operation to
occur.
Because you dont wait for an asynchronous IRP to complete, you can create
and send one at IRQL <= DISPATCH_LEVEL (assuming, that is, that the
driver to which you send the IRP can handle the IRP at elevated IRQLyou
must check the specifications for that driver!). Furthermore, its OK to create
and send an asynchronous IRP while owning a fast mutex.
Refer to Table 5-2 for a list of the types of IRP you can create using the two
asynchronous IRP routines. Note that IoBuildSynchronousFsdRequest and
IoBuildAsynchronousFsdRequest support the same IRP major function codes.
Table 5-2. Asynchronous IRP
Types
Support Function
IRP_MJ_READ IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IoBuildAsynchronousFsdRequest IRP_MJ_SHUTDOWN IRP_MJ_PNP
IRP_MJ_POWER (but only for
IRP_MN_POWER_SEQUENCE)
IoAllocateIrp
IRP-handling scenario numbers 5 and 8 at the end of this chapter contain cookbook
code for using asynchronous IRPs.
Forwarding to a Dispatch Routine
After you create an IRP, you call IoGetNextIrpStackLocation to obtain a pointer to
the first stack location. Then you initialize just that first location. If youve used
IoAllocateIrp to create the IRP, you need to fill in at least the MajorFunction code.
159/369
If youve used another of the four IRP-creation functions, the I/O Manager might
have already done the required initialization. You might then be able to skip this step,
depending on the rules for that particular type of IRP. Having initialized the stack, you
call IoCallDriver to send the IRP to a device driver:
PDEVICE_OBJECT DeviceObject; // <== somebody gives you this
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
stack->MajorFunction = IRP_MJ_Xxx;
<other initialization of "stack">NTSTATUS status = IoCallDriver(DeviceObject, Irp);
The first argument to IoCallDriver is the address of a device object that youve obtained
somehow. Often youre sending an IRP to the driver under yours in the PnP stack. In that
case, the DeviceObject in this fragment is the LowerDeviceObject you saved in your
device extension after calling IoAttachDeviceToDeviceStack. Ill describe some other
common ways of locating a device object in a few paragraphs.
The I/O Manager initializes the stack location pointer in the IRP to 1 before the actual
first location. Because the I/O stack is an array of IO_STACK_LOCATION structures,
you can think of the stack pointer as being initialized to point to the -1 element, which
doesnt exist. (In fact, the stack grows from high toward low addresses, but that detail
shouldnt obscure the concept Im trying to describe here.) We therefore ask for the
next stack location when we want to initialize the first one.
What IoCallDriver Does
You can imagine IoCallDriver as looking something like this (but I hasten to add that
this is not a copy of the actual source code):
NTSTATUS IoCallDriver(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
IoSetNextIrpStackLocation(Irp);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
stack->DeviceObject = DeviceObject;
ULONG fcn = stack->MajorFunction;
PDRIVER_OBJECT driver = DeviceObject->DriverObject;
160/369
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
NTSTATUS status;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
status = IoGetDeviceObjectPointer(devname, access,
&FileObject, &DeviceObject);
This function returns two pointers: one to a FILE_OBJECT and one to a
DEVICE_OBJECT.
To help defeat elevation-of-privilege attacks, specify the most restricted access
consistent with your needs. For example, if youll just be reading data, specify
FILE_READ_DATA.
161/369
When you create an IRP for a target you discover this way, you should set the FileObject
pointer in the first stack location. Furthermore, its a good idea to take an extra reference
to the file object until after IoCallDriver returns. The following fragment illustrates both
these ideas:
PIRP Irp = IoXxx(...);
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
ObReferenceObject(FileObject);
stack->FileObject = FileObject;<etc.>
IoCallDriver(DeviceObject, Irp);
ObDereferenceObject(FileObject);
After making this call, dont use either of the file or device object pointers.
IoGetDeviceObjectPointer performs several steps to locate the two pointers that it
returns to you:
1. It uses ZwOpenFile to open a kernel handle to the named device object.
Internally, this will cause the Object Manager to create a file object and to send
an IRP_MJ_CREATE to the target device. ZwOpenFile returns a file handle.
2. It calls ObReferenceObjectByHandle to get the address of the FILE_OBJECT
that the handle represents. This address becomes the FileObject return value.
3. It calls IoGetRelatedDeviceObject to get the address of the DEVICE_OBJECT
to which the file object refers. This address becomes the DeviceObject return
value.
4. It calls ZwClose to close the handle.
Names for Device Objects
For you to use IoGetDeviceObjectPointer, a driver in the stack for the device to which
you want to connect must have named a device object. We studied device object naming
in Chapter 2. Recall that a driver might have specified a name in the \Device folder in
its call to IoCreateDevice, and it might have created one or more symbolic links in the
\DosDevices folder. If you know the name of the device object or one of the symbolic
links, you can use that name in your call to IoGetDeviceObjectPointer.
Mechanically, completing an IRP entails filling in the Status and Information members
within the IRPs IoStatus block and calling IoCompleteRequest. The Status value is
one of the codes defined by manifest constants in the DDK header file NTSTATUS.H.
162/369
Refer to Table 5-3 for an abbreviated list of status codes for common situations. The
Information value depends on what type of IRP youre completing and on whether
youre causing the IRP to succeed or to fail. Most of the time, when youre causing
an IRP to fail (that is, completing it with an error status of some kind), youll set
Information to 0. When you cause an IRP that involves data transfer to succeed, you
ordinarily set the Information field equal to the number of bytes transferred.
Table 5-3. Some Commonly Used
NTSTATUS Codes
Status Code
Description
STATUS_SUCCESS
Normal completion.
STATUS_UNSUCCESSFUL
STATUS_NOT_IMPLEMENTED
STATUS_INVALID_HANDLE
STATUS_INVALID_PARAMETER
A parameter is in error.
STATUS_DELETE_PENDING
STATUS_INSUFFICIENT_RESOURCES
When you call IoCompleteRequest, you supply a priority boost value to be applied to
whichever thread is currently waiting for this request to complete. You normally choose
a boost value that depends on the type of device, as suggested by the manifest constant
names listed in Table 5-4. The priority adjustment improves the throughput of threads
that frequently wait for I/O operations to complete. Events for which the end user is
directly responsible, such as keyboard or mouse operations, result in greater priority
boosts in order to give preference to interactive tasks. Consequently, you want to choose
the boost value with at least some care. Dont use IO_SOUND_INCREMENT for
absolutely every operation a sound card driver finishes, for exampleits not necessary
to apply this extraordinary priority increment to a get-driver-version control request.
Table 5-4. Priority Boost Values for IoCompleteRequest
163/369
Manifest Constant
IO_NO_INCREMENT
IO_CD_ROM_INCREMENT
IO_DISK_INCREMENT
IO_KEYBOARD_INCREMENT
IO_MAILSLOT_INCREMENT
IO_MOUSE_INCREMENT
IO_NAMED_PIPE_INCREMENT
IO_NETWORK_INCREMENT
IO_PARALLEL_INCREMENT
IO_SERIAL_INCREMENT
IO_SOUND_INCREMENT
IO_VIDEO_INCREMENT
At least one of these three flags must be TRUE. Note that IoSetCompletionRoutine
is a macro, so you want to avoid arguments that generate side effects. The three flag
arguments and the function pointer, in particular, are each referenced twice by the
macro.
IoSetCompletionRoutine installs the completion routine address and context argument
in the nextIO_STACK_LOCATIONthat is, in the stack location in which the next
lower driver will find its parameters. Consequently, the lowest-level driver in a
particular stack of drivers doesnt dare attempt to install a completion routine. Doing so
would be pretty futile, of course, becauseby definition of lowest-level drivertheres
no driver left to pass the request on to.
CAUTION Recall that you are responsible for initializing the next I/O stack location
before you call IoCallDriver. Do this initialization before you install a completion
routine.
This
step
is
especially
important
if
you
use
IoCopyCurrentIrpStackLocationToNext to initialize the next stack location because that
function clears some flags that IoSetCompletionRoutine sets.
A completion routine looks like this:
NTSTATUS CompletionRoutine(PDEVICE_OBJECT fdo, PIRP Irp,
164/369
PVOID context)
{
return <some status code>;
}
It receives pointers to the device object and the IRP, and it also receives whichever
context value you specified in the call to IoSetCompletionRoutine. Completion routines
can be called at DISPATCH_LEVEL in an arbitrary thread context but can also be
called at PASSIVE_LEVEL or APC_LEVEL. To accommodate the worst case
(DISPATCH_LEVEL), completion routines therefore need to be in nonpaged memory
and must call only service functions that are callable at or below DISPATCH_LEVEL.
To accommodate the possibility of being called at a lower IRQL, however, a completion
routine shouldnt call functions such as KeAcquireSpinLockAtDpcLevel that assume
theyre at DISPATCH_LEVEL to start with.
There are really just two possible return values from a completion routine:
STATUS_MORE_PROCESSING_REQUIRED, which aborts the completion
process immediately. The spelling of this status code obscures its actual
purpose, which is to short-circuit the completion of an IRP. Sometimes, a
driver actually does some additional processing on the same IRP. Other times,
the flag just means, Yo, IoCompleteRequest! Like, dont touch this IRP no
more, dude! Future versions of the DDK will therefore define an enumeration
constant, StopCompletion, that is numerically the same as
STATUS_MORE_PROCESSING_REQUIRED but more evocatively named.
(Future printings of this book may also employ better grammar in describing
the meaning to be ascribed the constant, at least if my editors get their way.)
Anything else, which allows the completion process to continue. Because any
value besides STATUS_MORE_PROCESSING_REQUIRED has the same
meaning as any other, I usually just code STATUS_SUCCESS. Future versions
of the DDK will define STATUS_CONTINUE_COMPLETION and an
enumeration constant, ContinueCompletion, that are numerically the same as
STATUS_SUCCESS.
Ill have more to say about these return codes a bit further on in this chapter.
Situation 1: Synchronous Subsidiary IRP
The first situation to consider occurs when you create a synchronous IRP to help you
process an IRP that someone else has sent you. You intend to complete the main IRP
after the subsidiary IRP completes.
165/369
You wouldnt ordinarily use a completion routine with a synchronous IRP, but you
might want to if you were going to implement the safe cancel logic discussed later in this
chapter. If you follow that example, your completion routine will safely return before
you completely finish handling the subsidiary IRP and, therefore, comfortably before
you complete the main IRP. The sender of the main IRP is keeping you in memory until
then. Consequently, you wont need to use IoSetCompletionRoutineEx.
Situation 2: Asynchronous Subsidiary IRP
In this situation, you use an asynchronous subsidiary IRP to help you implement a main
IRP that someone sends you. You complete the main IRP in the completion routine that
youre obliged to install for the subsidiary IRP.
Here you should use IoSetCompletionRoutineEx if its available because the main IRP
senders protection expires as soon as you complete the main IRP. Your completion
routine still has to return to the I/O Manager and therefore needs the protection offered
by this new routine.
Situation 3: IRP Issued from Your Own System Thread
The third situation in our analysis of completion routines occurs when a system thread
youve created (see Chapter 14 for a discussion of system threads) installs completion
routines for IRPs it sends to other drivers. If you create a truly asynchronous IRP
in this situation, use IoSetCompletionRoutineEx to install the obligatory completion
routine and make sure that your driver cant unload before the completion routine
is actually called. You could, for example, claim an IO_REMOVE_LOCK that you
release in the completion routine. If you use scenario 8 from the cookbook at the end
of this chapter to send a nominally asynchronous IRP in a synchronous way, however,
or if you use synchronous IRPs in the first place, theres no particular reason to use
IoSetCompletionRoutineEx because youll presumably wait for these IRPs to finish
before calling PsTerminateSystemThread to end the thread. Some other function in your
driver will be waiting for the thread to terminate before allowing the operating system
to finally unload your driver. This combination of protections makes it safe to use an
ordinary completion routine.
Situation 4: IRP Issued from a Work Item
Here I hope youll be using IoAllocateWorkItem and IoQueueWorkItem, which protect
your driver from being unloaded until the work item callback routine returns. As in
the previous situation, youll want to use IoSetCompletionRoutineEx if you issue an
asynchronous IRP and dont wait (as in scenario 8) for it to finish. Otherwise, you
dont need the new routine unless you somehow return before the IRP completes, which
166/369
would be against all the rules for IRP handling and not just the rules for completion
routines.
Situation 5: Synchronous or Asynchronous IRP for Some Other Purpose
Maybe you have some reason for issuing a synchronous IRP that is not in aid of an IRP
that someone else has sent you and is not issued from the context of your own system
thread or a work item. I confess that I cant think of a circumstance in which youd
actually want to do this, but I think youd basically be toast if you tried. Protecting your
completion routine, if any, probably helps a bit, but theres no bulletproof way for you
to guarantee that youll still be there when IoCallDriver returns. If you think of a way,
youll simply move the problem to after you do whatever it is you think of, at which
point there has to be at least a return instruction that will get executed without protection
from outside your driver.
So dont do this.
167/369
168/369
A DPC routine (see the later discussion of how DPC routines work) would complete the
previous IRP and start the next one using this code:
VOID DpcForIsr(PKDPC junk, PDEVICE_OBJECT fdo, PIRP Irp,
PVOID morejunk)
{
IoCompleteRequest(Irp, STATUS_NO_INCREMENT);
IoStartNextPacket(fdo, TRUE);
}
To provide for canceling a queued IRP, you would need to write a cancel routine.
Illustrating that and the cancel logic in StartIo is beyond the scope of this book.
In addition, you can rely on the CurrentIrp field of a DEVICE_OBJECT to always
contain NULL or the address of the IRP most recently sent (by IoStartPacket or
IoStartNextPacket) to your StartIo routine.
Queuing an IRP is conceptually very simple. You can provide a list anchor in your
device extension, which you initialize in your AddDevice function:
typedef struct _DEVICE_EXTENSION {
LIST_ENTRY IrpQueue;
BOOLEAN DeviceBusy;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
{
InitializeListHead(&pdx->IrpQueue);
}
Then you can write two naive routines for queuing and dequeuing IRPs:
VOID NaiveStartPacket(PDEVICE_EXTENSION pdx, PIRP Irp)
169/369
{
if (pdx->DeviceBusy)
InsertTailList(&pdx->IrpQueue, &Irp->Tail.Overlay.ListEntry);
else
{
pdx->DeviceBusy = TRUE;
StartIo(pdx->DeviceObject, Irp);
}
}
VOID NaiveStartNextPacket(PDEVICE_EXTENSION pdx, PIRP Irp)
{
if (IsListEmpty(&pdx->IrpQueue))
pdx->DeviceBusy = FALSE;
else
{
PLIST_ENTRY foo = RemoveHeadList(&pdx->IrpQueue);
PIRP Irp = CONTAINING_RECORD(foo, IRP,
Tail.Overlay.ListEntry);
StartIo(pdx->DeviceObject, Irp);
}
}
170/369
Then your dispatch routine calls NaiveStartPacket, and your DPC routine calls
NaiveStartNextPacket in the manner discussed earlier in connection with the standard
model.
There are many problems with this scheme, which is why I called it naive. The most
basic problem is that your DPC routine and multiple instances of your dispatch routine
could all be simultaneously active on different CPUs. They would likely conflict in
trying to access the queue and the busy flag. You could address that problem by creating
a spin lock and using it to guard against the obvious races, as follows:
typedef struct _DEVICE_EXTENSION {
LIST_ENTRY IrpQueue;
KSPIN_LOCK IrpQueueLock;
BOOLEAN DeviceBusy;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
{
InitializeListHead(&pdx->IrpQueue);
KeInitializeSpinLock(&pdx->IrpQueueLock);
}
VOID LessNaiveStartPacket(PDEVICE_EXTENSION pdx, PIRP Irp)
{
KIRQL oldirql;
KeAcquireSpinLock(&pdx->IrpQueueLock, &oldirql);
if (pdx->DeviceBusy)
{
171/369
InsertTailList(&pdx->IrpQueue, &Irp->Tail.Overlay.ListEntry;
KeReleaseSpinLock(&pdx->IrpQueueLock, oldirql);
}
else
{
pdx->DeviceBusy = TRUE;
KeReleaseSpinLock(&pdx->IrpQueueLock, DISPATCH_LEVEL);
StartIo(pdx->DeviceObject, Irp);
KeLowerIrql(oldirql);
}
}
VOID LessNaiveStartNextPacket(PDEVICE_EXTENSION pdx, PIRP Irp)
{
KIRQL oldirql;
KeAcquireSpinLock(&pdx->IrpQueueLock, &oldirql);
if (IsListEmpty(&pdx->IrpQueue)
{
pdx->DeviceBusy = FALSE;
KeReleaseSpinLock(&pdx->IrpQueueLock, oldirql);
else
{
PLIST_ENTRY foo = RemoveHeadList(&pdx->IrpQueue);
172/369
KeReleaseSpinLock(&pdx->IrpQueueLock,
DISPATCH_LEVEL);
PIRP Irp = CONTAINING_RECORD(foo, IRP,
Tail.Overlay.ListEntry);
StartIo(pdx->DeviceObject, Irp);
KeLowerIrql(oldirql);
}
}
Incidentally, we always want to call StartIo at a single IRQL. Because DPC routines are
among the callers of LessNaiveStartNextPacket, and they run at DISPATCH_LEVEL,
we pick DISPATCH_LEVEL. That means we want to stay at DISPATCH_LEVEL
when we release the spin lock.
(You did remember that these two queue management routines need to be in nonpaged
memory because they run at DISPATCH_LEVEL, right?)
These queueing routines are actually almost OK, but they have one more defect and a
shortcoming. The shortcoming is that we need a way to stall a queue for the duration
of certain PnP and Power states. IRPs accumulate in a stalled queue until someone
unstalls the queue, whereupon the queue manager can resume sending IRPs to a StartIo
routine. The defect in the less naive set of routines is that someone could decide to
cancel an IRP at essentially any time. IRP cancellation complicates IRP queuing logic
so much that Ive devoted the next major section to discussing it. Before we get to that,
though, let me explain how to use the queuing routines that I crafted to deal with all the
problems.
Using the DEVQUEUE Object
To solve a variety of IRP queuing problems, I created a package of subroutines for
managing a queue object that I call a DEVQUEUE. Ill show you first the basic usage of
a DEVQUEUE. Later in this chapter, Ill explain how the major DEVQUEUE service
routines work. Ill discuss in later chapters how your PnP and power management code
interacts with the DEVQUEUE object or objects you define.
173/369
You define a DEVQUEUE object for each queue of requests youll manage in the
driver. For example, if your device manages reads and writes in a single queue, you
define one DEVQUEUE:
typedef struct _DEVICE_EXTENSION {
DEVQUEUE dqReadWrite;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
On the CD Code for the DEVQUEUE is part of GENERIC.SYS. In addition, if you
use my WDMWIZ to create a skeleton driver and dont ask for GENERIC.SYS support,
your skeleton project will include the files DEVQUEUE.CPP and DEVQUEUE.H,
which fully implement exactly the same object. I dont recommend trying to type this
code from the book because the code from the companion content will contain even
more features than I can describe in the book. I also recommend checking my Web site
(www.oneysoft.com) for updates and corrections.
Figure 5-8 illustrates the IRP processing logic for a typical driver using DEVQUEUE
objects. Each DEVQUEUE has its own StartIo routine, which you specify when you
initialize the object in AddDevice:
NTSTATUS AddDevice(...)
{
PDEVICE_EXTENSION pdx = ...;
InitializeQueue(&pdx->dqReadWrite, StartIo);
}
174/369
175/369
PAGED_CODE();
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoMarkIrpPending(Irp);
StartPacket(&pdx->dqReadWrite, fdo, Irp, CancelRoutine);
return STATUS_PENDING;
}
#pragma LOCKEDCODE
VOID CancelRoutine(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
CancelRequest(&pdx->dqReadWrite, Irp);
}
Note that the cancel argument to StartPacket is not optional: you must supply a cancel
routine, but you can see how simple that routine will be.
If you complete IRPs in a DPC routine, youll also call StartNextPacket:
VOID DpcForIsr(PKPDC junk1, PDEVICE_OBJECT fdo, PIRP junk2,
PDEVICE_EXTENSION pdx)
{
StartNextPacket(&pdx->dqReadWrite, fdo);
}
176/369
If you complete IRPs in your StartIo routine, schedule a DPC to make the call to
StartNextPacket in order to avoid excessive recursion. For example:
typedef struct _DEVICE_EXTENSION {
KDPC StartNextDpc;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
{
KeInitializeDpc(&pdx->StartNextDpc,
(PKDEFERRED_ROUTINE) StartNextDpcRoutine, pdx);
}
VOID StartIo(...)
{
IoCompleteRequest(...);
KeInsertQueueDpc(&pdx->StartNextDpc, NULL, NULL);
}
VOID StartNextDpcRoutine(PKDPC junk1, PDEVICE_EXTENSION pdx,
PVOID junk2, PVOID junk3)
{
StartNextPacket(&pdx->dqReadWrite, pdx->DeviceObject);
}
In this example, StartIo calls IoCompleteRequest to complete the IRP it has just
handled. Calling StartNextPacket directly might lead to a recursive call to StartIo.
After enough recursive calls, well run out of stack. To avoid the potential stack
overflow, we queue the StartNextDpc DPC object and return. Because StartIo runs
at DISPATCH_LEVEL, it wont be possible for the DPC routine to be called before
177/369
178/369
You mustnt touch an I/O buffer associated with a parked IRP because the IRP
can be cancelled (and the I/O buffer released!) at any time while its parked.
You should remove the IRP from the queue before trying to use a buffer.
179/369
(*CancelRoutine)(stack->DeviceObject, Irp);
return TRUE;
}
else
{
IoReleaseCancelSpinLock(Irp->CancelIrql);
return FALSE;
}
}
1. IoCancelIrp first acquires the global cancel spin lock. As you know if you read
the sidebar earlier, lots of old drivers contend for the use of this lock in their
normal IRP-handling path. New drivers hold this lock only briefly while
handling the cancellation of an IRP.
2. Setting the Cancel flag to TRUE alerts any interested party that IoCancelIrp has
been called for this IRP.
3. IoSetCancelRoutine performs an interlocked exchange to simultaneously
retrieve the existing CancelRoutine pointer and set the field to NULL in one
atomic operation.
4. IoCancelIrp calls the cancel routine, if there is one, without first releasing the
global cancel spin lock. The cancel routine must release the lock! Note also that
the device object argument to the cancel routine comes from the current stack
location, where IoCallDriver is supposed to have left it.
5. If there is no cancel routine, IoCancelIrp itself releases the global cancel spin
lock. Good idea, huh?
Could someone call IoCancelIrp twice? The thing to think about is that the
Cancel flag might be set in an IRP because of some number of primeval calls to
IoCancelIrp and that someone might call IoCancelIrp one more time (getting a
little impatient, are we?) while StartPacket is active. This wouldnt matter
because our first test of the Cancel flag occurs after we install our cancel
pointer. We would find the flag set to TRUE in this hypothetical situation and
would therefore execute the second call to IoSetCancelRoutine. Either
IoCancelIrp or we win the race to reset the cancel pointer to NULL, and
whoever wins ends up completing the IRP. The residue from the primeval calls
is simply irrelevant.
182/369
183/369
}
}
The first call (A) to KeWaitForSingleObject waits until one of two things happens. First,
someone might complete the IRP, and the I/O Managers cleanup code will then run and
signal event.
Alternatively, the timeout might expire before anyone completes the IRP. In this case,
KeWaitForSingleObject will return STATUS_TIMEOUT. The IRP should now be
completed quite soon in one of two paths. The first completion path is taken when
whoever was processing the IRP was really just about done when the timeout happened
and has, therefore, already called (or will shortly call) IoCompleteRequest. The other
completion path is through the cancel routine that, we must assume, the lower driver
has installed. That cancel routine should complete the IRP. Recall that we have to trust
other kernel-mode components to do their jobs, so we have to rely on whomever we sent
the IRP to complete it soon. Whichever path is taken, the I/O Managers completion
logic will set event and store the IRPs ending status in iosb. The second call (B) to
KeWaitForSingleObject makes sure that the event and iosb objects dont pass out of
scope too soon. Without that second call, we might return from this function, thereby
effectively deleting event and iosb. The I/O Manager might then end up walking on
memory that belongs to some other subroutine.
The problem with the preceding code is truly minuscule. Imagine that someone manages
to call IoCompleteRequest for this IRP right around the same time we decide to cancel
it by calling IoCancelIrp. Maybe the operation finishes shortly after the 5-second
timeout terminates the first KeWaitForSingleObject, for example. IoCompleteRequest
initiates a process that finishes with a call to IoFreeIrp. If the call to IoFreeIrp were
to happen before IoCancelIrp was done mucking about with the IRP, you can see
that IoCancelIrp could inadvertently corrupt memory when it touched the CancelIrql,
Cancel, and CancelRoutine fields of the IRP. Its also possible, depending on the exact
sequence of events, for IoCancelIrp to call a cancel routine, just before someone clears
the CancelRoutine pointer in preparation for completing the IRP, and for the cancel
routine to be in a race with the completion process.
Its very unlikely that the scenario I just described will happen. But, as someone (James
Thurber?) once said in connection with the chances of being eaten by a tiger on Main
Street (one in a million, as I recall), Once is enough. This kind of bug is almost
impossible to find, so you want to prevent it if you can. Ill show you two ways of
cancelling your own IRPs. One way is appropriate for synchronous IRPs, the other for
asynchronous IRPs.
Dont Do This
184/369
A once common but now deprecated technique for avoiding the tiger-on-main-street
bug described in the text relies on the fact that, in earlier versions of Windows, the call
to IoFreeIrp happened in the context of an APC in the thread that originates the IRP.
You could make sure you were in that same thread, raise IRQL to APC_LEVEL, check
whether the IRP had been completed yet, and (if not) call IoCancelIrp. You could be
sure of blocking the APC and the problematic call to IoFreeIrp.
You shouldnt rely on future releases of Windows always using an APC to perform the
cleanup for a synchronous IRP. Consequently, you shouldnt rely on boosting IRQL to
APC_LEVEL as a way to avoid a race between IoCancelIrp and IoFreeIrp.
Cancelling Your Own Synchronous IRP
Refer to the example in the preceding section, which illustrates a function that creates
a synchronous IRP, sends it to another driver, and then wants to wait no longer than
5 seconds for the IRP to complete. The key thing we need to accomplish in a solution
to the race between IoFreeIrp and IoCancelIrp is to prevent the call to IoFreeIrp
from happening until after any possible call to IoCancelIrp. We do this by means of
a completion routine that returns STATUS_MORE_PROCESSING_REQUIRED, as
follows:
SomeFunction()
{
KEVENT event;
IO_STATUS_BLOCK iosb;
KeInitializeEvent(&event, ...);
PIRP Irp = IoBuildSynchronousFsdRequest(..., &event, &iosb);
IoSetCompletionRoutine(Irp, OnComplete, (PVOID) &event,
TRUE, TRUE, TRUE);
NTSTATUS status = IoCallDriver(...);
if (status == STATUS_PENDING)
{
LARGE_INTEGER timeout;
185/369
timeout.QuadPart = -5 * 10000000;
if (KeWaitForSingleObject(&event, Executive, KernelMode,
FALSE, &timeout) == STATUS_TIMEOUT)
{
IoCancelIrp(Irp); // <== okay in this context
KeWaitForSingleObject(&event, Executive, KernelMode,
FALSE, NULL);
}
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
NTSTATUS OnComplete(PDEVICE_OBJECT junk, PIRP Irp, PVOID pev)
{
if (Irp->PendingReturned)
KeSetEvent((PKEVENT) pev, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
The new code in boldface prevents the race. Suppose IoCallDriver returns
STATUS_PENDING. In a normal case, the operation will complete normally, and a
lower-level driver will call IoCompleteRequest. Our completion routine gains control
and signals the event on which our mainline is waiting. Because the completion routine
returns STATUS_MORE_PROCESSING_REQUIRED, IoCompleteRequest will then
stop working on this IRP. We eventually regain control in our SomeFunction and notice
that our wait (the one labeled A) terminated normally. The IRP hasnt yet been cleaned
up, though, so we need to call IoCompleteRequesta second time to trigger the normal
cleanup mechanism.
186/369
Now suppose we decide we want to cancel the IRP and that Thurbers tiger is loose
so we have to worry about a call to IoFreeIrp releasing the IRP out from under
us. Our first wait (labeled A) finishes with STATUS_TIMEOUT, so we perform a
second wait (labeled B). Our completion routine sets the event on which were waiting.
It will also prevent the cleanup mechanism from running by returning
STATUS_MORE_PROCESSING_REQUIRED. IoCancelIrp can stomp away to its
hearts content on our hapless IRP without causing any harm. The IRP cant be released
until the second call to IoCompleteRequest from our mainline, and that cant happen
until IoCancelIrp has safely returned.
Notice that the completion routine in this example calls KeSetEvent only when the
IRPs PendingReturned flag is set to indicate that the lower drivers dispatch routine
returned STATUS_PENDING. Making this step conditional is an optimization that
avoids the potentially expensive step of setting the event when SomeFunction wont be
waiting on the event in the first place.
I want to mention one last fine point in connection with the preceding code. The call to
IoCompleteRequest at the very end of the subroutine will trigger a process that includes
setting event and iosb so long as the IRP originally completed with a success status.
In the first edition, I had an additional call to KeWaitForSingleObject at this point to
make sure that event and iosb could not pass out of scope before the I/O Manager was
done touching them. A reviewer pointed out that the routine that references event and
iosb will already have run by the time IoCompleteRequest returns; consequently, the
additional wait is not needed.
Cancelling Your Own Asynchronous IRP
To safely cancel an IRP that youve created with IoAllocateIrp or
IoBuildAsynchronousFsdRequest, you can follow this general plan. First define a
couple of extra fields in your device extension structure:
typedef struct _DEVICE_EXTENSION {
PIRP TheIrp;
ULONG CancelFlag;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
Initialize these fields just before you call IoCallDriver to launch the IRP:
pdx->TheIrp = IRP;
pdx->CancelFlag = 0;
187/369
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) CompletionRoutine,
(PVOID) pdx, TRUE, TRUE, TRUE);
IoCallDriver(..., Irp);
If you decide later on that you want to cancel this IRP, do something like the following:
VOID CancelTheIrp(PDEVICE_EXENSION pdx)
{
PIRP Irp =
(PIRP) InterlockedExchangePointer((PVOID*)&pdx->TheIrp, NULL);
if (Irp)
{
IoCancelIrp(Irp);
if (InterlockedExchange(&pdx->CancelFlag, 1)
IoFreeIrp(Irp);
}
}
This function dovetails with the completion routine you install for the IRP:
NTSTATUS CompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp,
PDEVICE_EXTENSION pdx)
{
if (InterlockedExchangePointer(&pdx->TheIrp, NULL)
InterlockedExchange(&pdx->CancelFlag, 1))
188/369
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
The basic idea underlying this deceptively simple code is that whichever routine sees
the IRP last (either CompletionRoutine or CancelTheIrp) will make the requisite call to
IoFreeIrp, at point 3 or 6. Heres how it works:
The normal case occurs when you dont ever try to cancel the IRP. Whoever
you sent the IRP to eventually completes it, and your completion routine gets
control. The first InterlockedExchangePointer (point 4) returns the non-NULL
address of the IRP. Since this is not 0, the compiler short-circuits the evaluation
of the Boolean expression and executes the call to IoFreeIrp. Any subsequent
call to CancelTheIrp will find the IRP pointer set to NULL at point 1 and wont
do anything else.
Another easy case to analyze occurs when CancelTheIrp is called long before
anyone gets around to completing this IRP, which means that we dont have
any actual race. At point 1, we nullify the TheIrp pointer. Because the IRP
pointer was previously not NULL, we go ahead and call IoCancelIrp. In this
situation, our call to IoCancelIrp will cause somebody to complete the IRP
reasonably soon, and our completion routine runs. It sees TheIrp as NULL and
goes on to evaluate the second half of the Boolean expression. Whoever
executes the InterlockedExchange on CancelFlag first will get back 0 and skip
calling IoFreeIrp. Whoever executes it second will get back 1 and will call
IoFreeIrp.
Now for the case we were worried about: suppose someone is completing the
IRP right about the time CancelTheIrp wants to cancel it. The worst that can
happen is that our completion routine runs before we manage to call
IoCancelIrp. The completion routine sees TheIrp as NULL and therefore
exchanges CancelFlag with 1. Just as in the previous case, the routine will get 0
as the return value and skip the IoFreeIrp call. IoCancelIrp can safely operate
on the IRP. (It will presumably just return without calling a cancel routine
because whoever completed this IRP will undoubtedly have set the CancelRoutine pointer to NULL first.)
The appealing thing about the technique I just showed you is its elegance: we rely
solely on interlocked operations and therefore dont need any potentially expensive
synchronization primitives.
Cancelling Someone Elses IRP
189/369
To round out our discussion of IRP cancellation, suppose someone sends you an IRP
that you then forward to another driver. Situations might arise where youd like to cancel
that IRP. For example, perhaps you need that IRP out of the way so you can proceed
with a power-down operation. Or perhaps youre waiting synchronously for the IRP to
finish and youd like to impose a timeout as in the first example of this section.
To avoid the IoCancelIrp/IoFreeIrp race, you need to have your own completion routine
in place. The details of the coding then depend on whether youre waiting for the IRP.
Canceling Someone Elses IRP on Which Youre Waiting
Suppose your dispatch function passes down an IRP and waits synchronously for it to
complete. (See usage scenario 7 at the end of this chapter for the cookbook version.)
Use code like this to cancel the IRP if it doesnt finish quickly enough to suit you:
NTSTATUS DispatchSomething(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, OnComplete, (PVOID) &event,
TRUE, TRUE, TRUE);
NTSTATUS status = IoCallDriver(...);
if (status == STATUS_PENDING)
{
LARGE_INTEGER timeout;
timeout.QuadPart = -5 * 10000000;
if (KeWaitForSingleObject(&event, Executive, KernelMode,
FALSE, &timeout) == STATUS_TIMEOUT)
190/369
{
IoCancelIrp(Irp);
KeWaitForSingleObject(&event, Executive, KernelMode,
FALSE, NULL);
}
}
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS OnComplete(PDEVICE_OBJECT junk, PIRP Irp, PVOID pev)
{
if (Irp->PendingReturned)
KeSetEvent((PKEVENT) pev, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
This code is almost the same as what I showed earlier for canceling your own
synchronous IRP. The only difference is that this example involves a dispatch routine,
which must return a status code. As in the earlier example, we install our own
completion routine to prevent the completion process from running to its ultimate
conclusion before we get past the point where we might call IoCancelIrp.
You might notice that I didnt say anything about whether the IRP itself was
synchronous or asynchronous. This is because the difference between the two types of
IRP only matters to the driver that creates them in the first place. File system drivers
must make distinctions between synchronous and asynchronous IRPs with respect to
how they call the system cache manager, but device drivers dont typically have this
complication. What matters to a lower-level driver is whether its appropriate to block a
191/369
thread in order to handle an IRP synchronously, and that depends on the current IRQL
and whether youre in an arbitrary or a nonarbitrary thread.
Canceling Someone Elses IRP on Which Youre Not Waiting
Suppose youve forwarded somebody elses IRP to another driver, but you werent
planning to wait for it to complete. For whatever reason, you decide later on that youd
like to cancel that IRP.
typedef struct _DEVICE_EXTENSION {
PIRP TheIrp;
ULONG CancelFlag;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS DispatchSomething(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnComplete,
(PVOID) pdx,
TRUE, TRUE, TRUE);
pdx->CancelFlag = 0;
pdx->TheIrp = Irp;
IoMarkIrpPending(Irp);
IoCallDriver(pdx->LowerDeviceObject, Irp);
return STATUS_PENDING;
}
192/369
193/369
194/369
One of the times the I/O Manager cancels IRPs is when a thread terminates.
Threads often terminate because their parent process is terminating, and the I/O
Manager will also automatically close all handles that are still open when a
process terminates. The coincidence between this kind of cancellation and the
automatic handle closing contributes to the incorrect idea that a driver can get
by with support for just one concept.
In this book, Ill show you two ways of painlessly implementing support for
IRP_MJ_CLEANUP, depending on whether youre using one of my DEVQUEUE
objects or one of Microsofts cancel-safe queues.
Cleanup with a DEVQUEUE
If youve used a DEVQUEUE to queue IRPs, your IRP_MJ_DISPATCH_CLEANUP
routine will be astonishingly simple:
NTSTATUS DispatchCleanup(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT fop = stack->FileObject;
CleanupRequests(&pdx->dqReadWrite, fop,
STATUS_CANCELLED);
return CompleteRequest(Irp, STATUS_SUCCESS, 0);
}
CleanupRequests will remove all IRPs from the queue that belong to the same file object
and will complete those IRPs with STATUS_CANCELLED. Note that you complete
the IRP_MJ_CLEANUP request itself with STATUS_SUCCESS.
CleanupRequests contains a wealth of detail:
VOID CleanupRequests(PDEVQUEUE pdq, PFILE_OBJECT fop,
196/369
NTSTATUS status)
{
LIST_ENTRY cancellist;
InitializeListHead(&cancellist);
KIRQL oldirql;
KeAcquireSpinLock(&pdq->lock, &oldirql);
PLIST_ENTRY first = &pdq->head;
PLIST_ENTRY next;
for (next = first->Flink; next != first; )
{
PIRP Irp = CONTAINING_RECORD(next, IRP,
Tail.Overlay.ListEntry);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PLIST_ENTRY current = next;
next = next->Flink;
if (fop && stack->FileObject != fop)
continue;
if (!IoSetCancelRoutine(Irp, NULL))
continue;
RemoveEntryList(current);
InsertTailList(&cancellist, current);
}
197/369
KeReleaseSpinLock(&pdq->lock, oldirql);
while (!IsListEmpty(&cancellist))
{
next = RemoveHeadList(&cancellist);
PIRP Irp = CONTAINING_RECORD(next, IRP,
Tail.Overlay.ListEntry);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
1. Our strategy will be to move the IRPs that need to be cancelled into a private
queue under protection of the queues spin lock. Hence, we initialize the private
queue and acquire the spin lock before doing anything else.
2. This loop traverses the entire queue until we return to the list head. Notice the
absence of a loop increment stepthe third clause in the for statement. Ill
explain in a moment why its desirable to have no loop increment.
3. If were being called to help out with IRP_MJ_CLEANUP, the fop argument is
the address of a file object thats about to be closed. Were supposed to isolate
the IRPs that pertain to the same file object, which requires us to first find the
stack location.
4. If we decide to remove this IRP from the queue, we wont thereafter have an
easy way to find the next IRP in the main queue. We therefore perform the loop
increment step here.
5. This especially clever statement comes to us courtesy of Jamie Hanrahan. We
need to worry that someone might be trying to cancel the IRP that were
currently looking at during this iteration. They could get only as far as the point
where CancelRequest tries to acquire the spin lock. Before getting that far,
however, they necessarily had to execute the statement inside IoCancelIrp that
nullifies the cancel routine pointer. If we find that pointer set to NULL when
we call IoSetCancelRoutine, therefore, we can be sure that someone really is
trying to cancel this IRP. By simply skipping the IRP during this iteration, we
allow the cancel routine to complete it later on.
6. Heres where we take the IRP out of the main queue and put it in the private
queue instead.
198/369
7. Once we finish moving IRPs into the private queue, we can release our spin
lock. Then we cancel all the IRPs we moved.
Cleanup with a Cancel-Safe Queue
To easily clean up IRPs that youve queued by calling IoCsqInsertIrp, simply adopt the
convention that the peek context parameter you use with IoCsqRemoveNextIrp, if not
NULL, will be the address of a FILE_OBJECT. Your IRP_MJ_CANCEL routine will
look like this (compare with the Cancel sample in the DDK):
NTSTATUS DispatchCleanup(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT fop = stack->FileObject;
PIRP qirp;
while ((qirp = IoCsqRemoveNextIrp(&pdx->csq, fop)))
CompleteRequest(qirp, STATUS_CANCELLED, 0);
return CompleteRequest(Irp, STATUS_SUCCESS, 0);
}
Implement your PeekNextIrp callback routine this way:
PIRP PeekNextIrp(PIO_CSQ csq, PIRP Irp, PVOID PeekContext)
{
PDEVICE_EXTENSION pdx = GET_DEVICE_EXTENSION(csq);
PLIST_ENTRY next = Irp ? Irp->Tail.Overlay.ListEntry.Flink
: pdx->IrpQueueAnchor.Flink;
199/369
200/369
201/369
202/369
}
NTSTATUS CompletionRoutine(PDEVICE_OBJECT fdo, PIRP Irp,
PDEVICE_EXTENSION pdx)
{
if (Irp->PendingReturned)
IoMarkIrpPending(Irp);
<whatever post processing you wanted to do>
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
return STATUS_SUCCESS;
}
Kch bn 2-S Chuyn xung khng c s hon thnh th tc
Trong kch bn ny, ngi no gi bn mt IRP. Bn s chuyn tip IRP ti trnh
iu khin thp hn trong chng PnP ca cc bn, nhng bn khng cn lm bt c ci
g vi IRP. Xem hnh 5-12. Chp nhn chin lc ny, m c th cng c gi " Let
Mikey try it" cch tip cn, khi c hai ca s theo sau true:
Mt ai ang gi bn mt IRP (ngc vi bn to ra chnh IRP).
Bn khng x l IRP ny, tr phi mt trnh iu khin di bn c l
mun ti.
203/369
204/369
return status;
}
Kch bn 3- Hon thnh trong th tc gi i
Trong kch bn ny, bn ngay lp tc hon thnh mt IRP m ngi no gi bn.
Xem hnh 5-13. Chp nhn chin lc ny khi:
Mt ai ang gi bn mt IRP (ngc vi bn to ra chnh IRP), v
Bn c th x l IRP ngay lp tc. iu ny l trng hp cho nhiu cch thc
ca nhng yu cu iu khin (IOCTL) vo/ra. Hoc
Ci g r rng sai vi IRP, m trong trng hp gy ra n qun ngay lp
tc c l l th t t nht lm.
205/369
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_XXX;
}
Kch bn 4-Hng i cho sau ny x l
Trong kch bn ny, ngi no gi bn mt IRP iu bn khng c th x l ngay
tc th. Bn mang IRP vo mt hng i cho sau ny x l mt th tc StartIo. Xem
Hnh 5-14. Chp nhn chin lc ny khi c hai s theo sau ng:
Ngi no ang gi bn mt IRP (ngc vi bn to ra chnh IRP).
Bn khng bit rng bn c th x l IRP ngay tc th. iu ny thng xuyn
l trng hp cho IRPs m i hi c xp theo th t truy nhp phn cng,
nh nhng s c v vit.
206/369
DEVQUEUE dqReadWrite;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT pdo)
{
InitializeQueue(&pdx->dqReadWrite, StartIo);
IoInitializeDpcRequest(fdo, (PIO_DPC_ROUTINE) DpcForIsr);
}
NTSTATUS DispatchReadWrite(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoMarkIrpPending(Irp);
StartPacket(&pdx->dqReadWrite, fdo, Irp, CancelRoutine);
return STATUS_PENDING;
}
VOID CancelRoutine(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
207/369
CancelRequest(&pdx->dqReadWrite, Irp);
}
VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp)
{
}
BOOLEAN OnInterrupt(PKINTERRUPT junk, PDEVICE_EXTENSION pdx)
{
}
VOID DpcForIsr(PKDPC junk1, PDEVICE_OBJECT fdo, PIRP junk2,
PDEVICE_EXTENSION pdx)
{
208/369
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
Kch bn 5-IRP Khng ng b ca ring mnh
Trong kch bn ny bn to nn mt IRP khng ng b, bn tip ti trnh iu khin
khc. Xem Hnh 5-15. Chp nhn chin lc ny khi nhng iu kin sau y ng:
Bn cn trnh iu khin khc thc hin mt thao tc trn li ch ca cc
bn.
Hay l bn trong mt lung chuyn quyn ( bn khng quyt tm Block) hay
bn chy DISPATCH_LEVEL (trong trng hp no bn khng c th
block).
209/369
(PVOID) 42);
if (!NT_SUCCESS(status))
return <status>;
PIRP Irp;
Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_XXX, DeviceObject,
...);
-orIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
stack->MajorFunction = IRP_MJ_XXX;
<additional initialization)
IoSetCompletionRoutine[Ex]([pdx->DeviceObject,] Irp,
(PIO_COMPLETION_ROUTINE) CompletionRoutine, pdx,
TRUE, TRUE, TRUE);
ObReferenceObject(DeviceObject);
IoCallDriver(DeviceObject, Irp);
ObDereferenceObject(DeviceObject);
}
210/369
211/369
{
PMDL mdl;
while ((mdl = Irp->MdlAddress))
{
Irp->MdlAddress = mdl->Next;
MmUnlockPages(mdl); // <== only if you earlier
// called MmProbeAndLockPages
IoFreeMdl(mdl);
}
IoFreeIrp(Irp);
<optional release of remove lock>
return STATUS_MORE_PROCESSING_REQUIRED;
}
Cleanup cho DO_BUFFERED_IO ch ( Cleanup for DO_BUFFERED_IO Target
):
Nu i tng thit b ch ch bo DO_BUFFERED_IO , qun l vo/ra s to ra mt
b m h thng. S hon thnh th tc ca cc bn v mt l thuyt cn phi sao chp
d liu t b m h thng n b m ca ring mnh v sau gii phng b m h
thng. Khng may, nhng bit c hiu v nhng lnh vc c cn lm iu ny th
khng phi c ly ti liu trong DDK. Li khuyn ca ti trc tip s n gin khng
gi nhng s c v vit ti mt trnh iu khin m s dng b m vo/ra. Thay vo
, gi ZwReadFile hay ZwWriteFile.
Cleanup cho nhng ch khc (C leanup for Other Targets ):
Nu thit b ch ch bo khng DO_DIRECT_IO hay DO_BUFFERED_IO, khng c
cleanup b sung. Phew!
Kch bn 6-IRP ng b ca ring mnh
212/369
213/369
(PVOID) 42);
if (!NT_SUCCESS(status))
return <status>;
PIRP Irp;
KEVENT event;
IO_STATUS_BLOCK iosb;
KeInitializeEvent(&event, NotificationEvent, FALSE);
Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_XXX,
DeviceObject, ..., &event, &iosb);
-orIrp = IoBuildDeviceIoControlRequest(IOCTL_XXX, DeviceObject,
..., &event, &iosb);
status = IoCallDriver(DeviceObject, Irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode,
FALSE, NULL);
status = iosb.Status;
}
214/369
}
Nh trong kch bn 5, nhng s gi ti IoAcquireRemoveLock v
IoReleaseRemoveLock (nhng im c gn nhn A) ch cn thit nu thit b ti no
bn gi IRP ny l LowerDeviceObject trong ngn xp PnP ca cc bn. 42 l mt nhn
chuyn quyn-n n gin qu phc tp th thu nhn s kha loi b sau tn ti
IRP, ng nh vy chng ti c th s dng con tr IRP nh mt nhn g li xy dng.
Chng ti s s dng kch bn ny thng xuyn trong Chng 12 gi nhng khi
yu cu USB (URBs) ng b xung ngawn xp. Trong nhng v d chng ti s nghin
cu , chng ti s thng ang lm iu ny trong vn cnh ca mt s lin lc th
tc IRP m c lp thu nhn s kha loi b. Bi vy, bn khng chin thng nhn thy
m kha loi b thm trong nhng v d .
Bn khng phi lm qut dn sau khi IRP ny! Qun l vo/ra lm n t ng.
Kch bn 7-S Chuyn qua ng b Xung
In kch bn ny, ngi no gi bn mt IRP. Bn i qua IRP xung ng b trong
ngn xp PnP ca cc bn v sau tip tc x l. Xem hnh 5-17. Chp nhn chin
lc ny khi tt c s theo sau ng:
Ngi no ang gi bn mt IRP (ngc vi bn to ra chnh IRP).
Bn chy PASSIVE_LEVEL trong mt lung khng chuyn quyn.
S x l sau ca cc bn cho IRP phi c lm PASSIVE_LEVEL.
215/369
216/369
FALSE, NULL);
status = Irp->IoStatus.Status;
}
return status;
}
NTSTATUS ForwardAndWaitCompletionRoutine(PDEVICE_OBJECT fdo,
PIRP Irp, PKEVENT pev)
{
if (Irp->PendingReturned)
KeSetEvent(pev, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
Ngi gi th tc ny cn gi cho IoCompleteRequest cho IRP ny v thu nhn v
gii phng s kha loi b. N khng thch hp cho ForwardAndWait cha ng
kha lgic loi b bi v ngi gi c l khng mun gii phng s kha sm nh
vy.
Ch rng chc nng IoForwardIrpSynchronously Windows XP DDK ng gi y
ging nh nhng bc.
Kch bn 8-IRP Khng ng b c x l ng b
In kch bn ny, bn to nn mt IRP khng ng b, bn chuyn tip ti trnh iu
khin khc. Ri bn i IRP hon thnh. Xem hnh 5-18. Chp nhn chin lc ny
khi tt c s theo sau ng:
Bn cn trnh iu khin khc thc hin mt thao tc trn s i din ca cc
bn.
Bn cn i thao tc kt thc trc khi bn c th tip tc.
Bn chy APC_LEVEL trong mt lung khng chuyn quyn.
217/369
if (!NT_SUCCESS(status))
return <status>;
PIRP Irp;
218/369
219/369
if (Irp->PendingReturned)
KeSetEvent(pev, EVENT_INCREMENT, FALSE);
<IRP cleanup -- see above>
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
(nhng im c gn nhn A) ch cn thit nu thit b ti bn ang gi IRP ny
Nh trong nhng kch bn trc , nhng s gi ti IoAcquireRemoveLock v
IoReleaseRemoveLock (nhng im c gn nhn A) ch cn thit nu thit b ti
no bn gi IRP ny l LowerDeviceObject trong ngn xp PnP ca cc bn. 42 l mt
nhn chuyn quyn-n n gin qu phc tp th thu nhn s kha loi b sau
tn ti IRP, ng nh vy chng ti c th s dng con tr IRP nh mt nhn g li xy
dng.
Ch rng bn vn cn phi thc hin tt c cng cleanup c bn lun trc v
Qun l vo/ra l khng qut dn sau khi mt IRP khng ng b. Bn c l cng
cn cung cp cho cancelling IRP ny, ti trng hp no bn cn phi s dng k thut
tranh lun trong thn ca chng ny cho IRPs khng ng b cancelling.
220/369
Bi 2.
Lp trnh truyn thng cng LPT da vo x l IRP
Bi 3.
Lp trnh m rng x l IRP.
221/369
}
Cc cu trc CM_PARTIAL_RESOURCE_lIST cha ng mt s m v mt mng
cc cu trc CM_PARTIAL_RESOURCE_DESCRIPTOR, nh l minh ho hnh 7.1.
Mi mt k hiu ngun trong mng ny c mt thnh phn l Type biu th kiu
ca ngun c m t v mt s cc thnh phn thm vo ci m cung cp cc th hin
c th v ngun c ch nh. Bn s khng b lm cho ngc nhin (bt ng) bng vic
hy tm trong mng ny v theo cch: Nu thit b ca bn s dng IRQ v vng cc
cng vo ra, bn s nhn c hai k hiu ngun t trong mng ny. Mt trong hai k
hiu l dnh cho IRQ ca bn v k hiu cn li s dnh cho phn cng vo/ra. Tht
khng may, bn khng th d on trc c th t m cc k hiu s xut hin trong
mng ny. Chnh v vy, hm gip StartDevice s phi bt u vi mt vng lp
l tri mng mng ny bng cch trch ra cc gi tr ngun vo mt tp hp cc bin
cc b. Bn c th s dng cc bin cc b ny sau lin kt vi cc ngun ch nh
ti cc v tr mm bn cn (n s khc vi nhng g l thuyt ni, c th khc mt cht
vi cc th t m trong PnP Manager chn la hin th cho bn)
222/369
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource =
223/369
translated->PartialDescriptors;
switch (resource->Type)
{
case CmResourceTypePort:
<save port info in local variables>
break;
case CmResourceTypeInterrupt:
<save interrupt info in local variables>
break;
case CmResourceTypeMemory:
<save memory info in local variables>
break;
case CmResourceTypeDma:
<save DMA info in local variables>
break;
224/369
}
}
Overview
225/369
Port
Memory
Dma
Interrupt
226/369
227/369
228/369
Irp->AssociatedIrp.SystemBuffer = sva;
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
if (reading)
stack->Parameters.Read.Length = length;else
stack->Parameters.Write.Length = length;
<code to send and await IRP>
if (reading)
RtlCopyMemory(uva, sva, length);
ExFreePool(sva);
Phng php trc tip (The Direct Method):
Nu trong i tng thit b bn ch r DO_DIRECT_IO th trnh iu khin vo ra s
to ra mt MDL m t cc trang b kho ang cha vng m d liu ch ngi
dng.Cu trc ca MDL c khai bo nh sau:
typedef struct _MDL {
struct _MDL *Next;
CSHORT Size;
CSHORT MdlFlags;
struct _EPROCESS *Process;
PVOID MappedSystemVa;
PVOID StartVa;
ULONG ByteCount;
ULONG ByteOffset;
} MDL, *PMDL;
229/369
Hnh 7.3 minh ho cho quy lut ca MDL. Thnh phn StartVa cung cp a ch o ca
vng m - ch hp l trong trng hp ch ngi dng x l iu ny. ByteOffset
l a ch offset ca ni bt u vng m trong sut mt Frame, v ByteCount l kch
thc ca vng m tnh theo n v Byte. Mng Page, khng c khai bo thng
thng nh phn cu trc ca MDL, tip theo MDL trong b nh v cha ng s lng
cc trang Frame vt l ca bn a ch o ch ngi dng.
Description
IoAllocateMdl
Creates an MDL.
230/369
IoBuildPartialMdl
IoFreeMdl
Destroys an MDL.
MmBuildMdlForNonPagedPool
MmGetMdlByteCount
MmGetMdlByteOffset
MmGetMdlPfnArray
MmGetMdlVirtualAddress
MmGetSystemAddressForMdl
MmGetSystemAddressForMdlSafe
MmInitializeMdl
MmMapLockedPages
MmMapLockedPagesSpecifyCache
MmPrepareMdlForReuse
Reinitializes an MDL.
MmProbeAndLockPages
MmSizeOfMdl
MmUnlockPages
MmUnmapLockedPages
231/369
232/369
8 bits
READ_PORT_UCHAR
WRITE_PORT_UCHAR
READ_REGISTER_UCHAR
WRITE_REGISTER_UCHAR
16 bits
READ_PORT_USHORT
WRITE_PORT_USHORT
READ_REGISTER_USHORT
WRITE_REGISTER_USHORT
32 bits
READ_PORT_ULONG
WRITE_PORT_ULONG
READ_REGISTER_ULONG
WRITE_REGISTER_ULONG
String of
8-bit bytes
READ_PORT_BUFFER_UCHAR
WRITE_PORT_BUFFER_UCHAR
READ_REGISTER_BUFFER_UCHAR
WRITE_REGISTER_BUFFER_UCHAR
String of
READ_PORT_BUFFER_USHORT READ_REGISTER_BUFFER_USHORT
16-bit words WRITE_PORT_BUFFER_USHORT WRITE_REGISTER_BUFFER_USHORT
String of
READ_PORT_BUFFER_ULONG
32-bit WRITE_PORT_BUFFER_ULONG
doublewords
READ_REGISTER_BUFFER_ULONG
WRITE_REGISTER_BUFFER_ULONG
PUCHAR portbase;
ULONG nports;
BOOLEAN mappedport;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
PHYSICAL_ADDRESS portbase;
235/369
{
case CmResourceTypePort:
portbase = resource->u.Port.Start;
pdx->nports = resource->u.Port.Length;
pdx->mappedport =
(resource->Flags & CM_RESOURCE_PORT_IO) == 0;
break;
if (pdx->mappedport)
{
236/369
237/369
}
Ti nguyn b nh (Memory Resources):
Cc thit b m b nh c m hnh ho ch ra cc thanh ghi, ci m phn mm truy
cp s dng cu lnh np v lu tr. Gi tr ti nguyn c dch ny bn ly t trnh
qun l PnP l mt a ch vt l, v bn cn phi d phng cc a ch o c th cha
(bao bc) b nh vt l. Sau , bn s phi gi cc th tc ca Hal, nhng ci m s
lien kt vi cc thanh ghi b nh nh l Read_Register_Unchar , write_register_unchar,
v hn th na. Phn code cu hnh cng nh ch thch ca bn s tng t nh nhng
g c trnh by di y.
typedef struct _DEVICE_EXTENSION {
PUCHAR membase;
ULONG nbytes;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
PHYSICAL_ADDRESS membase;
membase = resource->u.Memory.Start;
238/369
pdx->nbytes = resource->u.Memory.Length;
break;
if (pdx->membase)
MmUnmapIoSpace(pdx->membase, pdx->nbytes);
pdx->membase = NULL;
239/369
240/369
PKINTERRUPT InterruptObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
ULONG vector;
KIRQL irql;
// interrupt vector
// interrupt level
KINTERRUPT_MODE mode;
// latching mode
KAFFINITY affinity;
// processor affinity
BOOLEAN irqshare;
// shared interrupt?
241/369
switch (resource->Type)
{
case CmResourceTypeInterrupt:
vector = resource->u.Interrupt.Vector;
affinity = resource->u.Interrupt.Affinity;
irqshare =
resource->ShareDisposition == CmResourceShareShared;
break;
status = IoConnectInterrupt(&pdx->InterruptObject,
(PKSERVICE_ROUTINE) OnInterrupt, (PVOID) pdx, NULL,
242/369
243/369
{
if (<device not interrupting>)
return FALSE;
<handle interrupt>
return TRUE;
}
C cu ngt iu khin ca Windows NT l cc ngt cng (Hardware interupts) c th
c chia s bi nhiu thit b. Theo cng vic u tin trong ISR l quyt nh xem
c hay khng thit b ca bn ang ngt thi im hin ti. Nu khng, Bn s tr v
gi tr FASLE ngay tc th v th nhn (kernel) c th gi lnh ngt ti cc driver ca
cc thit b khc. Cn nu c, bn s xa ngt ti mc thit b v tr v gi tr l TRUE.
Liu rng sau nhn c gi n ISR ca cc thit b khc hay khng th n s ph
thuc vo vic liu rng thit b ngt l edge-triggered hay trigger mc( level-triggered)
v trn cc chi tit h nn khc.
Lp trnh gii hn trong ISR (Programming Restrictions in the ISR )ISR thc thi
ti mt IRQL cao hn so vi DISPATCH_LEVEL. Tt c cc on code v d liu s
dng trong mt ISR theo s phi trong b nh nonpaged (nonpaged memory). Hn
na, vic thit lp cc hm ch nhn (kernel-mode functions) m mt ISR c th
gi l rt hn ch.
K t khi mt ISR thc thi ti mt IRQL mc cao, n cho ra cc hot ng khc trn
chnh CPU ca n m yu cu IRQL tng t hoc thp hn. Vi h thng m vic thi
hnh l tt nht th theo , ISR phi thc thi nhanh nht mc c th. V c bn,
l lm s lng cng vic nh nht c yu cu phc v phn cng ca bn v tr
v. tr phi c thm cng vic lm (chng hn hon thnh mt IRP), lp lch cho mt
DPC nm gi, x l vic ny.
Nhng ng c vi v trong vic tnh ton s pi vi hng ngn im thp phn trn ISR
ca bn, ( tr phi thit b ca bn yu cu bn phi lm mt iu g th tht tc ci
v n chc hn l khng th). Mt kh nng phn on tt s ni cho bn bit iu g l
ng n khi bn la chn lm vic gia mt th tc ISR v mt DPC.
BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject,
PDEVICE_EXTENSION pdx)
{
244/369
245/369
}
IoInitializeDpcRequest l mt Macro trong WDM.H n khi to i tng xy dng sn
DPC (built-in DPC) ca i tng thit b. i s th 2 l mt a ch ca DPC thng
l m ti s ch ra cho cc bn ngay by.
Vi vic khi to cho i tng DPC ti y, ISR c th yu cu mt DPC bng vic s
dng Macro di y:
BOOLEAN OnInterrupt(...)
{
}
Li gi ny ti cc IoRequestDpc t i tng DPC ca i tng thit b trong mt
hng i ca h thng ln, nh hnh minh ha di y:.
246/369
mt DPC khc, nhn n gin s b qua yu cu th hai. Ni cch khc, i tng DPC
ca bn s trong hng i mt ln, khng c vn g c bao nhiu DPC c yu
cu k tip nhau ca ISR ca bn, v nhn s callback ch mt ln. Trong sut mt vic
khn cu ny, th DPC thng l ca bn cn phi hon thnh tt c cc cng vic lin
quan n cc ngt m xy ra DPC cui cng..
n gin nht, bn c th chc chn thit b ca bn s khng b ngt trong thi im
m bn yu cu DPC v thi im m DPC thng lca bn kt thc s lm vic ca
n.
i tng DPC ty bin (Custom DPC Objects )
Bn c th to ra cc i tng DPC khc bn cnh mt DPC vi tn Dpc trong mt i
tng thit b n gin hn ch b nh- trong phn m rng thit b ca bn hoc
mt vi ni khc m khng c nh s (isnt paged)vi mt i tngj KDPC, v
khi to n:
typedef struct _DEVICE_EXTENSION {
KDPC CustomDpc;
};
KeInitializeDpc(&pdx->CustomDpc,
(PKDEFERRED_ROUTINE) DpcRoutine, fdo);
Trong li gi ti KeInitializeDpc, i s th hai l a ch ca DPC thng l trong b
nh nonpaged, v i s th 3 l mt thng s ng cnh ty m s c gi ti DPC
thng l nh i s th 2 ca n..
yu cu mt li gi tr hon (deferred call ) ti mt DPC thng l ty bin, gi
KeInsertQueueDpc:
BOOLEAN inserted = KeInsertQueueDpc(&pdx->CustomDpc, arg1, arg2);
i s arg1 v arg2 l cc con tr ng cnh ty m s c chuyn ti DPC thng l
ty bin .Gi tr tr v l FALSE nu i tng DPC trong mt b x l i ri v
bng TRUE trong trng hp ngc li.
248/369
ResetDevice(pdx);
status = IoConnectInterrupt(...);
KeSynchronizeExecution(pdx->InterruptObject,
(PKSYNCHRONIZE_ROUTINE) SetupDevice, pdx);
return STATUS_SUCCESS;
}
iu ny c ngha l , chng ta vin dn mt th tc tr gip (ResetDevice) thit lp
li phn cng. Mt trong s nhng nhim v ResetDevice l trnh cho thit b khi
s sinh ra bt k ngt no trong mc c th. Sau chng ta gi IoConnectInterrupt
kt ni thit b ngt ti ISR ca mnh. Thm ch trc c khi IoConnectInterrupt tr li,
iu ny l c th cho cc thit b ca chng ta sn sinh ra mt ngt, v th bt k mi
th v trnh iu khin ca chng ta v phn cng phi sn sng i trc. Sau khi kt
ni ngt, chng ta vin dn th tc tr gip khc c tn l SetupDevice lp trnh cho
thit b lm vic theo cch m chng ta mun. chng ta phi ng b bc ny vi ISR
ca mnh bi v n s dng cng thanh ghi phn cng m ISR ca chng ta s s dng.
v chng ta khng mun mi kh nng ca vic gi cc lnh mu thun thit b. Li gi
SetupDevice l bc cui cng trong StartDevice ca PCI42 bi v tri li vi nhng g
ti ni vi cc bn trong chng 2 - PCI42 khng c ng k mi giao din thit
b v theo s khng th c kh nng thi im ny. t.
ResetDevice l mt ch nh thit b cao v c c nh sau:
VOID ResetDevice(PDEVICE_EXTENSION pdx)
{
249/369
PAGED_CODE();
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
if (!stack->Parameters.Read.Length)
{
StartNextPacket(&pdx->dqReadWrite, fdo);
CompleteRequest(Irp, STATUS_SUCCESS, 0);
return;
}
KeSynchronizeExecution(pdx->InterruptObject,
(PKSYNCHRONIZE_ROUTINE) TransferFirst, pdx);
}
1. y chng ta ghi li cc thng s trong phn m rng thit b m t tin
trnh vo ca mt thao tc u vo. Chng ta bo m PCI42 s dng phng thc
DO_BUFFERED_IO, l khng in hnh nhng n gip chng ta to ra trnh iu khin
n gin c s dng nh mt v d.
2. Bi v ngt ca chng ta c kt ni, thit b ca chng ta c th ngt bt k lc
no. ISR s mun truyn cc bytes d liu khi cc ngt xy ra, nhng chng ta mun
c m bo rng ISR khng bao gi b ln xn, rc ri v b m d liu s dng
hoc v s cc bytes chng ta ang c gng c. kim ch tnh hm ca ISR, chng
ta t mt c trong phn m rng thit b nh bn rn m thng thng l FALSE.
252/369
253/369
ULONG intcsr =
READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR));
if (!(intcsr & INTCSR_INTERRUPT_PENDING))
return FALSE;
BOOLEAN dpc = FALSE;
if (pdx->busy)
{
if (Irp->Cancel)
status = STATUS_CANCELLED;
else
status = AreRequestsBeingAborted(&pdx->dqReadWrite);
if (!NT_SUCCESS(status))
dpc = TRUE, pdx->nbytes = 0;
254/369
255/369
if (dpc)
{
pdx->busy = FALSE;
Irp->IoStatus.Status = status;
IoRequestDpc(pdx->DeviceObject, NULL, NULL);
}
return TRUE;
}
1. Nhim v u tin ca chng ta l khm ph xem liu rng thit b ring ca
chng ta by gi ang c gng ngt. chng ta c S5933s INTCSR v kim tra
mt bit (INTCSR_INTERRUPT_PENDING) m tm tt tt c cc l do,
nguyn nhn treo ca cc ngt. Nu nh bit ny b xa, chng ta s tr li ngay
lp tc. L do chng ta la chn s dng con tr m rng thit b nh mt i
s ng cnh routineback ny khi ti gi IoConnectInterruptby gi nn b
xa : chng ta cn truy cp ngay lp tc ti cu trc ny c c a ch
cng c s.
2. Khi chng ta s dng mt DEVQUEUE, chng ta da vo, tin tng vo i
tng hng i gi du vt ca IRP hin hnh. Ngt ny c th chng ta
khng mong i bi v thi im hin ti chng ta khng ang phc v
bt k IRp no. Trong trng hp , chng ta vn phi xa ngt nhng khng
nn lm lm bt k iu g khc.
3. Ngoi ra vn c th vi mt s kin Plug and Play hoc s kin ngun xy
ra m s to ra bt k IRP mi no b loi b bi th tc gi thng ip. Hm
AreRequestsBeingAborted ca DEVQUEUEs ni cho chng ta rng chng ta
c th abort (kt thc sm )yu cu hin hnh ngay by gi. Vic kt thc sm
256/369
4.
5.
6.
7.
8.
Testing PCI42
Nu nh bn mun kim tra PCI42 trong thao tc, bn cn phi lm mt vi vic. u
tin l tm kim v ci t mt board pht trin S5933DK1 bao gm card giao din
thm vo ISA (ISA add-in interface card). S dng Add Hardware wizard ci t
trnh iu khin S5933DK1.SYS v trnh iu khin PCI42.SYS. ( Ti pht hin rngI
Windows 98 ng nht thit lp board pht trin nh vic s khng chy sound cord v
ti phi g b n i trong Device Manager trc khi t c th tin hnh ci t PCI42
nh trnh iu khin cho n. Nhng Windows XP th lm vic bnh thng)
Sau chy c hai chng trnh ADDONSIM v TEST chng thuc cy th mc PCI42
trong ni dung sch hng dn. ADDONSIM ghi mt gi tr d liu ti mt mailbox
thng qua giao din ISA. TEST c mt byte d liu t PCI42. Vic quyt dnh gi tr
ca byte d liu l bi tp dnh cho cc bn.
258/369
259/369
Description
PutDmaAdapter
AllocateCommonBuffer
FreeCommonBuffer
AllocateAdapterChannel
FlushAdapterBuffers
FreeAdapterChannel
FreeMapRegisters
MapTransfer
GetDmaAlignment
ReadDmaCounter
GetScatterGatherList
PutScatterGatherList
260/369
261/369
PVOID vaddr;
PVOID regbase;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp)
{
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
264/369
pdx->vaddr = MmGetMdlVirtualAddress(mdl);
266/369
pdx->regbase = regbase;
PHYSICAL_ADDRESS address =
(*pdx->AdapterObject->DmaOperations->MapTransfer)
(pdx->AdapterObject, mdl, regbase, pdx->vaddr, pdx->xfer,
!isread);
return DeallocateObjectKeepRegisters;
}
1. Tham s th 2 ci m ti t tn l junk to AdapterControl is whatever(bt c
khi no) was in the CurrentIrp field of the device object khi m bn gi hm
AllocateAdapterChannel. Khi bn s dng DEVQUEUE cho hang i IRP, bn
cn phi yu cu i tng DEVQUEUE ci m l IRP hin ti. Nu bn s
dng hang i cc th tc ca Microsoft IoStartPacker & IoStartNextPacket
qunl hang i ca bn th junk s ng l mt IRP. Trong trng hp ny ti
s gi tn Irp thay th.
267/369
268/369
Mt ngt thng xut hin rt nhanh sau khi m chng ta bt u chuyn i.V th tc
ngt dch v lun lun yu cu mt DPC lin h vi s hon thnh ca phm vi u
tin ca chuyn i. Th tc DPC ca bnc th tng t nh sau:
VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo,
PIRP junk, PDEVICE_EXTENSION pdx)
{
(*pdx->AdapterObject->DmaOperations->FlushAdapterBuffers)
(pdx->AdapterObject, mdl, pdx->regbase, pdx->vaddr,
pdx->xfer, !isread);
pdx->nbytes -= pdx->xfer;
pdx->numxfer += pdx->xfer;
NTSTATUS status = STATUS_SUCCESS;
269/369
}
else
{
ULONG numxfer = pdx->numxfer;
(*pdx->AdapterObject->DmaOperations->FreeMapRegisters)
270/369
(pdx->AdapterObject, pdx->regbase,
pdx->nMapRegistersAllocated);
StartNextPacket(&pdx->dqReadWrite, fdo);
CompleteRequest(Irp, status, numxfer);
}
}
1. Khi bn s dng DEVQUEUE cho hng i IRP, bn tin tng vo i tng hng
i s gi ng i ca IRP hin thi.
2. Th tc FlushAdapterBuffer iu khin v tr trong chuyn i c yu cu s
dng cc vng m trung gian c s hu bi h thng. Nu nh bn thc hin mt
hnh ng input m ko di qua ranh gii ca trang th d liu vo nm vng m
trung gian v cn phi c copy vo vng m ch ngi dng.
3. y chng ta cp nht s d v s d liu cn li sau khi m phm vi chuyn i
hon tt.
4. Ti v tr ny, bn xc nh phm vi hin thi ca chuyn i c hon tt thnh
cng hoc c li xy ra. V d nh l bn c th c trng thi ca cng hay l xem
xt k kt qu ca mt hot ng tng t c thc hin bi th tc ngt ca bn.
trong v d ny, ti thit lp thuc tnh variable cho trng thi thnh cng (STATUSSUCCESS) vi s mong i rng bn thay i n nu tm ra li y.
5. Nu chuyn i ny khng dng li, bn cn phi lp trnh cho mt phm vi khc.
Bc u tin trong tin trnh ny l tnh ton a ch o ca v tr tip theo ca b m
ch ngi dng. Theo ti th vic tnh ton ny n thun ch l lm vic vi mt
s- thc t chng ta cha c gng truy cp vo b nh bng cch s dng a ch o
ny. Tt nhin, truy cp b nh c th l mt kin ti bi v chng ta ang thc hin
mt lung ng cnh tu bin.
6. Cc cu lnh tip theo hu nh y ht nh vic chng ta thc hin trong phm vi u
tin cho StartIo v AdapterControl. Kt qu cui cng s l mt a ch logic ci m c
th c lp trnh trong thit b ca bn. N c th ph hp hay khng ph hp vi a
ch vt l nh c hiu bi CPU. Mt li khuyn nh l chng ta b min cng ch
s dng s cc s thanh ghi nh l chng ta c php bi th tc iu khin iu
271/369
ExAllocatePool(NonPagedPool, sizeof(SCATTER_GATHER_LIST) +
MAXSG * sizeof(SCATTER_GATHER_ELEMENT));
Vi cc c s h tng ti v tr ny, th tuch AdapterControl ca bn s trng ging
nh l:
IO_ALLOCATION_ACTION AdapterControl(PDEVICE_OBJECT fdo,
PIRP junk, PVOID regbase, PDEVICE_EXTENSION pdx)
{
sglist->Elements[isg].Address =
(*pdx->AdapterObject->DmaOperations->MapTransfer)
(pdx->AdapterObject, mdl, regbase, pdx->vaddr,
&elen, !isread);
sglist->Elements[isg].Length = elen;
xfer -= elen;
pdx->xfer += elen;
vaddr = (PVOID) ((PUCHAR) vaddr + elen);
++isg;
}
sglist->NumberOfElements = isg;
return DeallocateObjectKeepRegisters;
}
1. Hy xem m t ban u ca cch ly mt con tr ti IRP ng trong th tc
iu khin iu hp
2. Trc chng ta tnh ton pdxxfer da vo s lng c cho php ca s
cc thanh ghi. By gi chng ta s c gng c th chuyn i c nhiu
274/369
3.
4.
5.
6.
7.
8.
275/369
276/369
dmachannel = resource->u.Dma.Channel;
dmaport = resource->u.Dma.Port;
break;
}
}
DEVICE_DESCRIPTION dd;
RtlZeroMemory(&dd, sizeof(dd));
dd.Version = DEVICE_DESCRIPTION_VERSION;
dd.InterfaceType = InterfaceTypeUndefined;
dd.MaximumLength = MAXTRANSFER;
dd.DmaChannel = dmachannel;
dd.DmaPort = dmaport;
277/369
dd.DemandMode = ??;
dd.AutoInitialize = ??;
dd.IgnoreCount = ??;
dd.DmaWidth = ??;
dd.DmaSpeed = ??;
pdx->AdapterObject = IoGetDmaAdapter(...);
}
1. Danh sch cc ngun ti nguyn vo/ra s c mt ti nguyn DMA, tnhng g
m bn cn trch ra knh v cc s hiu cng. S knh nh ngha mt trong
s cc knh c h tr bi mt h thng iu khin DMA. S hiu cng ch l
duy nht trong bus thit b MCA
2. Bt u t y, bn buc phi khi to mt s trng ca cu trc
DEVICE_DESCRIPTION da vo hiu bit ca bn v thit b ca bn. Hy
xem bng 7.5
Tt c mi iu v iu khin iu hp ca bn v cc th tc DPC s ging ht vi
on code m chng ta c xem xt phn u ca phn iu khin thit b busmastering khng c kh nng s cc thanh ghi ngoi tr hai chi tit nh. Th nht l,
adaptercontrol tr ra mt gi tr khc
IO_ALLOCATION_ACTION AdapterControl(...)
{
return KeepObject;
}
Gi tr tr ra KeepObject ch ra rng chng ta mun gi li iu khin thng qua s
cc thanh ghi v knh DMA chng ta ang s dng. Th hai l, t khi chng ta khng
gii phng i tng iu hp khi m AdapterControl c tr ra, chng ta phi lm
vic ny trong th tc DPC bi li gi FreeAdapterChannel thay v FreeMapRegister:
VOID DpcForIsr(...)
278/369
(*pdx->AdapterObject->DmaOperations->FreeAdapterChannel)
(pdx->AdapterObject);
}
S dng mt b m chung (Using a Common Buffer).
Bn thng ch nh b m chung ca bn ti thi im StartDevice sau khi to ra i
tng iu hp ca bn:
typedef struct _DEVICE_EXTENSION {
PVOID vaCommonBuffer;
PHYSICAL_ADDRESS paCommonBuffer;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
dd.Dma32BitAddresses = ??;
dd.Dma64BitAddresses = ??;
pdx->AdapterObject = IoGetDmaAdapter(...);
pdx->vaCommonBuffer =
(*pdx->AdapterObject->DmaOperations->AllocateCommonBuffer)
(pdx->AdapterObject, <length>, &pdx->paCommonBuffer, FALSE);
279/369
280/369
281/369
Th tc ci t thanh ghi hot ng S5933 cho chuyn giao DMA v sau chuyn giao
bt u chy . Cc Bc ca qu trnh nh sau :
1. a ch chng trnh ( MxAR ) v tng s chuyn giao (MxTC) thanh ghi thch hp
nh hng cho lung d liu . AMCC c chn cho gii hn c miu t hot
ng truyn d liu ra thit b . Bi vy khi chng ta thc hin y IRP_MJ_WRITE,
chng trnh s c hot ng ti chip level . a ch chng ta sa dng l a ch logic
c quay tr li bi MapTransfer.
2. Cho php mt ngt khi m s chuyn i dn ti 0 bi vic vit Intcsr
1. Bt u s chuyn i bng cch thit lp mt bt cho php chuyn i trong
MCSR.
on code ny khng c r rng cho lm, nhng S5933 l mt kh nng thc t ca
vic mt DMA c v mt DMA vit ti cng mt thi im. Ti vit PKTdma
theo cch ch vi mt hot ng (hoc l c hoc l vit) c th xy ra. khi
qut ho trnh iu khin cho php c hai loi hot ng xy ra ng thi, bn cn
ti phng tin tch cc hng i cho vic c v ghi IRP v to ra hai i tng
thit b v hai i tng iu hp- mt cp c v cp cn li vit. trnh tnh
trng lng tng ca vic c gng i gp i cc i tng ging nhau bn trong
AllocateAdapterChannel. Ti ngh rng vic thm s phc tp vo trong v d mu s
gy kh khn cho bn. (ti bit rng ti cm thy lc quan v k nng m t hm
rng ti khng lm cho bn thy ln ln, nhng n c th s ti t hn)
iu khin cc ngt trong PKTDMA
PCI42 bao gm mt th tc ngt ci m thc hin mt bit nh ca cng vic di
chuyn d liu. Th tc ngt ca PKTDMA th n gin hn.
BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject,
PDEVICE_EXTENSION pdx)
{
ULONG intcsr =
READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR));
if (!(intcsr & INTCSR_INTERRUPT_PENDING))
return FALSE;
282/369
284/369
Nu
bn
ang
s
dng
GENERIC.SYS,
li
gi
n
gin
GenericGetSystemAddressForMdl, ci m cha nhng iu ni on code trn. Ti
khng c gng thm vo MnMapLockedPagesSpecifyCache ti WDMSTUB.SYS
(xem phc lc A) bi v Windows 98/ME khng cung cp cc b phn cn thit h
tr hon ton cho hm ny.
285/369
<error>
CloseHandle(Handle);
Nhng c i s ti CreateFile cng l FILE_FLAG_OVERLAPPED hay 0 ch
ra bn s biu din c hay khng s hot ng d b vi knh iu khin tp tin
ny. Trong khi bn c knh iu khin m, bn c th lm nhng s gi ti ReadFile,
WriteFile, hay DeviceIoControl. Hoc khi no bn truy cp thit b, bn cn phi ng
dt khot knh iu khin bng vic gi l CloseHandle.Phi hng vo trong tm
tr, th nhng, h iu hnh t ng ng bt k knh iu khin no m c
m v pha tri khi qu trnh (ca) cc bn hon thnh. Code (DWORD) i s ti
DeviceIoControl l mt m iu khin m ch bo thao tc iu khin (php ton kim
tra) bn mun thc hin. Ti s bn lun v vic bn nh ngha nhng m ny hi
xa hn nh th no trn (in Defining I/O Control Codes). InputData (PVOID) v
InputLength (DWORD) nhng i sm t mt vng d liu m bn gi ti trnh iu
khin thit b. (Ngha l, d liu ny c nhp vo t phi cnh (ca) trnh iu khin.).
The OutputData (PVOID) and OutputLength (DWORD) nhng i sm t mt vng
d liu m trnh iu khin c th hon ton hay tng phn lm y thng tin m
n mun nhn quay tr li cho bn. (Ngha l, d liu ny l u ra t phi cnh (ca)
286/369
287/369
288/369
290/369
Description
OutputBufferLength
InputBufferLength
IoControlCode
Type3InputBuffer
Mt chc nng lin lc thuc v b xng cho nhng thao tc iu khin (php ton
kim tra) ging nh th ny:
#pragma PAGEDCODE
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp)
{
1->
PAGED_CODE();
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
291/369
ULONG info = 0;
2->
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG cbin =
stack->Parameters.DeviceIoControl.InputBufferLength;
ULONG cbout =
stack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG code =
stack->Parameters.DeviceIoControl.IoControlCode;
switch (code)
{
3->
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return CompleteRequest(Irp, status, info);
}
1. Bn c th tin chc c gh thm PASSIVE_LEVEL, nh vy khng c l do
c bit cho mt s lin lc n gin vn hnh l bt c ni u nhng nh s trang
k c.
2. Vi s pht biu tip theo rt m chc nng v nhng kch thc vng m t lin
hip nhng tham s trong chng vo/ra. Bn thng cn nhng gi tr ny khng c vn
IOCTL c bit no m bn x l, v vy Ti lun lun tm thy d dng hn nhng
s pht biu ny trong chc nng
292/369
293/369
294/369
295/369
{
case IOCTL_GET_VERSION:
case IOCTL_INTERNAL_GET_SECRET:
// <== exposed for user-mode calls
}
}
Nu mt ng dng c th bng cch no xc nh gi tr s ca
IOCTL_INTERNAL_GET_SECRET, n c th pht hnh mt s gi DeviceIoControl
bnh thng v i vng an ton d nh trn chc nng .
296/369
298/369
CompleteRequest(pdx->NotifyIrp,
STATUS_SUCCESS, 0); // <== don't do this!
}
" Nhng s xem xt khc " Ti thy ng nh vy tin li gp li di Thm, tt
nhin, ht sc quan trng crafting mt trnh iu khin ch lm vic.
B khi u (ca) IRP c l quyt nh hy b n. ng dng c l gi l CancelIo,
hay im tn cng (ca) lung ng dng c l gy ra mt thnh phn kiu nhn gi
l IoCancelIrp. Trong mi trng hp, chng ti phi cung cp mt s hy b thng
l IRP c hon thnh. Phi chng sc mnh c loi b t thit b (ca) chng
ta, hoc Nu thit b (ca) chng ta c loi b thnh lnh t my tnh, chng ti c
th mun lm sy (hng) bt k yu cu IOCTL ni bt no. Ni chung, bt k s
lng IOCTLs no c l cn sa sy. Vy th, Chng ti s cn mt bn k lin kt
ca chng. T nhng lung c l ang th truy nhp bn k lin kt ny, chng
ti cng s cn mt s kha quay trn chng ti c th truy nhp danh sch an ton.
Helper Routines
n gin ha cuc sng (ca) ring mnh, Ti vit mt s ng cng (ca) ngi
gip nhng th tc qun l IOCTLs khng ng b. Hai th Quan trng nht ca
nhng th tc ny c tn CacheControlRequest v UncacheControlRequest. H gi thit
iu bn s chp nhn ch c mt IOCTL khng ng b c mt m iu khin c bit
trn thit b phn i v m bn c th, bi vy, d tr mt con tr trong m rng
thit b ch ti IRP iu hin thi ni bt. Trong NOTIFY, Ti gi l con tr
NotifyIrp ny. Bn chp nhn IRP khng ng b cch ny:
switch (code)
{
case IOCTL_WAIT_NOTIFY:
if (<parameters invalid in some way>)
status = STATUS_INVALID_PARAMETER;
else
status = CacheControlRequest(pdx, Irp, &pdx->NotifyIrp);
break;
299/369
}
return status == STATUS_PENDING ? status :
CompleteRequest(Irp, status, info);
S pht biu quan trng y l s gi ti CacheControlRequest, nhng s ng k
IRP ny trong mt cch m chng ti s c kh nng hy b n sau nu cn thit.
N cng ghi a ch (ca) IRP ny trong thnh vin NotifyIrp (ca) m rng thit b
(ca) chng ta. Chng ti ch i n tr li STATUS_PENDING, ti trng hp no
chng ti trnh hon thnh IRP v n gin tr li STATUS_PENDING cho ngi gi
(ca) chng ta.
NOTE Bn c th d dng khi qut ha s Ti m t cho php mt ng dng
c mt IRP (ca) mi kiu ni bt (cho) mi iu khin m. Thay v vic mang
nhng con tr IRP hin thi vo m rng thit b (ca) cc bn, t chng vo trong
mt cu trc m bn thy lin quan n FILE_OBJECT m tng ng ti iu khin .
Bn s a mt con tr ti FILE_OBJECT ny trong s nh v (v tr) chng I/O (cho)
IRP_MJ_CREATE, IRP_MJ_CLOSE, v, tht ra, tt c IRPs khc sinh ra (cho) iu
khin h s. Bn c th s dng mi FsContext hay lnh vc i tng h s (cho) bt
k (ci) no FsContext2 Bn d nh chn.
Later , khi s kin no ng dng ang i cho xut hin, chng ti thc hin m nh
iu ny
PIRP nfyirp = UncacheControlRequest(pdx, &pdx->NotifyIrp);if (nfyirp)
{
<do something>
CompleteRequest(nfyirp, STATUS_SUCCESS, <info value>);
}
Lgic ny khi phc a ch (ca) yu cu IOCTL_WAIT_NOTIFY ang xem xt, m
ci g cung cp d liu quay tr li ng dng, v sau hon thnh gi yu cu I/
O ang xem xt.
bin i trn k thut Chng ti tranh lun ni khc trong sch an ton xp hng v
ra khi hng IRPs i khi mt ngi khc c l ang di ch v vic th hy b
IRP. Ti tht s ng gi nhng th tc ny trong GENERIC.SYS, and mu NOTIFY
trong ni dung hng dn ch ra lm sao gi chng. Heres how those functions work
(but note that the GENERIC.SYS versions have Generic in their names):
typedef struct _DEVICE_EXTENSION {
KSPIN_LOCK IoctlListLock;
LIST_ENTRY PendingIoctlList;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS CacheControlRequest(PDEVICE_EXTENSION pdx, PIRP Irp,
PIRP* pIrp)
{
KIRQL oldirql;
KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql);
NTSTATUS status;
if (*pIrp)
status = STATUS_UNSUCCESSFUL;
else if (pdx->IoctlAbortStatus)
status = pdx->IoctlAbortStatus;
else
{
IoSetCancelRoutine(Irp, OnCancelPendingIoctl);
if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
status = STATUS_CANCELLED;
301/369
else
{
IoMarkIrpPending(Irp);
status = STATUS_PENDING;
Irp->Tail.Overlay.DriverContext[0] = pIrp;
*pIrp = Irp;
InsertTailList(&pdx->PendingIoctlList,
&Irp->Tail.Overlay.ListEntry);
}
}
KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
return status;
}
VOID OnCancelPendingIoctl(PDEVICE_OBJECT fdo, PIRP Irp)
{
KIRQL oldirql = Irp->CancelIrql;
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
KeAcquireSpinLockAtDpcLevel(&pdx->IoctlListLock);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
PIRP pIrp = (PIRP) Irp->Tail.Overlay.DriverContext[0];
302/369
303/369
1. Chng ti s dng mt s kha quay trn bo v danh sch (ca) IOCTLs ang xem
xt v cng bo v tt c cc con tr m c d tr tr vo th hin hin thi ca
mi yu cu kiu IOCTL khng ng b khc nhau
2. iu ny l ni chng ta Gim st vic thi hnh quy tc-n l ca mt quyt nh thit
k na, tht s-ch c mt IRP (ca) mi kiu c th (th) ni bt ti mt thi gian
3. iu ny nu s pht biu iu tit thc t m chng ti c th cn bt u b qun
u vo IRPs ti im no bi v PnP hay nhng s kin sc mnh.
4. T Chng ti ni vo cui ui IRP ny ci g c l l mt thi gian di, chng
ti cn phi c mt s hy b thng l (cho) n. Ti bn lun lgic hy b rt nhiu
thi gian trong sch ny m Ti cm thy chc chn bn khng kh hn khi c v n
mt ln na.
5. y Chng ti c gii quyt tin ln v cc IRP ny v th m chng ti c
th hon thnh n sau . T Chng ti i n kt lun tr li STATUS_PENDING
t chc nng DispatchControl (ca) chng ta, chng ti cn gi l IoMarkIrpPending.
6. Chng ti cn c mt cch ti NULL ngoi con tr b m khi Chng ti
hy b IRP. T khng c cch c mt tham s vn cnh chuyn cho s
hy b thng l (ca) chng ta , Ti quyt nh kt np mt trong nhng lnh vc
DriverContext trong IRP gi mt con tr ti con tr b m.
7. Trong kha hc bnh thng (ca) nhng s kin, pht biu uncaches l mt IRP.
8. By gi c iu l Chng ti khng c vng nh m IRP ca chng ti, chng ti
khng mun n cancelled bt k (ci) no na. Nu IoSetCancelRoutine tr li NULL
,tuy nhin, chng ti bit IRP ny hin thi trong qu trnh (ca) cancelled.Chng ti tr
li mt con tr NULLIRP trong trng hp .
NOTIFY cng C mt trnh iu khin IRP_MJ_CLEANUP v vic xem xt IOCTLs
m trng th ch ging nh nhng trnh iu khin cleanup Ti tranh lun v
vic c v vit nhng thao tc. Cui cng, n bao gm mt chc nng gip
AbortPendingIoctls trong vic s dng ti thi gian ngt in hay thi gian di chuyn
bt ng, nh sau:
VOID AbortPendingIoctls(PDEVICE_EXTENSION pdx, NTSTATUS status)
{
InterlockedExchange(&pdx->IoctlAbortStatus, status);
CleanupControlRequests(pdx, status, NULL);
304/369
}
CleanupControlRequests l trnh iu khin IRP_MJ_CLEANUP. Ti vit n theo mt
cch m n hy b tt c IRPs ng ch nu i sth ba-bnh thng mt con tr i
tng tp tin l NULL .
NOTIFY hi qu n gin c dng lm mt m hnh y (cho) mt trnh iu
khin th gii- thc s. y l mt s s xem xt b sung (cho) bn tham kho
trong qu trnh thit k (ca) ring mnh:
_Trnh iu khin c l c vi kiu nhng s kin m thc y thng bo. Bn
c th quyt nh tha thun Vi chng bng cch s dng mt m IOCTL n, trong
trng hp no bn ch bo nhng m IOCTL kiu s kin bi loi no (ca) d liu
ra, hay bng cch s dng nhiu.
_Bn c l mun cho php nhiu lung ng k (cho) s kin. Nu m trng hp,
bn chc chn c mt con tr IRP n trong m rng thit b- bn cn mt cch theo di
tt c IRPs m lin quan ti mt kiu c bit (ca) s kin. Nu bn ch s dng mt
kiu n ca IOCTL (cho) tt c cc thng bo, mt cch kim tra l chng xp hng
trn PendingIoctlList c ch ra trc . Ri, khi mt s kin xut hin, bn thc hin
mt vng m trong bn gi ExInterlockedRemoveHeadList v IoCompleteRequestto
lm trng rng danh sch ang xem xt. (Ti trnh s phc tp ny trong NOTIFY bi
mnh lnh-Ti quyt nh Ti ch chy c mt chng trnh th ti mt thi im.) _S
lin lc IOCTL (ca) Cc bn thng l c trong mt cuc ua vi hot ng m pht
sinh nhng s kin. Chng hn, trong mu USBINT Ti tranh lun trong Chng 12,
chng ti c mt cuc ua tim tng gia th tc lin lc IOCTL v pseudointerrupt
thng l m dch v mt ngt endpoint trn mt thit b USB. Ti vic trnh mt nhng
s kin hay cm ly nhng hot ng mu thun, bn cn mt s kha quay trn. Tham
chiu ti mu USBINT trong ni dung (cho) mt s minh ha ca vic s dng s kha
quay trn nh th no ph hp. (ng b ha khng chy ra trong NOTIFY bi v bng
thi gian mt con ngi (th) c th thc hin nhn phm m th s kin bo hiu, yu
cu thng bo gn nh chc chn ang xem xt. Nu khng phi, yu cu tn hiu c
mt li.).
305/369
Bi 2.
Vit driver cho ng dng Plug and Play, ng dng : pht hin ra thit b USB khi cn
USB vo my tnh. a ra thng bo c thit b USB-KTMT
306/369
2001
2000
1998
1997
307/369
1996
1995
Intel gii thiu USB silic u tin. USBIF c 340 thnh vin.
1994
10 nm qua chng kin s hnh thnh v pht trin mt cng ngh truyn dn c
tn gi hin tr thnh rt i quen thuc trong gii truyn thng l kt ni USB
(Universal Serial Bus). Trong nhng nm u tin ra mt, nhiu ngi cho rng USB
khng th tr thnh cng ngh dn u. Ngoi mc ch kt ni cc my tnh v cc
thit b thng tin v vin thng li vi nhau, loi hnh ny nay tr thnh phng tin
truyn dn ph thng nht kt ni thit b ch vi cc thit b ngoi vi, bao gm c
cc thit b in t gia dng. Ngay t khi ra i, USB ng mt vai tr quan trng
trong vic kt ni ca my tnh desktop v cc thit b ngoi vi.
Tiu s ca USB l mt cu chuyn di kh hp dn v c hu. Nm 1995, USB chnh
thc c mt nhm gm 7 hng vin thng, my tnh hng u th gii trnh lng, v
gi y, n tr thnh mt loi hnh kt ni ph qut nht khng ch c ng dng
trong lnh vc cng ngh thng tin m cn c s dng h tr kt ni cho cc thit
b vin thng v in t gia dng. Hin nay, USB tr thnh thn thuc n mc bn
c th d dng thy rng a s cc sn phm in t u c trang b kt ni ny.
Nhm gm 7 i gia tin c USB gia nhp th gii thit b truyn dn d liu
l Compaq, Digital Equipment Corporation (DEC), IBM, Intel, Microsoft, NEC v
Northern Telecom. T khi ra mt USB t cch y 10 nm, DEC b Compaq mua ri
li hp nht vi hng HP (Hewlett Packard). Ngy nay, Hip hi USB (USB-IF) 1.000
thnh vin c nh hng bi cc hng hng u nh Agere, Intel, HP, Microsoft,
NEC v Philips; v trong s ny ch cn li 3 trong 7 hng u cho a con chung
USB t lc khai sinh n gi.
Hng pht trin ca kt ni USB nhn theo logo (t di ln, bn phi sang).
308/369
Khng nh cc giao din kt ni song song (parallel), tun t (serial), PS/2 v cc cng
game thng thng, USB c kh nng thit lp mt loi kt ni ng nht cho tt c
cc thit b ngoi vi trang b USB n my tnh c nhn (PC). V mt l thuyt, ng
truyn n l ny li c th c thay th bng mt khi kt ni USB a cng lp ngoi
cho php ti 127 thit b ngoi vi c th ln lt ni vo mt cng USB n bn ngoi
nh cc HUB USB a cng.
Trong nhng ngy s khai, USB c cc hng u tin hnh th nghim kt ni cc
sn phm vi nhau, thi khc ny tr thnh s kin quan trng m nhng ngi thn
sinh ra USB gi mc s kin lch s ny l Ngy hi kt ni hay Plugfest. S khng
ai tng tng c cm gic ca nhng ngi chng kin i ng kim chng vin lc
, n t hn 50 cng ty thnh vin ca USB-IF trc tip n kim nghim, h h hi
i t phng ny sang phng khc ch chng thc tc phm diu k ny.
Sau , h phi mt 3 ngy cng nhau chnh thc kim th kt ni cc sn phm
USB mi nht vo h thng my ch trung tm. Lc , 10 thit b kt ni thnh cng
vi mt PC m khng h c trc trc hay xung t h thng, cc nh pht trin cng
ngh thc s c th n mng. Thm nhiu thit b khc c ni vi PC chy h iu
hnh Windows. Trong sut qu trnh th nghim, ngi ta thng k c c 127 thit
b kt ni thnh cng vi my tnh, tuy nhin trong s hu ht l chut dng cng
USB.
Biu trng (logo) ca USB qu quen thuc vi cc bn nh ngy nay cng ly i
nhiu thng ca cc n v khai sinh ra n.
Khng ch l kt ni
Ban u, cc nh sn xut PC hng u kh thn trng khng thay th ton b cc cng
ni vn c bng USB, tc l h s dng song song c loi hnh USB mi n v cc kt
ni c truyn. Nm 1998, Apple mnh dn gii thiu dng my tnh iMac, ln u tin
s dng tt c cc kt ni u l USB. H iMac G5 ngy nay cng ch bao gm ton cc
cng USB 2.0 (480 Mb/s) v cc cng Fi-Wi IEEE 1394, nhm h tr tt nht cc ng
dng tc cao.
309/369
nh USB 5 GB ca Seagate.
310/369
311/369
312/369
313/369
Thng thng cc my tnh hin nay ch c mt hoc hai khe cm USB (USB Socket).
Ngy nay vi a s cc thit b u s dng USB, my tnh rt d b thiu khe cm. V
d, trn my tnh c cc thit b nh: my in, my qut, Webcam, Network Connection
s dng USB trong khi my tnh ch c mt cng USB (USB Connector).
gii quyt vn ny, ch cn lp thm mt USB Hub. Chun USB h tr ti 127
thit b v USB Hub l mt trong s ny. Cc Hub ny thng c bn cng nhng cng
c th c nhiu hn tu thuc tng loi. Ch cn cm USB Hub vo my tnh sau cm
cc thit b hoc Hub khc vo cc cng trn USB Hub.
Hub c hai loi: loi c cung cp ngun v khng cung cp ngun in cho thit b cm
vo Hub. Chun USB cho php cc thit b s dng ngun in t cng USB. Cc thit
314/369
315/369
Cc thit b ni vi cng USB dng cp USB truyn ti dng in hay d liu. Khi
my tnh hot ng, n truy vn ti tt c cc thit b ni vo Bus v gn cho mi thit
b mt a ch. Qu trnh ny c gi l lit k cc thit b. My tnh cng s tm ra
cch truyn d liu ca tng thit b:
Interrupt: Cc thit b nh bn phm gi lng d liu rt nh v ngt on s
c chn kiu Interrupt Mode.
Bulk: Cc thit b nh my in thng nhn nhng gi d liu ln, dng kiu
Bulk Transfer Mode. Tng on d liu (64 Byte) c gi ti my in v c
kim tra tnh chnh xc.
Isochronous: Cc thit b truyn d liu theo dng Stream nh loa s dng
Isochronous Mode. D liu tc thi c truyn gia thit b v my tnh v
khng c c ch sa li.
My tnh cng c th gi i cc lnh hay truy vn cc thng s vi cc gi Control
Packet. Khi mt thit b c my tnh lit k, my tnh s ginh ti 90% bng thng
(Bandwidth) phc v cc yu cu ca cc thit b kiu Interrupt v Isochronous. Sau khi
dng 90% ca 480 Mbps bng thng, my tnh s t chi cc truy nhp ca bt k thit
b kiu Interrupt hay Isochronous no khc. Cc Control Packet v thit b kiu Bulk
Transfer s s dng khong 10% bng thng cn li.
USB phn chia bng thng thnh cc Frame v my tnh s iu khin cc Frame ny.
Mi Frame cha 1.500 Byte v Frame mi c sinh ra sau mi mili giy. Trong mt
Frame, cc thit b kiu Isochronous v Interrupt phn chia thnh cc khe nn chng
m bo c bng thng cn thit trong khi cc thit b Bulk Transfer v Control
Packet s dng phn bng thng cn li.
Chun USB2.0 xut hin vo thng T nm 2000 v c nng cp t USB1.1. USB2.0
cung cp thm bng thng cho cc ng dng Multimedia v lu tr c tc truyn d
liu ln gp 40 ln so vi USB1.1. vic chuyn t chun USB1.1 sang USB2.0 thun
tin cho c ngi s dng v nh sn xut, USB2.0 c thit k hon ton tng thch
v lm vic c vi cp cng nh cng ni ca thit b USB nguyn thu.
USB2.0 h tr ba ch truyn d liu: 1,5Mbps, 12Mbps v 480Mbps. Ngoi ra
USB2.0 h tr cc thit b bng thng thp nh bn phm v chut cng nh cc thit b
bng thng ln nh Webcam, my in, my qut nh v h thng lu tr.
316/369
Bi 2.
Thc hin truyn, nhn d liu qua cng USB.
317/369
318/369
319/369
320/369
322/369
324/369
mt cch kim tra dng giao tip "out of band" vi driver. Nu chng ti c
giao dch vi mt thit b thc t, do , driver s c mt bo co chn nh danh
mi u vo bo co m n c t in thoi.
325/369
327/369
328/369
329/369
return pdx->AddDeviceStatus;
return STATUS_SUCCESS;
}
VOID StopDevice(PDEVICE_OBJECT fdo, BOOLEAN oktouch)
{
}
HIDFAKE chnh n khng c m s ti cc im c nhn A, B, v C. Nu bn s dng
mu ny nh l mt mu cho minidriver ring ca bn, bn s vit m thc hin nh
sau: A. Xa cc bt k ngun ti nguyn (chng hn nh b nh, lookaside danh sch,
v nh vy trn) phn b AddDevice. HIDFAKE khng c ngun ti nguyn nh vy.
B. nh cu hnh cc thit b nh tho lun trong chng trc. HIDFAKE khng c
phn cng v do khng c g lm trong bc ny.
C. Deconfigure in thoi do reversing cc bc thc hin trong StartDevice. K t
HIDFAKE khng c g, khng c g trong StartDevice, n khng cn phi lm bt c
iu g y c hai.
DispatchPower goi
Bn ch r DispatchPower gi nh nu n l nhng thi quen cho dispatch
IRP_MJ_POWER, bng cch t mt yu t trong mng, driver ca i tng
MajorFunction bng. HIDCLASS cuc gi ca bn gi nh l mt subroutine trong khi
x l IRPs quyn lc ca nhiu loi. Trong a s trng hp, bn nn ch cn gi qua cc
IRP xung tip theo bng driver m khng thc hin bt k hnh ng v HIDCLASS
c tt c cc qun l ngun in h tr cn thit do cc thit b tiu biu (bao gm c
WAIT_WAKE h tr).
Nu bn t ra DevicesArePolled c FALSE trong cuc gi ca qu v
HidRegisterMinidriver, HIDCLASS s hy b cc ping-pong IRPs trc khi chuyn
tip mt my in yu cu lm gim sc mnh. Nu bn c mt cch n gin
piggybacked trn nhng IRPs gi yu cu thm xung PnP stack, do bn s khng
cn phi lo lng v vic hu b chng. Nu bn c b nh m IRPs n nhng ni no,
bn nn cung cp cho hy b mt thi quen.
Ch thch:
331/369
332/369
}
return PoCallDriver(LDO(fdo), Irp);
}
NTSTATUS PowerUpCompletionRoutine(PDEVICE_OBJECT fdo, PIRP Irp,
PDEVICE_EXTENSION pdx)
{
// TODO restore device context without blocking this thread
pdx->devpower = PowerDeviceD0;
return STATUS_SUCCESS;
}
1. Bn khng cn phi lm bt c iu g c bit vi bt k quyn lc IRP ngoi
tr mt SET_POWER cho mt thit b quyn lc nh nc.
2. Khi khi phc li quyn lc, bn ci t mt thi quen hon tt trc khi
chuyn tip cc IRP xung stack.
3. Khi xo b quyn lc, bn tit kim bi cnh bt k thng tin trc khi chuyn
tip cc IRP. i ph vi nhng kh nng c th thp hn HIDCLASS rng
sc mnh trong bc (v d, ln u tin sau D2 v D3), bn cng cn phi
theo di ca cc thit b hin quyn lc nh nc. Hay khng in thoi ca
bn c bi cnh thng tin tit kim, iu ny cng l thi gian hy b bt
k chi nhnh IRPs rng driver ca bn ban hnh, chm dt polling threads,
and so on. HIDCLASS bn s c gi in thoi ti khch sn
PASSIVE_LEVEL trong mt h thng si rng bn ang c cho php
chn nu cn thit trong khi thc hin cc nhim v.
4. Nh thng l, bn gi PoCallDriver chuyn tip cc IRP. Bn khng cn
phi gi PoStartNextPowerIrp v HIDCLASS lm nh vy.
5. Cc thng c gi l hon thnh ch sau khi hon thnh mt ti x xe but
t-D0 hot ng. in thoi ca bn c repowered, v bn c th o
ngc cc bc bn thc hin khi bn xo b quyn lc. K t khi bn ang c
kh nng chy t DISPATCH_LEVEL v trong mt si arbitrary, tuy nhin,
bn cn phi thc hin cc bc sau m khng ngn chn hin nay si.
DispatchInternalControl goi
Bn ch r DispatchInternalControl gi nh nu n l nhng thi quen cho dispatch
IRP_MJ_INTERNAL_DEVICE_CONTROL, bng cch t mt yu t trong mng,
333/369
334/369
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
USHORT Reserved[11];
} HID_DEVICE_ATTRIBUTES, * PHID_DEVICE_ATTRIBUTES;
V d, bn c th hon tt cc c cu trong bi cnh ca cc skeletal
DispatchInternalControl hin th sm hn thng l:
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
{
if (cbout < sizeof(HID_DEVICE_ATTRIBUTES))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define p ((PHID_DEVICE_ATTRIBUTES) buffer)
RtlZeroMemory(p, sizeof(HID_DEVICE_ATTRIBUTES));
p->Size = sizeof(HID_DEVICE_ATTRIBUTES);
p->VendorID = 0;
p->ProductID = 0;
p->VersionNumber = 1;
#undef p
info = sizeof(HID_DEVICE_ATTRIBUTES);
335/369
break;
}
Nu in thoi ca bn l nonstandard ch n gin l mt thit b USB, iu r rng
cc gi tr m bn nn cung cp cho cc VendorID, ProductID, v VersionNumber lnh
vc ny c cu: cc idVendor, idProduct, bcdDevice lnh vc v thc s t in thoi
descriptor. Nu in thoi ca bn isn'ta thit b USB, bn cn phi i ln vi dummy
gi tr. Ti s dng 0, 0, v 1, tng ng, trong m ny fragment, v nhng s la
chn s cho tt c cc loi hnh HID thit b ngoi tr mt phm iu khin. c
mt phm iu khin in thoi, bn cn phi chn duy nht gi tr ph hp vi nhng g
bn ch nh trong ng k subkey OEM bn to ra cho cc phm iu khin. Ti khng
c t vn v vic lm th no chn nhng gi tr.
M ra mt b su tp giu trong ch Thnh vin
M ra mt b su tp HID x l cc thnh vin trong ch chnh n l n
gin nu bn ch nh duy nht gi tr cho cc VendorID v ProductID lnh vc
ca HID_DEVICE_ATTRIBUTES c cu. Gi, v d, cc cng ty ca bn s hu
USB bn hng rong ID 0x1234 v rng bn c giao cho 0x5678 ID sn phm
in thoi ca bn. Bn s s dng nhng gi tr khi tr li cu
IOCTL_HID_GET_DEVICE_ATTRIBUTES yu cu.
MFC l mt ng dng s dng cc lp hc CDeviceList cp n trong Chng 2 c
th m ra mt x l mt trong nhng b su tp driver ca bn bng cch tip xc
vi cc m nh sau y (xem cc chng trnh TEST HIDFAKE mu i km vi trnh
iu khin):
HANDLE CtestDlg::FindFakeDevice()
{
GUID hidguid;
HidD_GetHidGuid(&hidguid);
CDeviceList devlist(hidguid);
int ndevices = devlist.Initialize();
for (int i = 0; i < ndevices; ++i)
{
336/369
HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
FILE_SHARE_READ FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
continue;
HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
BOOLEAN okay = HidD_GetAttributes(h, &attr);
CloseHandle(h);
if (!okay)
continue;
if (attr.VendorID != HIDFAKE_VID
attr.ProductID != HIDFAKE_PID)
continue;
return CreateFile(devlist.m_list[i].m_linkname,
GENERIC_READ GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
}
return INVALID_HANDLE_VALUE;
}
1. HidD_GetHidGuid s dng xc nh giao din ton cu nhn bit duy nht
(GUID) cho cc thit b HID.
2. Chng ti enumerate tt c cc thit b HID. Trong thc t, cc Enumeration
khng bao gm cc thit b tiu chun, nh con chut v bn phm.
3. M ra mt cch x l ny (m khng c quyn truy cp y quyn v cho
php chia s) cho php chng ti vn truy vn. Khng ging nh hu ht cc
337/369
338/369
} DescriptorList [1];
} HID_DESCRIPTOR, * PHID_DESCRIPTOR;
Mc d, r rng tng qut ca cu trc ny, hin nay HIDCLASS tr y cc
khng gian cho ch c mt yu t trong DescriptorList mng, v n phi c bo co
descriptor. Pht trin ca Microsoft khuyn bn nn kim tra cng tc song le kch c
ca sn lng buffer v sp xp m ca bn sao chp thm no descriptors-nh l
mt vt cht descriptor-rng bn c th c.
Cng vic ca bn trong minidriver l in trong c cu descriptor nh nu bn l
mt USB-HID thit b tiu chun. V d:
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
{
#define p ((PHID_DESCRIPTOR) buffer)
if (cbout < sizeof(HID_DESCRIPTOR))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlZeroMemory(p, sizeof(HID_DESCRIPTOR));
p->bLength = sizeof(HID_DESCRIPTOR);
p->bDescriptorType = HID_HID_DESCRIPTOR_TYPE;
p->bcdHID = HID_REVISION;
p->bCountry = 0;
p->bNumDescriptors = 1;
p->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE;
p->DescriptorList[0].wReportLength = sizeof(ReportDescriptor);
339/369
#undef p
info = sizeof(HID_DESCRIPTOR);
break;
}
Cc ch kha cnh ca m ny l khng c c t mt trong cng mt iu khin
tip theo l chiu di bn ch nh cho cc wReportLength thnh vin ca n
DescriptorList mc m bn cung cp. Gi tr ny nn l chiu di no thc s hay
dummy bo co descriptor bn s cung cp, p ng yu cu
IOCTL_HID_GET_REPORT_DESCRIPTOR.
Ch thch:
HIDCLASS gi mt yu cu IOCTL_HID_GET_REPORT_DESCRIPTOR l mt
phn ca cc ch bin ca IRP_MN_START_DEVICE yu cu v conceivably, vo
nhng thi gian khc, c c mt USB-HID tiu chun bo co descriptor.
UserBuffer cc lnh vc ca IRP im n nh l mt buffer ln nh bn ch nh s l
cn thit tr li ca bn trong mt IOCTL_HID_GET_DEVICE_DESCRIPTOR yu
cu.
Gi s bn c mt d liu tnh khu vc c tn ReportDescriptor c cha mt bo co
descriptor nh dng chun. Bn c th x l yu cu ny theo cch ny:
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
{
if (cbout < sizeof(ReportDescriptor))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(buffer, ReportDescriptor,
sizeof(ReportDescriptor));
340/369
info = sizeof(ReportDescriptor);
break;
}
Bc u tin ca bn trong vic xy dng cc bo co descriptor c thit k b
tr cc bo co. USB HID c im k thut cho cc thit b lm cho n c v rng bn
ang kh nhiu thit k min ph cho bt k loi bo co bn mun, vi cc Windows s
thc hin rng con s no ch ra nhng g lm vi cc d liu kt qu. Trong kinh
nghim ca ti, tuy nhin, bn tht s khng c t do. Mt trong nhng la chn no
khi bn tit kim trong cng vic ca bn HID Cng c l to ra mt C-ngn ng tiu
tp tin, nh th ny mt (tng ng vi cc descriptor hin th trong Hnh 13-3):
char ReportDescriptor[64] = {
0x05, 0x05, // USAGE_PAGE (Gaming Controls)
0x09, 0x03, // USAGE (Gun Device )
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x01, //
REPORT_ID (1)
0x05, 0x09, //
USAGE_PAGE (Button)
0x09, 0x01, //
USAGE (Button 1)
0x15, 0x00, //
LOGICAL_MINIMUM (0)
0x25, 0x01, //
LOGICAL_MAXIMUM (1)
0x75, 0x01, //
REPORT_SIZE (1)
0x95, 0x01, //
REPORT_COUNT (1)
0x81, 0x02, //
INPUT (Data,Var,Abs)
0x75, 0x07, //
REPORT_SIZE (7)
0x81, 0x03, //
INPUT (Cnst,Var,Abs)
341/369
0xc0,
// END_COLLECTION
REPORT_ID (2)
0x05, 0x01, //
0x09, 0x30, //
USAGE (X)
0x25, 0xff, //
LOGICAL_MAXIMUM (-1)
0x75, 0x20, //
REPORT_SIZE (32)
0xb1, 0x02, //
FEATURE (Data,Var,Abs)
0xc0,
// END_COLLECTION
REPORT_ID (3)
0x05, 0x09, //
USAGE_PAGE (Button)
0x09, 0x01, //
USAGE (Button 1)
0x25, 0x01, //
LOGICAL_MAXIMUM (1)
0x75, 0x01, //
REPORT_SIZE (1)
0xb1, 0x02, //
FEATURE (Data,Var,Abs)
0x75, 0x07, //
REPORT_SIZE (7)
0xb1, 0x03, //
FEATURE (Cnst,Var,Abs)
0xc0,
// END_COLLECTION
0xc0
// END_COLLECTION
};
Bn c th ch n gin ny bao gm cc tp tin tiu ca bn trong trnh iu khin
xc nh ReportDescriptor bn tr v t IOCTL_HID_GET_REPORT_DESCRIPTOR.
342/369
343/369
case IOCTL_HID_READ_REPORT:
{
if (cbout < <size of report>)
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
<obtain report data>
RtlCopyMemory(buffer, <report>, <size of report>);
info = <size of report>;
break;
}
Ghi nh rng nu bo co ca bn descriptor bao gm nhiu hn mt bo co, bo
co d liu bn quay tr li HIDCLASS bt u vi mt 1-byte bo co nh danh.
IOCTL_HID_WRITE_REPORT HIDCLASS vn IOCTL_HID_WRITE_REPORT
cc yu cu v dch v IRP_MJ_WRITE v IOCTL_HID_SET_OUTPUT_REPORT
yu cu cp t mt thnh phn cp cao hn, chng hn nh mt ngi s dng-p dng
ch m cc cuc gi WriteFile, HidD_SetOutputReport, hoc IDirectInputDevice8::
SendDeviceData.
Sn lng cc bo co thng c s dng thit lp ch s cc loi, chng hn nh
LEDs v hin th bng iu khin. Cng vic ca bn trong mt minidriver l truyn
ti d liu bo co cc sn lng in thoi hoc n m phng hot ng ca mt
thit b HID nhn c mt bo co nh vy c ngha l do mt s. Thit b USB thc
hin cc lp hc c th kim sot-ng lnh Set_Report_Request (hoc ngi no khc
m h xc nh mt gin on-out endpoint) cho sn lng nhn c bo co, nhng
kin trc ca bn c th gi cho mt cch tip cn khc nhau.
Khng ging nh cc hot ng kim sot ni b HIDCLASS,
IOCTL_HID_WRITE_REPORT s dng METHOD_BUFFERED. iu ny c ngha
l cc lnh vc AssociatedIrp.SystemBuffer ca IRP cha cc a ch ca ngi sn
344/369
345/369
346/369
break;
#undef p
}
case IOCTL_HID_SET_FEATURE:
{
#define p ((PHID_XFER_PACKET) buffer)
switch (p->reportId)
{
case FEATURE_CODE_YY:
if (p->reportBufferLen > sizeof(FEATURE_REPORT_YY))
{
status = STATUS_INVALID_PARAMETER;
break;
}
RtlCopyMemory(FeatureReportYy, p->reportBuffer,
p->reportBufferLen);
break;
}
break;
#undef p
}
6.2.3. V d:
347/369
case IOCTL_GET_PHYSICAL_DESCRIPTOR:
{
if (cbout < sizeof(PhysicalDescriptor))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
PUCHAR p =
(PUCHAR) MmGetSystemAddressForMdlSafe(Irp->MdlAddress);
if (!p)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory(p,
PhysicalDescriptor, sizeof(PhysicalDescriptor));
info = sizeof(PhysicalDescriptor);
break;
}
Lu rng IOCTL
METHOD_NEITHER.
ny
dng
METHOD_OUT_DIRECT
thay
348/369
349/369
break;
}
if (!string)
{
status = STATUS_INVALID_PARAMETER;
break;
}
ULONG lstring = wcslen(string);
if (cbout < lstring * sizeof(WCHAR))
{
status = STATUS_INVALID_BUFFER_SIZE;
break;
}
RtlCopyMemory(buffer, string, lstring * sizeof(WCHAR));
info = lstring * sizeof(WCHAR);
if (cbout >= info + sizeof(WCHAR))
{
((PWCHAR) buffer)[lstring] = UNICODE_NULL;
info += sizeof(WCHAR);
}
break;
}
350/369
351/369
IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST HIDCLASS gi mt
IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST sc mnh xung mt
thit b nhn ri. Vi mt thit b USB thc t, yu cu ny dovetails vi cc tnh nng
USB chn la tm ngng tho lun trong chng trc.
Cc u vo m cho METHOD_NEITHER yu cu ny l mt d ca cc cu trc sau
y:
typedef struct _HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO {
HID_SEND_IDLE_CALLBACK IdleCallback;
PVOID IdleContext;
} HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO,
*PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO;
where HID_SEND_IDLE_CALLBACK is declared as follows:
typedef void (*HID_IDLE_CALLBACK)(PVOID Context);
Lu rng cu trc ny l ging ht nhau trong b tr v ngha cho mt USB c s
dng vi chn la treo. Trong thc t, xy ra, nu in thoi ca bn phi l mt thit
b USB, bn c th ch cn chuyn IRP xung stack sau khi thay i chc nng m:
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
{
IoCopyCurrentIrpStackLocationToNext(Irp);
stack = IoGetNextIrpStackLocation(Irp);
stack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
Nu in thoi ca bn khng phi l mt thit b USB, tuy nhin, bn nn gi li ngay
HIDCLASS v hon tt cc IRP, nh c hin th y
352/369
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
{
PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO p =
(PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)
stack->Parameters.DeviceIoControl.Type3InputBuffer;
(*p->IdleCallback)(p->IdleContext);
break;
}
HIDCLASS gi li cho rng n c th ngay lp tc sc mnh ca thit b xung.
353/369
Bi 2.
To cho mnh mt driver nh v HID.
354/369
Bi 2.
Lp trnh cng LPT.
Bi 3.
Lp trnh USB
Bi 4.
Cc x l IRP
Bi 5.
Cc gi tin I/O
Bi 6.
iu khin cho thit b HID
355/369
356/369
MC LC
Lp trnh h thng: Mc lc
Bi 1: TNG QUAN V LP TRNH H THNG 1
1.1 Khi nim v lp trnh h thng 1
1.2 Tng quan 1
1.3 Lch s 1
1.4 Cu trc tng quan lp trnh h thng 2
Bi 2: CNG C LP TRNH H THNG 2
2.1 Cc ngn ng lp trnh 2
2.2 Gii thiu v C++ 3
2.3 Gii thiu v Visual C++ 5
2.4 Giao bi tp ln nghin cu v C++ v Visual C++ 9
Bi 3: Thc hnh mt s bi tp c bn trn C++ 9
Bi 4: C BN V CU TRC V DRIVER 10
4.1 Tm lc lch s cc b iu khin thit b 10
4.2 Tng quan v cc H iu hnh 13
4.3 Cc kiu Driver 14
4.4 Tng quan v qun l v kim tra danh sch 18
Bi 5: Thc hnh mt s bi tp c bn trn VC++ 19
Bi 6: CC K THUT LP TRNH C BN 20
6.1 Mi trng lp trnh Kernel mode 20
357/369
6.2 X l li 21
6.3 Qun l b nh 33
6.4 X l chui 44
6.5 Mt s k thut lp trnh khc 44
Bi 7: Thc hnh mt s bi tp c bn trn VC++ 55
Bi 8: LP TRNH GIAO TIP QUA CNG LPT 56
8.1 Gii thiu cng LPT 56
8.2 Cu trc cng LPT 56
8.3 Lp trnh cho cng LPT 59
Bi 9: Thc hnh vi cc chng trnh giao tip qua cng LPT 60
Bi 10: Thc hnh vi cc chng trnh giao tip qua cng COM 60
10.1 Gii thiu cng COM 60
10.2 Cu trc cng COM 60
10.3 Lp trnh cho cng COM 63
Bi 11: Thc hnh vi cc chng trnh giao tip qua cng COM 64
Bi 12: VN NG B 64
12.1 Gii thiu v vn ng b 64
12.2 Mc yu cu Ngt 66
12.3 Kha xoay vng 69
12.4 Cc i tng Kernel Dispatcher 71
12.5 Mt s phng php ng b khc 82
Bi 13: Thc hnh lp trnh driver c bn 90
358/369
Bi 14: GI D LIU VO RA 90
14.1 Cc cu trc d liu 90
14.2 Hng i yu cu vo/ra 99
14.3 Hy b yu cu vo/ra 105
14.4 Tm lc cc kch bn x l 117
Bi 15: Thc hnh lp trnh driver cho x l IRP 128
Bi 16: C V GHI D LIU 128
16.1 Cu hnh thit b ca bn 128
16.2 a ch mt B m d liu 131
16.3 Cc cng v cc thanh ghi 134
16.4 Phc v ngt 139
16.5 Truy nhp b nh trc tip 150
Bi 17: IU KHIN VO/RA V HM IU KHIN PLUG AND PLAY 165
17.1 Hm DeviceIoControl API 165
17.2 iu khin IRP_MJ_DEVICE_CONTROL 168
17.3 Nhng thao tc bn trong iu khin vo/ra 169
Bi 18: Thc hnh lp trnh driver cho iu khin vo/ra 177
Bi 19: TRNH IU KHIN CHO USB 177
19.1 Gii thiu cng USB 177
19.2 Cu trc cng USB 185
19.3 Lp trnh cho cng USB 185
Bi 20: Thc hnh iu khin qua cng USB 185
359/369
360/369
Tham gia ng gp
Ti liu: LP TRNH H THNG
Bin tp bi: Khoa CNTT HSP KT Hng Yn
URL: http://voer.edu.vn/c/92c88426
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Khi nim v lp trnh h thng
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/a49cc356
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Tng quan v lp trnh h thng
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/e391eb05
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Lch s v lp trnh h thng
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/a30b5f62
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Cu trc tng quan lp trnh h thng
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/d6321b07
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Cc ngn ng lp trnh
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/aaff2f01
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Gii thiu v C++
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/6a337c50
361/369
362/369
363/369
364/369
URL: http://www.voer.edu.vn/m/e6bcd0d2
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Cc i tng Kernel Dispatcher (Kernel Dispatcher Objects )
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/be5dd762
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Mt s phng php ng b khc (Other Kernel-Mode Synchronization
Primitives )
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/bfcc3fdc
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Thc hnh lp trnh driver c bn
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/d73d84fe
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Cc cu trc d liu (Data Structures )
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/b116212a
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Hng i yu cu Vora (Queuing IO Requests)
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/4c2e2899
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Hy b yu cu vora (Cancelling IO Requests )
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/822823e6
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Tm lc cc kch bn x l (SummaryEight IRP-Handling Scenarios)
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/82adc58e
365/369
366/369
367/369
368/369
369/369