Professional Documents
Culture Documents
(Asm) LẬP TRÌNH HỆ THỐNG PDF
(Asm) LẬP TRÌNH HỆ THỐNG PDF
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
1/369
10.2. Cu trc cng COM
11. Bi 11: THC HNH VI CC CHNG TRNH GIAO TIP QUA CNG
COM
11.1. Thc hnh vi cc chng trnh giao tip qua cng COM
12. Bi 12: VN NG B
12.1. Vn ng b ha nguyn mu (An Archetypal Synchronization Problem )
12.2. Mc yu cu Ngt (Interrupt Request Level )
12.3. Kha xoay vng (Spin Locks )
12.4. Cc i tng Kernel Dispatcher (Kernel Dispatcher Objects )
12.5. Mt s phng php ng b khc (Other Kernel-Mode Synchronization
Primitives )
13. Bi 13: THC HNH LP TRNH DRIVER C BN
13.1. Thc hnh lp trnh driver c bn
14. Bi 14: GI D LIU VO RA
14.1. Cc cu trc d liu (Data Structures )
14.2. Hng i yu cu Vora (Queuing IO Requests)
14.3. Hy b yu cu vora (Cancelling IO Requests )
14.4. Tm lc cc kch bn x l (SummaryEight IRP-Handling Scenarios)
15. Bi 15: THC HNH LP TRNH DRIVER CHO X L IRP
15.1. Thc hnh mt s bi lp trnh driver c bn
16. Bi 16: C V GHI D LIU
16.1. Cu hnh thit b ca bn (Configuring Your Device )
16.2. a ch mt B m d liu (Addressing a Data Buffer )
16.3. Cc cng v cc thanh ghi (Ports and Registers )
16.4. Phc v ngt (Servicing an Interrupt )
16.5. Truy nhp b nh trc tip (Direct Memory Access )
17. Bi 17: IU KHIN VO/RA V HM IU KHIN PLUG AND PLAY
17.1. Hm DeviceIoControl API (The DeviceIoControl API)
17.2. iu khin IRP MJ DEVICE CONTROL
17.3. Nhng thao tc bn trong iu khin IO (Internal IO Control Operations)
18. Bi 18: THC HNH LP TRNH DRIVER CHO IU KHIN VO/ RA
18.1. Thc hnh lp trnh driver cho iu khin Vora
19. Bi 19: TRNH IU KHIN CHO USB
19.1. Gii thiu cng USB
20. Bi 20: THC HNH IU KHIN QUA CNG USB
20.1. Thc hnh vi cc chng trnh v d iu khin qua cng USB
2/369
21. Bi 21: TRNH IU KHIN CHO HID
21.1. Nhng b iu khin cho thit b HID (Drivers for HID Devices )
21.2. Nhng m t bo co v nhng bo co (Reports and Report Descriptors )
21.3. Nhng iu khin nh HIDCLASS (HIDCLASS Minidrivers)
22. Bi 22: THC HNH LP TRNH HID
22.1. Thc hnh vi cc chng trnh v d iu khin cho HID
23. Bi 23: THC HNH LP TRNH DRIVER GIAO TIP CC CNG
23.1. Thc hnh mt s bi tp tng hp
24. TI LIU THAM KHO
24.1. Lp trnh h thng: Ti liu tham kho
25. MC LC
25.1. Lp trnh h thng: Mc lc
Tham gia ng gp
3/369
Bi 1: TNG QUAN V LP TRNH H
THNG
Khi nim v lp trnh h thng
Lp trnh h thng (hoc chng trnh h thng) l hot ng ca cc phn mm h
thng. u tin ch ra s khc bit tiu biu ca cc chng trnh h thng khi so
snh ti lp trnh ng dng l nhm vo lp trnh ng dng sn sinh phn mm
m cung cp nhng dch v ti ngi dng (v du: b x l vn bn), trong khi nhng
nh lp trnh h thng nhm vo vic sn xut phn mm m cung cp nhng dch v
ti phn cng my tnh (v d: phn mm chng phn mnh a). N cng yu cu mt
ln hn ca s thc phn cng.
4/369
Tng quan v lp trnh h thng
Nhng im c bit hn trong lp trnh h thng:
Thc hin nhng phn nht nh trong H iu hnh v nhng quy nh hot ng mng
nhng nh lp trnh h thng (cho v d thi hnh phn trang (b nh o) hoc mt trnh
iu khin thit b cho mt h iu hnh).
5/369
Lch s v lp trnh h thng
Trc y nhng nh lp trnh h thng khng thay i in thm ngn ng assembly.
Nhng cuc th nghim vi vic h tr phn cng nhng ngn ng bc cao vo cui
nhng nm 1960 dn dt vi nhng ngn ng nh BLISS v BCPL, tr C, gip bi
s tng ca UNIX, tr thnh l khp ni vo nhng nm 1980. C++ nhng mi y
hn nhn thy s s dng no , cho th hin trong b dng c cc trnh iu khin
Vo/ra ca Mac OS X.
6/369
Cu trc tng quan lp trnh h thng
7/369
Bi 2: CNG C LP TRNH H THNG
Cc ngn ng lp trnh
Lp trnh h thng khng nht thit phi s dng ngn ng assembly. Tht vy, tuyt
i a s cc module chc nng cu thnh h iu hnh Windows, Unix, Linux... u
c vit bng ngn ng C. u im ca cc ngn ng cp cao l r rng, d c, d
din t gii thut, din t gii thut c ng... Nh vy, nu cha tht cn thit phi
dng assembly hay ngn ng my, bn nn dng 1 ngn ng cp cao nh C, C++
vit cc ng dng ca bn.
Ngc li, ngn ng Assembly hay ngn ng my khng nht thit ch dng cho lp
trnh h thng m c th c dng vit ng dng bt k. Tuy nhin do nhc im
ca assembly v ngn ng my l qu yu din t gii thut nn rt t ngi dng
chng trc tip. Nh trn ni, ngay c khi vit h iu hnh hay cc h thng nhng
(chng trnh iu khin thit b v c ghi trn ROM ca thit b ), ngi ta cng
c gng dng ngn ng cp cao nh C, tr nhng on code c bit mi dng assembly
hay m my.
Trong trng hp buc phi dng assembly hay m my, bn phi lu rng cc
ngn ng ny ph thuc hon ton vo CPU c dng. Bn khng th vit on code
assembly hay m my m c th chy trn nhiu loi CPU c. Ring i vi CPU
Intel t 80386 tr ln, n c th hot ng 1 trong 3 ch qun l b nh khc nhau
nh: Real-mode (ch mc nh khi b reset ban u), protected-mode (qun l theo
segment) v 386-enchanced mode (qun l va theo segment, va theo page, y l ch
qun l b nh hon ho nht). Th d khi mi boot my hay khi my c boot v
chy MSDOS, CPU Intel s chy ch Real-mode, cn khi my ang chy Linux,
Windows XP... th CPU Intel chy ch 386-enchanced mode. Nu bn lp trnh
bng ngn ng cp cao, bn khng cn bit ch qun l b nh no s c dng
chy ng dng. Cn nu lp trnh bng assembly hay m my, bn cn phi nm vng
cc ch qun l b nh ca CPU, phi quyt nh ch qun l no s dng
chy ng dng, t mi bt u vit lnh tng thch vi ch qun l b nh mong
mun. Th d nu bn lp trnh ch real-mode (1 trong nhng ch 16-bit), bn
ch c th dng cc thanh ghi 16-bit ca CPU nh ax, bx, cx, dx, ds, cs, es, ss). Cn nu
bn lp trnh ch 386-enchanced mode, bn c th dng cc thanh ghi 32 bit ca
CPU, trong c 2 thanh ghi fs, gs nh bn cp. Lu rng cc ng dng vit ch
32bit ch c th chy trn mi trng Windows (hay Linux), ch khng th chy trn
MSDOS c. Chi tit v cc ch qun l b nh cng nh tp lnh CPU tng ch
qun l b nh c trnh by trong ti liu k thut gii thiu CPU tng ng. Bn
c th tm ti liu k thut trn Internet hay lin h trc tip vi cc i l ca Intel.
8/369
Gii thiu v C++
C++ l mt ngn ng lp trnh tin tin, mnh trong cc ngn ng lp trnh hin nay,
n c s dng bi hng triu lp trnh vin trn th gii. N l mt trong nhng ngn
ng ph bin vit cc ng dng my tnh v ngn ng thng dng nht lp trnh
games. c sng to bi Bjarne Stroustrup, C++ l th h sau ca ngn ng C. Thc
t, C++ gi li hu ht cc c im ca C. Nh th no i na, C++ em n cho chng
ta nhng thun li hn trong vic lp trnh.
9/369
To File thc thi: (.exe)
1. u tin, ngi lp trnh dng editor (trnh son tho) vit m ngun C++, file
thng c ui .cpp. Trnh son tho ging nh b x l ngn ng cho chng trnh, n
cho php lp trnh vin to, chnh sa, v lu tr m ngun.
2. Sau khi lp trnh vin lu li m ngun, anh (ch) ta s gi compiler (trnh bin dch)
mt ng dng c chc nng c m ngun v dch n sang file i tng (object file).
Object files thng c ui m rng l .obj.
10/369
3. Tip theo, b phn kt ni (Linker) s kt ni file object n nhng file ngoi nu cn
thit, sau to file thc thi (executable file), thng c ui m rng l .exe. n lc
ny, ngi dng c th chy chng trnh bng cch chy file thc thi.
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 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
Trong thc t: Nh cc nh to phn mm, cng ty game thng gp rc ri vi cc sn
phm b li. Bin php khc phc ca h l trc khi em ra ngoi th trng, h thu
nhng ngi chi game th (game testers). Nhng ngi ny ch chi games, nhng
cng vic ca h khng th v nh bn tng u. H phi chi i chi li mt phn
no ca game c th ln n hng trm c gng tm xem c li no khng. V
vi cng vic bun t ny, lng ca h cng bo nho. Nhng tr thnh game testers
l mt nc thang bn c th vo lm vic ti cng ty lm games.
V d:
#include <stdio.h>
#include <conio.h>
void main()
getch();
12/369
Gii thiu v Visual C++
Visual C++ l mt phn mm lp trnh hng i tng c pht trin trn c s l
ngn ng lp trnh C v C++.
Phng php thit k hng i tng va mi pht trin nhm gip nh pht trin khai
thc c sc mnh ca i tng v ngn ng lp trnh hng i tng, dng cc lp
v i tng nh l khi xy dng c s.
OOP (ngn ng lp trnh hng i tng ) l ngn ng hin thc trong chng trnh
c t chc nh tp hp nhng i tng hp tc vi nhau, mi i tng i din cho
mt instance ca mt vi lp v nhng lp m chng l thnh vin ca mt lp phn cp
thng qua quan h tha k.
13/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.
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.
C++ c khuynh hng kim tra kiu cht ch nhng ta c th l i hay cm kim
tra.Tnh a dng (polymorphism):
15/369
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.
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.
16/369
Modifier : l operation thay i trng thi ca i tng. Selector: l Operation truy
xut trng thi ca i tng nhng khng lm thay i trng thi ca n.
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.
8. Bn cht ca lp:
V d:
18/369
#include "stdafx.h"
#include "conio.h"
#include "stdio.h"
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
Bi 2
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.
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.
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.
23/369
trong ch nhng b mt h thng bo mt. Bo mt l mt lnh vc ca Windows
NT v nhng ngi k nghip n, m ngn cm cc chng trinhg user-mode t vic
nhn thy hoc thay i nhng ti nguyn qun l bi nhn.
24/369
Tng quan v cc H iu hnh (An Overview of the
Operating Systems)
Windows Driver Model cung cp mt khung cho cc b iu khin thit b hot ng
2 h iu hnh h thngWindows 98/Windows Me v Windows 2000/Windows
XP. Nh c tho lun v trong tm lc lch s trc y, hai cp ny ca nhng h
iu hnh l cc sn phm ca hai con ng ca s pht trin song song. Tht ra, ti
s tham chiu ti cp trc kia ca nhng h thng vi s tm tt Windows 98/Me
nhn mnh di sn chung ca h v and to ci ghp i n gin nh XP. Mc
d ti ngi dng cui hai cp ny ca nhng h thng l ging nhau, chng lm vic
kh khc nhau trong. on ny, Ti s gii thiu tng quan v ngn gn ca hai h
thng ny.
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.
API gc
26/369
mode v c th bi vy ni trc tip ti phn cng ca h, s dng nhng phng tin
c cung cp bi lp tru tng ha phn cng (HAL) truy nhp phn cng. Mt
thao tc c c l bao gm s gi EAD_PORT_UCHAR c mt byte d liu t
mt cng Vo/ra. HAL thng s dng mt phng php platform-dependent tht s
thc hin thao tc HAL thng l s dng mt phng php ph thuc nn tng tht
s thc hin thao tc. Trn mt my tnh x86, HAL s dng trong lnh IN; trong mt
nn tng Windows XP tng lai khc no , n c l thc hin mt cng vic np
vo b nh.
Sau khi mt trnh iu khin kt thc vi mt thao tc Vo/ra, n hon thnh IRP
bng vic gi mt th tc dch v kernel-mode c bit. Hon thnh l mn cui cng
trong vic x l mt IRP, v n cho php ng dng ch i thc hin li.
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.
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
29/369
Cc HID Non-USB, bao gm chut, cc bn phm, cc cn iu khin, nhng
bnh li, vn vn. Nu bn c mt thit b USB (cho) hnh vi chung no ca
HIDUSB.SYS (nhng trnh iu khin Microsoft cho nhng thit b USB HID
cn thiu, bn cng nn vit mt minidriver HIDCLASS minidriver. Phn ch
yu in hnh ca nhng thit b ny l h bo co ngi s dng c nhp
vo bng phng php nhng bo co m c th c m t bi mt cu trc
d liu b m t. Cho nhng thit b nh vy, phc v HIDCLASS.SYS nh
trnh iu khin lp v thc hin nhiu chc nng iu Direct-Input v
nhng lp bc cao khc ca phn mm tip tc ph thuc, v th l bnre
tng i b kt nhiu vi vic s dng IDCLASS.SYS. y kh khn
ti dnh cho khng gian ng k tn tm ti n sau trong sch ny. Nh mt
s ni ring, HIDUSB.SYS chnh n l mt HIDCLASS minidriver.
Nhng thit b Windows Image Acquisition (WIA), bao gm nhng scanner v
nhng camera. Bn s vit mt WIA minidriver m thc cht thc hin mt vi
mch ghp ni COM-style ti nhng din mo h tr vendor-specific ca phn
cng ca bn.
Nhng thit b Lung, nh m thanh, DVD, v nhng thit b video, v nhng
b lc software-only cho nhng dng d liu a phng tin. Bn s vit mt
dng minidriver.
Nhng thit b giao din Mng trn nhng bus khng truyn thng, nh USB
hay 1394. Cho mt thit b nh vy, bn s vit mt mt trnh iu khin
miniport Network Driver Interface Specification (NDIS) vi mt kha cnh
thp hn WDM, ti s dng nhng cm t ging nh ti liu DDK trn ch
ny. Mt trnh iu khin nh vy khng chtrinhflinh ng gia nhng h
iu hnh, v th l bn cn phi lp k hoch trn s ghi ring bit ca h vi
nhng s khc nhau nh hn i ph vi nhng phn ph thuc nn tng.
Nhng card Video. Nhng thit b ny yu cu mt video minidriver m lm
vic vi b iu khin lp cng video.
Nhng my in, m i hi thay cho cc DLL user-mode ca cc trnh iu
khin kernel-mode.
Nhng ngun pin, Microsoft cung cp mt trnh iu khin lp chung. Bn vit
mt minidriver (DDK no gi l mt trnh iu khin miniclass, nhng cng
th ca n) lm vic vi BATTC.SYS.
30/369
Nhng trnh iu khin chc nng WDM nguyn bn
Vi mt s ngoi l s c ghi chp trong mc tip theo, a s nhng kiu khc (ca)
thit b yu cu ci g Ti c gi cho y mt trnh iu khin chc nng WDM nguyn
khi. Mt trnh iu khin nh vy thc cht ng mt mnh v x l tt c cc chi tit
ca kim sot phn cng ca bn.
Khi kiu ny ca trnh iu khin thch hp, Ti khuyn co cch tip cn sau y v th
m bn c th kt lun vi mt bit nh phn l s lm vic vic trn cc nn tng Intel
x86 trong tt c cc h iu hnh. u tin, xy dng vi nhiu DDK gn y nht
Ti s dng mt phin bn beta ca DDK .NET cho nhng v d tiu biu trong ni dung
sch hng dn. Bn c th s dng IoIsWdmVersionAvailableto quyt nh h iu
hnh no m bn tnh c ang s dng. Nu bn tnh c c chy trong Windows 2000
hay Windows XP, bn c th gi l MmGetSystemRoutineAddress c mt con tr ti
mt chc nng Windows XP-only. Ti cng gi mt hi cng WDMSTUB.SYS, m
c bn lun trong Ph lc A, nh ngha MmGetSystemRoutineAddress v nhng
hm nhn then cht khc trong Windows 98/Me; cch khc, trnh iu khin ca cc
bn n gin khng ti c trong Windows 98/Me bi v nhng nhp khu khng xc
nh.
Mt trnh iu khin cho mt cng ni tip. Trnh iu khin trn Windows 98/
Me l mt VxD m a ra giao din trnh iu khin cng VCOMM ti cnh
trn ca n, trong khi m trnh iu khin Windows 2000/ XP l mt trnh iu
khin WDM l nhng xut rt hay v nghim khc ch r giao din
IOCTL ti mp trn ca n. Hai thuyt minh upper-edge khng c ci g chung.
Mt trnh iu khin cho mt thit b ni ti mt cng ni tip. Trnh iu
khin Windows 98/Me l mt VxD m gi l VCOMM ni chuyn vi
cng. Trnh iu khin Windows 2000/XP l mt trnh iu khin WDM m
31/369
ni chuyn vi SERIAL.SYS hay mt vi trnh iu khin cng ni tip khc
m thc hin cng giao din IOCTL.
Mt trnh iu khin cho mt thit b tr tin ln USB khng tiu chun. Dnh
cho Windows 98/Me, bn s vit mt VxD m iu chnh vo trong s phn
cp gim st vin Vo/ra ca nhng trnh iu khin phn tng. Dnh cho
Windows 2000/XP, bn s vit mt trnh iu khin chc nng WDM nguyn
khi l cc khi yu cu SCSI chp nhn cnh trn ca n v giao tip vi
thit b USB ti mp thp hn ca n.
Dnh cho hai lp ca thit b, Microsoft nh ngha mt kin trc trnh iu khin di
ng di trc WDM:
32/369
Tng quan v qun l v kim tra danh sch
Nu bn l mt gim c pht trin, hay nu bn chi trch nhim khc v chuyn mt
thit b phn cng kinh doanh, l vi suy ngh bn cn bit v nhng b iu
khin thit b. Bn cn quyt nh, trc ht, liu c phi bn cn mt trnh iu khin
ty bin v, nh vy th, cch thc no. Phn c trc cn phi gip bn vi quyt
nh , nhng bn c l mun thu mt c vn chuyn gia cho mc ch hn ch
ca vic khuyn bn trn im .
Nhng trnh iu khin c th Cung cp Thng k v thng tin qun l khc trong hai
cch. H thng con Windows Management Instrumentation (WMI) cung cp mt ngn
ng - v truyn ti- ng mn c lp cho nhng phn loi khc nhau ca d liu nh
phn. Microsoft thit lp nhng lp WMI tiu chun cho nhng kiu nht nh ca
thit b, v nhm con cng nghip ca ring cc bn c th thit lp nhng tiu chun
khc m ti ci trnh iu khin ca cc bn cn phi lm ph hp.
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.
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
Bi 2
Bi 3
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:
36/369
Nhn XP Windows ( Tin t Ke ) l tt c s ng b ha mc thp (ca)
nhng hot ng gia nhng lung v nhng b x l xut hin. KeXxx c
bn ti trong chng tip theo.
Nhiu lp di ca h iu hnh, n c tc dng h t h thng khi v ch
ngh ngi, l lp tru tng ha phn cng ( hay HAL, tin t Hal). Tt c
nhng thnh phn h iu hnh ca my tnh c lin kt vi nhau trong
HAL. HAL gi ngt trong nhng qu trnh lm vic, kt ni cc thit b vo/
ra v nhng thit b lu tr khc. Thay v vic kt ni trc tip ti phn cng
ca my tnh, iu khin WDM gi l nhng hm trong HAL thc hin.
Windows NT, kin trc s a thch m khng s dng trnh iu khin run_time cc th
vin c cung cp bi nh cung cp ca chng trnh bin dch C. Trong mt phn,
ban u khng chp ny sinh t thi gian rt n gin. Windows NT c thit k
ti mt thi gian khi khng c ANSI tiu chun cho nhng g thuc mt hm chun th
vin v khi rt nhiu trnh bin dch tn ti, vi mi tng ring ca nhng g bao gm
s bnh tnh v c o ring chun cht lng.
37/369
Mt Nhc nh v nhng tc dng ph
int a = 2, b = 42, c;
c = min(a++, b);
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
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 l-
ch 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
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
if (!NT_SUCCESS(status))
//handle error
40/369
i khi l cng mt gi tr tr ra cho bn. V d, y l mt s bc u tin trong hm
AddDevice , vi tt c cc li kim tra bn tri:
NTSTATUS status;
PDEVICE_OBJECT fdo;
&fdo);
if (!NT_SUCCESS(status))
return status;
pdx->DeviceObject = fdo;
pdx->Pdo = pdo;
pdx->state = STOPPED;
IoInitializeRemoveLock(&pdx->RemoveLock, 0, 0, 0);
&pdx->ifname);
if (!NT_SUCCESS(status))
41/369
KdPrint(("IoRegisterDeviceInterface failed - %X\n", status));
IoDeleteDevice(fdo);
return status;
Bng 3-1 cho thy nhng th quan trng nht i vi tnh trng m s.
42/369
S khc bit gia mt li v cnh bo c th c ng k. V d, khng mt
METHOD_BUFFERED kim sot hot ng (xem Chng 9) vi
STATUS_BUFFER_OVERFLOW-a-gy ra cc cnh bo I / O Trng i din sao
chp d liu i vi ngi s dng ch -buffer. Vic khng cng mt hot ng vi
STATUS_BUF FER_TOO_SMALL-mt li-nguyn nhn ca I / O Trng i din
cho bt k khng c sao chp d liu.
M s mu
43/369
dereference khng hp l cho ngi dng tr-ch b nh
opcode khng hp l
Chng trnh ht nhn-ch s dng cu trc ngoi tr trng hp ngoi l bng cch
xy dng khung trn cng mt cy rm c s dng cho cc i s qua, subroutine
gi in thoi, v t ng cc bin. Mt dnh x l ng k im hin ti ngoi tr
khung. Mi phng trong khung im n trc khung.
u tin cc my tnh thi guarded trong c th. Khi kim sot cc l guarded c th cho
bt c l do g, my tnh handler thi chm dt. Xem Hnh 3-3.
44/369
Hnh 3-3. Kim sot dng chy ca trong mt th-cui cng khi.
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:
45/369
__try
++*pcounter;
return;
__finally
--*pcounter;
__try
++counter;
BadActor();
__finally
--counter;
46/369
Hy th-Ngoi tr Blocks Cc cch khc s dng cu trc ngoi l bao gm vic x
l mt th-ngoi tr khi:
__try
<guarded body>
__except(<filter expression>)
<exception handler>
Bottom of Form
Bottom of Form
47/369
Hnh 3-3. Lung ca iu khin khi try - finally .
y l mt v d n gin:
LONG counter = 0;
__try
++counter;
__finally
--counter;
KdPrint(("%d\n", counter));
Trc tin thc thi phn thn v tng bin m t 0 ln 1. Khi iu khin drops
through cui ca phn thn, kt thc qu trnh x l v gim bin m ti 0. Bi vy
gi tr in ra s l 0.
y l mt v d phc tp hn.
48/369
VOID RandomFunction(PLONG pcounter)
__try
++*pcounter;
return;
__finally
--*pcounter;
__try
++counter;
BadActor();
__finally
49/369
{
--counter;
__try
<guarded body>
__except(<filter expression>)
<exception handler>
50/369
ca bn tht bi, iu khin s tip tc chng trnh ca bn cu lnh ngay
sau .( Ti xem ti liu Platform SDK ni v hiu ng m iu khin tr ra
ngoi l ti im ca ngoi l, nhng iu khng ng)
EXCEPTION_CONTINUE_SEARCH c gi tr bng 0 v thng bo vi h
iu hnh rng bn khng th x l ngoi l. H thng s qut qua stack tm
kim x l khc. Nu khng ai cung cp mt x l no cho ngoi l th mt h
thng v s xy ra.
EXCEPTION_CONTINUE_EXECUTION c gi tr bng -1 v thng bo cho
h iu hnh tr ra mt dim ni m ngoi l c sinh ra. Ti s c mt bi
ni v gi tr biu thc ny nhiu hn na.
PVOID p = (PVOID) 1;
__try
ProbeForWrite(p, 4, 4);
51/369
}
__except(EXCEPTION_EXECUTE_HANDLER)
Nh v d sau y.
ULONG quotient;
if (!denominator)
<handle error>else
52/369
Theo cch thng thng, gi tr thc m mt nhn thnh phn a cho bn.
__except(EvaluateException(GetExceptionCode(),
GetExceptionInformation()))
a ra ngoi l
53/369
tr v mt trng thi m, thm ch nh th l s ch dn t bn ngoi kh c hn. Bn
nn trnh nhng ngoi l bi v my mc rt dt tin. Thm ch gi ca khung ngoi l
l quan trng v mt vi th cn trnh khi bn c th.
V d thc t
__try
MmProbeAndLockPages(mdl, ...);
__except(EXCEPTION_EXECUTE_HANDLER)
IoFreeMdl(mdl);
54/369
}
__try
ProbeForRead(p, 4, 4);
LONG x = *p;
__except(EXCEPTION_EXECUTE_HANDLER)
Bug Checks
55/369
Nhng li khng th phc hi c trong kiu nhn c th biur th chnh n trong ci
goi l mn hnh xanh ca s cht(BSOD) l tt c qu quen thuc i vi lp trnh
vin. Hnh 3-5 l mt v d .
Bn c th gi KeBugCheckEx nh sau:
Nh mt ngi pht trin bn khng c thng tin t mn hnh xanh. Nu bn may mn.
thng tin s bao gm c hng dn been trong trnh iu khin ca bn. Sau bn
c th xem xt v tr ny trong nhn trnh g ri, c l, suy lun c th thc hin c
v kim tra ri. Chnh kim tra ri ca Microsoft xut hin trong bugcodes.h S gii
thch v m ca h c th tm thy trong Nhng kin thc c bn Q103059. a fuller
56/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:
KeBugCheckEx(MY_BUGCHECK_CODE, 0, 0, 0, 0);
57/369
Qun l b nh (Memory Management )
chng ny, ti s bn v ch qun l b nh. Windows XP chia ct vng a ch
thc t chia ct bn trong bng vi cch. Mt cch chia - rt bo mt v ton vn l a
ch ngi dng v a ch nhn. Mt cch chia khc, m s dng hu ht nhng khng
tt lm l gia trang nh v khng phaitrang nh. Hu ht a ch ngi s dng v vi
a ch kiu nhn tham chiu dn nh m Qun l b nh i ti v t a trong ton
b thi gian, trong khi mt vi a ch kiu nhn lun lun lin kt ti nh trong b
nh vt l. T Windows XP cho php nhng phn ca trnh iu khin t nh, ti s
gii thch cch lm th no iu khin nh ca trnh iu khin ca bn ti mt thi
im bn xy dng trnh iu khin v chy n. Windows XP cung cp mt s phog
thc qun l b nh. Ti s m t hai hm dch v c bn ExAllocatePoolWithTag
v ExFreePool m bn s dng phn chia v gii phng mt cch ngu nhin. Ti
s gii thch nguyn thu m bn s dng t chc b nh v trong nhng danh sch
lin kt ca cu trc. Cui cng ti s gii thch khi nim mt danh sch m cho php
bn phn chia c hiu qu.
Hnh 3-6. Thnh vin-ht nhn v ch -ch ca phn khng gian a ch. Mi ngi
s dng ch x l c a ch bi cnh ring ca mnh, m bn ca ngi s dng
ch o-a ch duy nht cho mt b su tp ca vt cht trang khung. Ni cch khc,
ngha ca bt k a ch ring o thay i t mt cht thi gian tip theo nh l
Windows XP Scheduler tc t mt si mt trong qu trnh vo mt si khc trong qu
58/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
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.
59/369
PAGE_ALIGN vng mt o a ch xung mt trang ranh gii. Ngy 4-KB-trang,
my tnh, PAGE_ALIGN (0x12345678) s c 0x12345000.
nh s trang v nh s trang B nh
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.
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
Nu h thng xy ra DispatchPower gi ti mt thi gian khi trang cha n khng
phi l hin nay, mt trang li s xy ra, theo sau l mt li kim tra. Li m
kim tra s c pretty uninformative (IRQL_NOT_LESS_OR_EQUAL hay
DRIVER_IRQL_NOT_LESS_OR_EQUAL), nhng t nht bn s tm ra rng bn c
mt vn .
Ch :
61/369
chc chn lm cho kh hn tm thy li gy ra bi misplacement ca driver hoc m
d liu vo paged pool! Nu bn s dng debugger ny, ti khuyn bn nn religiously
s dng PAGED_CODE v m v Driver Verifier.
#ifdef ALLOC_PRAGMA
#endif
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
62/369
Khi-Thi gian kim sot ca Pageability
Bng 3-3 lit k cc dch v, bn c th s dng hm chy thi gian tinh chnh s
pageability ca bn driver trong tnh hung khc nhau. Mc ch ca cc thi quen l
cho bn pht hnh ca b nh vt l m c khc c gn ln do m ca bn v d liu
trong sut thi gian khi n s khng c cn thit.
PVOID hPageIdleSection;
NTSTATUS DriverEntry(...)
63/369
{
hPageIdleSection = MmLockPagableCodeSection((PVOID)
DispatchRead);
MmUnlockPagableImageSection(hPageIdleSection);
MmLockPagableSectionByHandle(hPageIdleSection);
PVOID hPageDataSection;
#pragma data_seg("PAGE")
ULONG ulSomething;
#pragma data_seg()
hPageDataSection = MmLockPagableDataSection((PVOID)
&ulSomething);
MmUnlockPagableImageSection(hPageDataSection);
64/369
MmLockPagableSectionByHandle(hPageDataSection);
MmPageEntireDriver((PVOID) DriverEntry);
MmResetDriverPaging((PVOID) DriverEntry);
Bottom of Form
V d:
if (!p)
return STATUS_INSUFFICIENT_RESOURCES;
Cc loi pool bao gm khi nim phi thnh cng. Nu khng c b nh heap
satisify mt yu cu t phi-pool thnh cng, h thng kim tra li. Trnh iu khin
65/369
khng nn phn b b nh bng cch s dng mt trong nhng thnh cng phi-
specifiers. iu ny l do mt driver c th gn nh lun lun tht bi no l hot ng
theo cch
#ifndef POOL_RAISE_IF_ALLOCATION_FAILURE
#define POOL_RAISE_IF_ALLOCATION_FAILURE 16
#endif
(PagedPool POOL_RAISE_IF_ALLOCATION_FAILURE)
(NonPagedPool POOL_RAISE_IF_ALLOCATION_FAILURE)
NTSTATUS SomeFunction()
NTSTATUS status;
__try
PMYSTUFF p = (PMYSTUFF)
ExAllocatePoolWithTag(PagedPoolRaiseException,
sizeof(MYSTUFF), DRIVERTAG);
66/369
<Code that uses "p" without checking it for NULL>
status = STATUS_SUCCESS;
__except(EXCEPTION_EXECUTE_HANDLER)
status = GetExceptionCode();
return status;
Bn phi khng phi l nguyn nhn ca mt h thng sp trong tnh hnh ny, tuy
nhin, v bn do s c cc ngun tim nng ca mt t chi-ca-dch v khai thc.
Nhng t khi c li s khng pht sinh trong thc t i sng, khng c im trong xy
dng a vo m ca bn ng nhp li trnh iu khin, tn hiu WMI cc s kin,
in g li tin nhn, thc hin cc thut ton thay th, v nh vy trn. Tht vy, thm m
cn thit lm tt c m c th l l do h thng khng c thm 32 byte cung cp
cho bn l ngi u tin ni! V vy, ti khuyn bn nn kim tra cc gi tr tr ra tt
c cc cuc gi n t ExAllocatePoolWithTag.
67/369
b nh (Releasing a Memory Block)
ExFreePool((PVOID) p);
68/369
. Lc ti vit iu ny,ExAllocatePoolWithTagPriority bin chuyn v tr ln n
gin c gi l ExAllocatePoolWithTag nu bn yu cu c nh s trang b nh
mc u tin c bit hay bt k quyn u tin no. Vic kim tra thm ti nguyn ch
xy ra vi nhng yu cu nh s trang b nh c quyn u tin thp hay bnh thng.
Hnh vi ny c th thay i trong nhng gi dch v hay nhng phin bn sau ca h
iu hnh.
SINGLE_LIST_ENTRY linkfield;
} ONEWAY, *PONEWAY;
69/369
SINGLE_LIST_ENTRY SingleHead;
SingleHead.Next = NULL;
sizeof(ONEWAY));
PushEntryList(&SingleHead, &psElement->linkfield);
if (psLink)
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
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
Cc khi ln, sau s c sn p ng mt s yu cu sau cho mt khi ln hn bt
k mt trong ba thnh phn gc
Hnh 3-12 minh ho khi nim ca mt lookaside danh sch. Hy tng tng rng bn
c mt ly m bn c th (no -php lut ca Vt l khng chnh xc lm cho vic
ny d dng!) S d ngay thng, trong mt h pool
Bottom of Form
71/369
H thng nh k iu chnh su ca tt c cc lookaside danh sch da trn thc t s
dng. Cc chi tit ca cc thut ton khng tht s quan trng, v chng ti c th thay
i trong bt k trng hp no. V c bn (trong bn pht hnh hin ti, anyway), h
thng s gim chiu su ca lookaside danh sch m khng c c truy cp trong thi
gian gn y hay khng c truy cp pool buc t nht 5 phn trm ca thi gian. Su
khng bao gi i di y 4, tuy nhin, cng l chiu su ban u ca mt danh sch
mi.
PVOID p = ExAllocateFromPagedLookasideList(pagedlist);
PVOID q = ExAllocateFromNPagedLookasideList(nonpagedlist);
72/369
To put a block back onto the list, call the appropriate FreeTo function:
ExFreeToPagedLookasideList(pagedlist, p);
ExFreeToNPagedLookasideList(nonpagedlist, q);
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
Trnh by chui (String Handling)
WDM trnh iu khin c th lm vic vi cc d liu trong bt k phn no trong bn
nh dng:
74/369
K thut lp trnh hn hp (Miscellaneous Programming
Techniques )
Truy cp vo Registry
Windows XP v Windows 98/Me ghi li cu hnh v cc thng tin quan trng trong mt
c s d liu gi l ng k. WDM trnh iu khin c th gi cc chc nng c lit
k trong bng 3-10 truy cp cc ng k. Nu bn thc hin ch ngi dng
truy cp chng trnh lin quan n ng k, bn c th c th on nh th no s
dng cc chc nng trong mt driver. Ti c tm thy ht nhn-ch h tr y
cc chc nng khc nhau, tuy nhin, ti ngh rng gi tr ca n m t cch no bn c
th s dng chng.
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
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
PUNICODE_STRING RegistryPath)
OBJECT_ATTRIBUTES oa;
76/369
HANDLE hkey;
if (NT_SUCCESS(status))
ZwClose(hkey);
HANDLE hkey;
77/369
ni pdo l a ch ca cc i tng vt l in thoi (PDO) di cng ca trnh iu
khin c bit ca bn stack, c l mt ch cho cc kho c bit m bn mun m (xem
B ng 3-11), v truy cp l mt v d nh mt n truy cp KEY_READ
HANDLE hkey;
&hkey);
Bt v ci t cc gi tr
UNICODE_STRING valname;
RtlInitUnicodeString(&valname, L"ImagePath");
78/369
size = 0;
NULL, 0, &size);
<handle error>;
PKEY_VALUE_PARTIAL_INFORMATION vpip =
if (!vpip)
<handle error>;
if (!NT_SUCCESS(status))
<handle error>;
79/369
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG DataLength;
UCHAR Data[1];
} KEY_VALUE_PARTIAL_INFORMATION,
*PKEY_VALUE_PARTIAL_INFORMATION;
Loi hnh l mt trong nhng loi d liu ng k lit k trong bng 3-12. (Cc loi d
liu l c th c nhng khng quan tm n trnh iu khin thit b.) DataLength l
chiu di ca d liu gi tr, v d liu l d liu ring ca mnh. TitleIndex khng c
lin quan n trnh iu khin. Di y l mt s d kin hu ch bit v cc loi
d liu khc nhau:
Ch thch:
80/369
thit lp mt gi tr ng k, bn phi c KEY_SET_VALUE truy cp vo cha m
cha kha. Ti s dng KEY_READ sm hn, s khng cho bn truy cp nh
vy. Bn c th s dng KEY_WRITE hay KEY_ALL_ACCESS, mc d bn thu c
nhiu hn do cn thit cho php. Sau , gi ZwSetValueKey. V d:
RtlInitUnicodeString(&valname, L"TheAnswer");
sizeof(value));
Subkeys xa hoc gi tr
L"TheAnswer");
81/369
Trong Windows 2000 v sau ny, bn c th s dng ZwDeleteValueKey xa mt
gi tr (n l mt gim st rng chc nng ny khng phi l ti liu trong DDK):
UNICODE_STRING valname;
RtlInitUnicodeString(&valname, L"TheAnswer");
RtlDeleteValueKey(hkey, &valname);
ZwDeleteKey(hkey);
Cha kha cho n khi cuc sng trn tt c cc x l ang ng ca, nhng cc n lc
m mt ca hng mi x l cc phm hoc truy cp vo cc phm bng cch s
dng bt c hin ang m x l s khng thnh cng vi STATUS_KEY_DELETED.
K t khi bn c mt m x l ti im ny, bn cn phi chc chn s c gi
ZwClose sometime. (The DDK ti liu hng dn cho cc mc nhp ZwDeleteKey ni
nhng x l s tr thnh khng hp l. It doesnt-bn vn phi ng n bng cch gi
in thoi ZwClose.)
LARGE_INTEGER LastWriteTime;
ULONG TitleIndex;
ULONG ClassOffset;
ULONG ClassLength;
ULONG SubKeys;
82/369
ULONG MaxNameLen;
ULONG MaxClassLen;
ULONG Values;
ULONG MaxValueNameLen;
ULONG MaxValueDataLen;
WCHAR Class[1];
} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION;
ULONG size;
ExAllocatePool(PagedPool, size);
ExAllocatePool(PagedPool, size);
83/369
ZwEnumerateKey(hkey, i, KeyBasicInformation, bip, size, &size);
ExFreePool(bip);
LARGE_INTEGER LastWriteTime;
ULONG Type;
ULONG NameLength;
WCHAR Name[1];
} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION
Khng phi l tn null-chm dt, bn phi s dng cc NameLength thnh thnh vin
ca cc c cu xc nh chiu di ca n. ng qun rng trong chiu di l byte!
Tn l khng y hoc ng dn ng k; iu ch cn tn ca subkey no trong
vng cha kha cha n. y tht s l may mn, bi v bn c th d dng m mt
subkey ca n cho mt tn v x l m cc bc cha m cha kha.
sizeof(KEY_VALUE_BASIC_INFORMATION);
ExAllocatePool(PagedPool, maxlen);
84/369
{
maxlen, &size);
ExFreePool(vip);
ULONG TitleIndex;
ULONG Type;
ULONG NameLength;
WCHAR Name[1];
} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
Truy cp tp tin
85/369
cng ca bn, hoc c l bn cn phi to ring ca bn rng ln ca thng tin ng
nhp cho mt s mc ch. C b ZwXxx thi quen gip bn lm c nhng iu
.
M s mu
NTSTATUS status;
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK iostatus;
InitializeObjectAttributes(&oa, pathname,
To hoc vit li mt tp
86/369
to mt tp tin mi, hoc m v truncate khng chiu di hin c mt tp tin,
thay th cc cuc gi n ZwCreateFile trong trc fragment ny vi mt trong:
Lnh vc x l
FILE_STANDARD_INFORMATION si;
FileStandardInformation);
87/369
Bn s c kh nng mun c mt a tp tin trong mt WDM driver trong khi bn ang
bt u in thoi ca bn phn ng li mt IRP_MN_START_DEVICE yu cu.
(Xem Chng 6.) Ty thuc vo ni m in thoi ca bn t ng trong s khi trnh t,
bn c th hoc c th khng c quyn truy cp vo cc tp tin bng cch s dng nh
bnh thng pathnames \?? \ C: \ dir \ file.ext. c an ton, a cc tp tin d liu
ca bn vo mt s th mc di y ca h thng th mc gc v s dng nh mt file
\ SystemRoot \ dir \ file.ext. SystemRoot cc chi nhnh ca cc tn ny, lun lun c th
truy cp t cc h iu hnh c th c a file bt u ln.
ni xxx l tn ca mt trnh iu khin thit b. Nh li rng thy hai gip bin string
constants nh l mt c nh. Trick c bit bng cch s dng ny cho php ti ct
v dn ton b subroutines, bao gm c cc cuc gi ca h KdPrint, t mt driver khc
m khng cn phi lm cho m ngun thay i.
Cc khng nh v m
ASSERT(1 + 1 == 2);
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
Hnh 3-15. Driver Verifier thut s th hai trang
90/369
Hnh 3-16. Driver Verifier ca thut s ci t tu chnh trang
I / O M xc nhn nguyn nhn ca Driver Verifier kim tra vic thc hin c bn
nh th no l mt driver x l IRPs rng n to ra hoc forwards n cc trnh iu
91/369
khin. Enhanced I / O M xc nhn cc n lc tun ra driver ra li trong trng hp
ranh gii, chng hn nh hon tt v PnP Power IRPs khng chnh xc, lm cho cc gi
nh v trnh t, trong cc Trng i din PnP ti cc trnh iu khin, v nh vy
trn. Mt s trong nhng bi kim tra xy ra khi trnh iu khin thit b bt u bc
u, by the way, m c th ngn chn vic bt u t h thng.
Low Ti nguyn M phng ngu nhin khng bao gm vic phn pool t xc nhn
trnh iu khin, bt u by pht sau khi h thng bt u. Mc ch ca cc tht bi l
m bo rng trnh iu khin th nghim cc gi tr tr li t pool phn b cc cuc
gi.
Ch thch:
Lu rng qu Driver Verifier l pht trin nhanh chng ngay c khi chng ti ni
chuyn. DDK c s t vn cho bn xy ra c lm vic vi cho up-to-date thng
tin. Sau khi bn chn tu chn verifier bn mun, bn s thy mt thut s cui cng ca
trang (xem Hnh 3-17). Trang ny cho php bn xc nh trnh iu khin m bn
mun xc minh bng cch kim tra cc hp trong mt danh sch. Sau khi thc hin l
la chn, bn s cn phi khi ng li my tnh, v nhiu ca Driver Verifier kim tra
yu cu khi ng-thi gian s khi. Khi ti g li mt trong cc trnh iu khin ca
ring ti, ti tm thy n thun tin nht ca ti khng c bng driver ti khi khi
ng li xy ra. Do vy, driver ca ti s khng c trong danh sch, v ti s c
thm n qua Thm vo Hin nay khng c ti Driver (s) To The Danh sch nt.
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
Bi 2
94/369
Bi 8: LP TRNH GIAO TIP QUA
CNG LPT
Gii thiu cng LPT
a s cc my vi tnh u trao i thng tin thng qua cc ng sau y: Parallel port,
Serial port, USB v Network card. Parallel port l mt phn khng th thiu trong vic
s dng computer giao tip vi cc thit b in t khc. Bi ny ch yu dng cho
sinh vin hardware nhng vic hiu bit ca n cng khng tha i vi cc bn hc
software.
95/369
Cu trc cng LPT
Cu trc ca Parallel port nhn trn phng din hardware
5 pins dng hin th tnh trng hot ng ca parallel port: ang bn, ang gi/nhn
thng tin...(cc pin s 10-13 v pin s 15) gi l STATUS Port. D liu trao i qua 8
pin ny dng 5 bit cao ca byte.
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.
96/369
DATA port l ni thng tin s c trao i t computer n cc thit b khc (hai
chiu). Khi lp trnh t hn cng c khi bn nghe ni n chuyn vit 1 program/driver
cho cc hardware (nu bn lm cho mt s hng my in, vin thng...). y driver cho
parallel port chnh l chng trnh qun l v iu khin qu trnh trao i thng tin ny.
DATA port c 8 pins tc l 1 bytes. Bn c l tng nghe k thut ti thng tin qua ng
parallel port l nhanh nht (trong qu kh) nhng k thc n cng ch dng c 1byte =
8 bit = 8 ci pins ny m thi! Ti s tr li sau trong vic bn tho th no l mt si
dy parallel tt.
Thc ra th vi dn software, h cng khng cn bit pha parallel port sau lng my tnh
c bao nhin pin v mi pin cn bao nhiu in, cu trc nh th no...My ci ny hi
tha cho dn software! Tt c nhng g m mt ngi lp trnh cn bit l address ca
cc pin trn parallel port l ! 25 pins kia s c chia lm 3 phn vi tn gi l DATA
port (hay l DATA register), STATUS port (hay l STATUS register), v CONTROL
port (hay l CONTROL register). Mi port l 8 bits vi address hn hi. Nh m t t
u, DATA port s l 8 bits, STATUS port c 5 pins cho nn s cng thm 3 bit trng
to mt byte, tng t nh th cho CONTROL port. Ring phn a ch cho cc port ny
cng kh l phc tp, v n lin quan n BIOS. Nu bn hiu cch phn b memory
ca my tnh th n gin hn, cn khng th hy vng l li gii thch ca ti s lm bn
hiu phn no. i khi l khi my tnh bt ln (turn on) th BIOS s lm vic trc,
n s tm kim v nh a ch cho ci port trong my ca bn. V BIOS khng ci no
ging ci no cho nn li qui nh a ch ca n cng khc, tuy nhin di y l mt
v d in hnh (bn thng thy) trong cc my vi tnh ngy nay. Nhng a ch ny
bn c th thy khi khi ng my trong cc thng s BIOS hin ra.
Port Address Ghi ch 3BCh - 3BFh dng cho prallel port vn dnh vo Video Card (cch
c) 378h - 37Fh khu vc memory thng dng cho LPT 1 278h - 27Fh khu vc memory
thng dng cho LPT 2 ....
97/369
(nn nh l mi khon l 8 bits, tnh theo h hexadecimal)
Cng lu cc bn cc i ch trn l port address qui nh trn BIOS, khi BIOS qui
nh nhng a ch trn (tt my vn cn) n s qui nh km theo i ch lu thng tin
(tt my s mt) cho tng port. Nhng a ch di y s c dng a s bi cc bn
lp trnh kim tra x hin din ca parallel port trn my bn.
Base + 3
#include <stdio.h>
#include <dos.h>
void main(void)
/* Address of Port */
98/369
int a;
{address = *ptraddr;
if (address == 0)
a+1, address);
*ptraddr++;}}
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....
99/369
Direction/type (nhn t PC)
Normal signal line function 1 -STROBE OC/Pullup Control register bit 0 kch hot
thng bo gi hoc nhn data, 0 l c, 1 l vit 2 D0 hai chiu Data register bit 0 bit 0
cha data 3 D1 hai chiu Data register bit 1 bit 1 cha data 4 D2 hai chiu Data register
bit 2 bit 2 cha data 5 D3 hai chiu Data register bit 3 bit 3 cha data 6 D4 hai chiu
Data register bit 4 bit 4 cha data 7 D5 hai chiu Data register bit 5 bit 5 cha data 8 D6
hai chiu Data register bit 6 bit 6 cha data 9 D7 hai chiu Data register bit 7 bit 7 cha
data 10 -ACK Input Status register bit 6 Pulsed low by printer to acknowledge data byte
Rising (usually) edge causes IRQ if enabled 11 BUSY Input Status register bit 7 kch
hot khi printer ang bn (busy) 12 NOPAPER Input Status register bit 5 kch hot khi
printer ht giy 13 SELECTED Input Status register bit 4 kch hot khi printer ang hot
ng 14 -AUTOFEED OC/Pullup Control register bit 1 kch hot thng bo data sn
sng c hoc vit 15 -ERROR Input Status register bit 3 kch hot khi printer b li
(v nhiu l do) 16 -INITIALIZE OC/Pullup Control register bit 2 kch hot printer
reset li v tr ban u 17 -SELECT OC/Pullup Control register bit 3 kch hot nh
du printer nhn c valid address 18 Ground ...Ground chn (18-25) b trng, dng
ty 25 Ground Thm mt hnh minh ho tng th hot ng ca parallel port.
100/369
101/369
Bi 9: THC HNH VI CC CHNG
TRNH GIAO TIP QUA CNG LPT
Thc hnh vi cc chng trnh giao tip qua cng LPT
Bi 1.
S dng VB6 thit lp, truyn d liu ra cng LPT v nhn d liu v
Bi 2.
102/369
Bi 10: THC HNH VI CC CHNG
TRNH GIAO TIP QUA CNG COM
Gii thiu cng COM
IBM PC cung cp 2 cng ni tip: COM1 v COM2. Cc cng ny giao tip theo tiu
chun RS232. Chng c th c ni vi mt Modem dng cho mng in thoi,
hay ni trc tip vi mt my tnh khc. D liu c truyn qua cng ny theo cch
ni tip, ngha l d liu c gi i ni tip nhau trn 1 ng dy. Do cc d liu
c truyn i tng bit mt nn tc truyn chm, cc tc truyn c th l 300,
600, 1200, 2400, 4800bps, 9600bps, chiu di d liu c th l 5, 6, 7 hoc 8 bit v kt
hp vi cc bit Start, Stop, Parity to thnh mt khung (frame). Ngoi ra cng ny cn
c cc iu khin thu (Receive), pht (Trans), kim tra. Cch giao tip ny cho php
khong cch truyn d liu xa, tuy nhin tc truyn rt chm tc ti a l 20kbps.
103/369
Cu trc cng COM
Cng ni tip c s dng truyn d liu hai chiu gia my tnh v ngoi vi, c
cc u im sau:
- S dy kt ni t.
Cc thit b ghp ni chia thnh 2 loi: DTE (Data Terminal Equipment) v DCE (Data
Communication Equipment). DCE l cc thit b trung gian nh MODEM cn DTE l
cc thit b tip nhn hay truyn d liu nh my tnh, PLC, vi iu khin, Vic trao
i
tn hiu thng thng qua 2 chn RxD (nhn) v TxD (truyn). Cc tn hiu cn li c
chc
Tn hiu truyn theo chun RS-232 ca EIA (Electronics Industry Associations). Chun
RS-232 quy nh mc logic 1 ng vi in p t -3V n -25V (mark), mc logic 0 ng
vi in p t 3V n 25V (space) v c kh nng cung cp dng t 10 mA n 20 mA.
Ngoi ra, tt c cc ng ra u c c tnh chng chp mch.
Chun RS-232 cho php truyn tn hiu vi tc n 20.000 bps nhng nu cp truyn
ngn c th ln n 115.200 bps.
104/369
- Bn song cng ( half-duplex): d liu truyn theo 2 hng, nhng mi thi im ch
c truyn theo 1 hng.
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):
Cc tc truyn d liu thng dng trong cng ni tip l: 1200 bps, 4800 bps,
? Schn:
105/369
H n h 4 .2 S c h n c ng n i t i p
Tnh H ng
D25 D9 M t
iu tru y n
1 - - - Protected ground: ni t bo v
2 3 TxD DTEDCE Transmitted data: d liu truyn
3 2 RxD DCEDTE Received data: d liu nhn
4 7 RTS DTEDCE Request to send: DTE yu cu truyn d liu
5 8 CTS DCEDTE Clear to send: DCE sn sng nhn d liu
6 6 DSR DCEDTE Data set ready: DCE sn sng lm vic
7 5 GND - Ground: ni t (0V)
8 1 DCD DCEDTE Data carier detect: DCE pht hin sng mang
20 4 DTR DTEDCE Data terminal ready: DTE sn sng lm vic
106/369
22 9 RI DCEDTE Ring indicator: bo chung
23 - DSRD DCEDTE Data signal rate detector: d tc truyn
Transmit Signal Element Timing: tn hiu nh
24 - TSET DTEDCE
thitruyn i t DTE
Transmitter Signal Element Timing: tn hiu nh
15 - TSET DCEDTE
thitruyn t DCE truyn d liu
Receiver Signal Element Timing: tn hiu nh
17 - RSET DCEDTE
thitruyn t DCE truyn d liu
18 - LL Local Loopback: kim tra cng
Remote Loopback: To ra bi DCE khi tn hiu
21 - RL DCEDTE
nhnt DCE li
14 - STxD DTEDCE Secondary Transmitted Data
16 - SRxD DCEDTE Secondary Received Data
19 - SRTS DTEDCE Secondary Request To Send
13 - SCTS DCEDTE Secondary Clear To Send
12 - SDSRD DCEDTE Secondary Received Line Signal Detector
25 - TM Test Mode
9 - Dnh ring cho ch test
10 - Dnh ring cho ch test
11 Khng dng
107/369
Bi 11: THC HNH VI CC CHNG
TRNH GIAO TIP QUA CNG COM
Thc hnh vi cc chng trnh giao tip qua cng COM
Bi 1.
S dng VB6 thit lp, truyn d liu ra cng COM v nhn d liu v
Bi 2.
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:
++lActiveRequests;
--lActiveRequests;
if (lActiveRequests)
IoDeleteDevice(fdo);
109/369
V d ny m t mt vn thc s, nhn tin, chng ti s dng tho lun vn
ny chng 6 trong nhng yu cu ca chng ta ca nhng yu cu Plug and Play
(PnP). Qun l vo/ra c th c gng loi b mt trong s nhng thit b ca chng
ta ti mt thi im khi nhng yu cu c kch hot, v chng ti cn phng iu
bng vic gi loi no ca my m. Ti s trnh by vi bn chng 6 s dng
IoAcquireRemoveLock nh th v mt s chc nng lin quan gii quyt vn .
; ++lActiveRequests;
add eax, 1
; --lActiveRequests;
sub eax, 1
Ch
110/369
By gi hnh dung rng lung khc qun l a m tng ln qua ti s bt u ca
DispatchPnp. N s tng dn lActiveRequests t 2 n 3 (bi v lung u tin cha
bao gi c ti cp nht bin). Nu lung u tin chn trc lung khc ny, h iu
hnh s khi phc u tin ng cnh ca lung, m bao gm gi tr 2 trong thanh ghi
EAX. Lung u tin by gi thu c tr 1 t EAX v ct gi kt qu sau
lActiveRequests. Ti im ny, lActiveRequests cha ng gi tr 1, m sai. u
xung l con ng, chng ti c l hp tp xa i tng thit b ca chng ta v
chng ti c rnh ghi b mt thc s ca ca mt yu cu vo/ra.
; ++lActiveRequests;
inc lActiveRequests
111/369
; --lActiveRequests;
dec lActiveRequests
; ++lActiveRequests;
; --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.
112/369
Mc yu cu Ngt (Interrupt Request Level )
Windows XP gn mt mc yu cu ngt ti mi ngt phn cng v ti mt s chn
la vi s kin phn mm. Mi CPU c IRQL ca mnh. Chng ti gn nhn nhng
mc IRQL khc nhau vi nhng tn nh PASSIVE_LEVEL, APC_LEVEL,. Hnh
4-1 minh ha phm vi ca nhng gi tr IRQL cho nn tng x86. (Ni chung, nhng gi
tr s ca IRQL ph thuc vo nn tng no bn ni v n). Hu ht thi gian, my tnh
thc hin trong kiu ngi s dng PASSIVE_LEVEL. Tt c kin thc ca cc bn
v cng vic nhng h iu hnh a nhim p dng PASSIVE_LEVEL nh th no.
iu , b lp lch biu c th chn trc mt lung ch cui ca mt phn chia thi
gian hay bi v mt lung quyn u tin bc cao tr nn xng ng chy. Nhng
lung cng c th l khi t trong khi h i nhng s kin xut hin.
CH :
113/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.)
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
Hnh 4-2. u tin ngt trong hnh ng .
Quyn u tin lung l mt khi nim rt khc nhau t IRQL. Quyn u tin Lung
kim sot nhng hot ng ca b lp lch biu trong vic quyt nh khi chn trc
chy nhng lung v ci g xu thnh chui bt u chy bc tip theo. " Quyn u
tin " duy nht m c ngha rng bt c ci g IRQLs trn APC_LEVEL l chnh
IRQL, v n kim sot nhng chng trnh no c th thc hin hn l vn cnh lung
m bn trong ci chng thc hin.
M thc hin ti hoc trn DISPATCH_LEVEL khng phi l trang nguyn nhn cc
li.
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:
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);
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
Kha xoay vng (Spin Locks )
gip bn ng b ha truy nhp ti d liu dng chung trong th gii a x l cn
i ca Windows XP, kernel cho bn nh ngha bt k s ca cc i tng kha
xoay vng no. thu nhn mt kha xoay vng, m trn mt CPU thc hin mt trong
nhng thao tc nguyn t m nhng s th v sau c t mt bin k c theo mt
cch m khng c CPU khc c th truy nhp bin cho n thao tc hon thnh. Nu s
th ch ra s kha trc t do, chng trnh tip tc. Nu s th ch ra s kha
th trc c gi, chng trnh lp li test-and-set trong mt vng lp cht: n
l spins. Dn dn ch nhn gii phng s kha bng vic t li bin, v ci l mt
trong s s ch i qu trnh hot ng test-and-set ca CPU s bo co s kha nh t
do.
Hnh 4-3 minh ha khi nim ca vic s dng mt s kha xoay vng. Gi thit chng
ti c " ti nguyn " no m c l c s dng ng thi trn hai CPU khc nhau.
lm v d c th, hnh dung rng ti nguyn l t bo LIST_ENTRY m neo mt bn
k lin kt ca IRPs. Danh sch c l c truy nhp bi mt hoc nhiu th tc gi
i, mt s hy b thng l, mt DPC thng l,.... Bt k s no ca nhng th tc
ny c l l ang thc hin ng thi trn cc CPU khc nhau v th sa i danh
sch kt hp. ngn nga s hn lon, chng ti lin tng mt kha xoay vng vi
iu ny " ti nguyn."
Gi thit by gi m m thc hin trn CPU-A mun truy nhp ti nguyn dng chung
thi gian t1. N thu nhn s kha xoay vng v bt u s truy nhp ca n. Khng
lu na v sau, thi gian t2, m thc hin trn CPU-B cng mun truy nhp cng ti
nguyn. CPU- B chng trnh th thu nhn s kha xoay vng. T CPU mt hin thi
s hu s kha xoay vng, CPU B nhng s xoay vng trong mt vng lp cht, lin
tc kim tra v kim tra li kha xoay vng nhn thy liu c phi n tr nn t do.
118/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.)
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.
KSPIN_LOCK QLock;
119/369
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
KeInitializeSpinLock(&pdx->QLock);
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;
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.
KeAcquireSpinLockAtDpcLevel(&pdx->QLock);
KeReleaseSpinLockFromDpcLevel(&pdx->QLock);
121/369
Cc i tng Kernel Dispatcher (Kernel Dispatcher
Objects )
Kernel cung cp nm kiu ca nhng i tng ng b ha m bn c th s dng
kim sot lung ca nhng lung khng chuyn quyn. Nhn thy Bng 4-1 cho mt
tm lc ca nhng kiu i tng thu pht nhn ny v nhng s s dng ca h. Vo
mt vi khonh khc, mt trong s i tng ny trong mt ca hai trng thi: c
bo hiu hay khng phi - bo hiu. Ti nhng ln khi n tha nhn c cho bn
ngn chn mt lung trong vn cnh ca bn ang chy, bn c th i mt hoc nhiu
i tng t n bo hiu trng thi bng vic gi l KeWaitForSingleObject hay
KeWaitForMultipleObjects. Kernel cng cung cp nhng th tc cho kKhi to v kim
sot tnh trng ca mt trong cc i trng ny.
122/369
hiu khi no v nh th no n tha nhn c mt trnh iu khin WDM ngn
chn mt lung trn mt i tng thu pht kernel. Ni chung, d lung no ang thc
hin lc ca mt phn mm hay ngt phn cng tip tc l lung hin thi trong khi
nhng x l kernel ngt. Chng ti ni ca vic thc hin m kernel-mode trong vn
cnh ca lung hin thi ny. Trong s p li ti nhng ngt ca nhng cch thc khc
nhau, b lp lch biu c l quyt nh chuyn nhng lung, tt nhin, ti trng hp
no mt lung mi tr nn " hin hnh."
Thng thng, ch mt trnh iu khin mc- cao nht c th bit cho chc chn iu
n l s vn dng trong mt vn cnh lung khng chuyn quyn. Gi s cho php bn
l mt s lin lc thng l trong mt trnh iu khin mc- thp hn, v bn ngc nhin
c hay khng bn c gi l trong mt lung chuyn quyn. Nu trnh iu khin
mc- cao nht trc tip ch gi bn mt IRP t s lin lc thng l ca n, bn lm
trong bn gc, khng chuyn quyn, lung. Nhng gi thit rng trnh iu khin c
c mang mt IRP vo mt hng i v sau tr li ti ng dng. Trnh iu khin
loi b IRP t hng i trong mt lung chuyn quyn v sau c gi n hay
IRP khc n bn. Tr phi bn bit iu l khng xy ra, bn cn phi gi thit bn
trong mt lung chuyn quyn nu bn khng phi l trnh iu khin mc- cao nht.
LARGE_INTEGER timeout;
123/369
Trong s gi ny, i tng tr vo i tng bn mun i trn. Mc d i s ny
c nh my nh mt PVOID, n cn phi l mt con tr ti mt trong nhng i
tng thu pht c lit k trong Bng 4-1. i tng phi trong c nh s trang
k c-chng hn, trong mt cu trc m rng thit b hay vng d liu khc c cp
pht t nh s trang pool. Cho a s nhng mc ch, ngn xp thc hin c th c
xem xt c nh s trang.
LARGE_INTEGER timeout;
124/369
Nu bn ch r WaitAll, gi tr STATUS_SUCCESS tr li c ch bo rng tt c cc
i tng qun l t n bo hiu trng thi ng thi. Nu bn ch r WaitAny,
gi tr tr li bng s th bng ch s mng nhng i tng ca i tng n m tha
mn s ch i. Nu hn mt trong nhng i tng tnh c c bo hiu, bn s
c ni v mt trong s chng c th lowest- numbered ca tt c th m c bo
hiu vo khonh khc , tr phi c th mt vi cch khc. Bn c th ngh v php
cng gi tr STATUS_WAIT_0 ny cng vi ch s mng. Bn khng c th n gin
thc hin s th NT_SUCCESS thng thng ca trng thi tr v trc khi vic rt
ch s mng t m tnh trng, tuy nhin, bi v cc m tr v kh d khc (bao gm
STATUS_TIMEOUT, STATUS_ALERTED, v STATUS_USER_APC) cng i qua
s th. M s dng thch iu ny:
Bn s dng nhng chc nng dch v c lit k trong Bng 4-2 lm vic vi
nhng i tng s kin kernel. khi to mt i tng s kin, d tr u tin
nonpaged cho mt i tng ca kiu KEVENT v sau gi l KeInitializeEvent:
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
125/369
c t li bi ti liu trong kiu ngi s dng. Mt s kin ng b ha, mt khc,
c t li ti trng thi khng - bo hiu ngay khi mt lung n c gii phng.
y l ci g xy ra trong kiu ngi s dng khi ngi no gi l SetEvent trn mt
i tng s kin t khi ng li. Thao tc duy nht c thc hin trn mt i tng
s kin bi KeWaitXxx s t li mt s kin ng b ha ti khng phi - bo hiu.
Cui cng, initialstate TRUE ch r rng trng thi ban u ca s kin s c bo hiu
v FALSE ch r trng thi ban u khng phi - bo hiu.
CH :
126/369
Nh bao hm bi ASSERT, bn phi ang l chy ti hoc di DISPATCH_LEVEL
gi chc nng ny. i s s kin l mt con tr ti i tng s kin trong cu hi,
v s tng l mt gi tr c thm vo mt lung i quyn u tin nu vic t s
kin dn ti tha mn ngi no i. Nhn thy bn cnh (" m i s th ba lm
phin ti KeSetEvent ") cho mt gii thch ca i s Boolean i i s, mt trnh iu
khin WDM no m hu nh cha bao gi ch nh TRUE. Gi tr tr li khc khng
nu s kin bo hiu trng thi trc khi gi v 0 nu s kin l khng khng - Bo
hiu trng thi.
127/369
typedef struct _DEVICE_EXTENSION {
KEVENT lock;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
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);
129/369
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
delta, wait);
Kernel Timers
130/369
Bng 4-5. Cc chc nng dch v cho
vic s dng vi nhng i tng Thit
b bm gi Kernel
Service Function M t
KeCancelTimer Hy b mt thit b bm gi tch cc
Khi to mt thit b bm gi thng bo
KeInitializeTimer
trc kia
Khi to mt thng bo hay thng bo c
KeInitializeTimerEx c trng lp i lp li hay thit b bm
gi ng b ha
Xc nh trng thi hin thi ca mt thit
KeReadStateTimer
b bm gi
Ch r thi gian ht hn cho mt thng
KeSetTimer
bo thit b bm gi
Ch r s ht hn thi gian v nhng
KeSetTimerEx
thuc tnh khc ca mt thit b bm gi
C vi kch bn cch dng khc nhau cho nhng thit b bm gi, ti m t trong trong
vi mc tip theo:
KeInitializeTimer(timer);
131/369
Ti im ny, thit b bm gi khng - bo hiu trng thi v khng m xung-mt s
ch i trn thit b bm gi cha bao gi c tha mn. bt u s m thit b
bm gi, gi l KeSetTimer nh sau:
LARGE_INTEGER duetime;
KeInitializeTimerEx(timer, NotificationTimer);
132/369
LARGE_INTEGER duetime;
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:
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
KeInitializeTimer(timer);
133/369
Khi chng ti mun bt u s m thit b bm gi xung, chng ti ch r i tng
DPC nh mt trong nhng i s ti KeSetTimer HayKeSetTimerEx:
LARGE_INTEGER duetime;
PVOID junk2)
KeInitializeTimerEx(timer, SynchronizationTimer);
134/369
SynchronizationTimer l mt trong nhng gi tr ca s lit k TIMER_TYPE. Gi tr
khc l NotificationTimer.
LARGE_INTEGER duetime;
period, dpc);
Giai on y l theo mt chu k timeout, biu th trong nhng mili-giy (ms), v dpc
l mt con tr chn ti mt i tng KDPC. Mt thit b bm gi ca cch thc ny
ht hn mt ln vo thi gian n hn v nh k sau . t c s ht hn tun
hon chnh xc, ch r cng dng tng quan thi gian vi s tm ngng hot ng.
Vic ch r mt ch s khng vo thi gian gy ra thit b bm gi ngay lp tc ht
hn, v ci hnh vi tun hon bt qua. N thng c ngha bt u mt thit b
bm gi tun hon phi hp vi mt i tng DPC, bi cch, bi v vic cho php bn
c thng bo m khng phi nhiu ln i timeout.
Mt V d:
135/369
Mt s dng cho nhng thit b bm gi nhn c ch o mt vng kim tra tun t
trong mt lung h thng dnh cho nhim v ca vic nhiu ln kim tra mt thit b
cho hot ng. Khng phi nhiu thit b ngy nay cn c phc v bi mt vng kim
tra tun t, nhng ca bn c th mt ca vi ngoi l. Ti s bn lun ti ny trong
Chng 14, v ni dung bn bao gm mt trnh iu khin mu (POLLING) m minh
ha tt c cc khi nim lin quan. Mt phn m ly mu l vng sau y m thu c
thit b ti nhng khong c nh. Lgic ca trnh iu khin l vng nh vy c
th b t qung bng vic t mt s kin lm cht. Vy th, trnh iu khin s dng
KeWaitForMultipleObjects. M tht s phc tp hn on sau y, ti bin tp son
tho tp trung vo phn lin quan n thit b bm gi:
NTSTATUS status;
KTIMER timer;
KeInitializeTimerEx(&timer, SynchronizationTimer);
PVOID pollevents[] = {
(PVOID) &pdx->evKill,
(PVOID) &timer,
};
136/369
KeSetTimerEx(&timer, duetime, POLLING_INTERVAL, NULL);
while (TRUE)
status = KeWaitForMultipleObjects(arraysize(pollevents),
NULL, NULL);
if (status == STATUS_WAIT_0)
break;
<do something>;
KeCancelTimer(&timer);
PsTerminateSystemThread(STATUS_SUCCESS);
137/369
3. S pht biu KeSetTimerEx bt u mt thit b bm gi tun hon ang chy.
Duetimeis l 0, v vy thit b bm gi i ngay lp tc vo trong bo hiu trng
thi. N s ht hn mi 500 ms sau .
4. Trong khong thi gian kim tra tun t ca chng ti kim sot thnh vng,
chng ti i thit b bm gi ht hn hay cho s kin lm cht s c t.
Nu s ch i hon thnh bi v s kin lm cht, chng ti ri b vng, dn
sch s ln trn, v ra khi lung h thng ny. Nu s ch i hon thnh v
thit b bm gi ht hn, chng ti tip tc bc tip theo.
5. y l trnh iu khin thit b ca chng ti lm ci g lin quan n phn
cng ca chng ti.
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
LARGE_INTEGER duetime;
Alertable, &duetime);
KeStallExecutionProcessor(nMicroSeconds);
138/369
Nhng lung Nhn (Kernel Thread):
Ghi ch:
Hng cui: Thc hin nhng s ch i khng nhanh nhn tr phi bn bit bn khng
quyt tm.
139/369
Mt s phng php ng b khc (Other Kernel-Mode
Synchronization Primitives )
Nhn XP Windows a ra mt s phng php b sung ng b ha s thc hin
gia nhng lung hay bo v c truy nhp chia s nhng i tng. Trong mc
ny, ti s bn lun mutex nhanh, l mt i tng m nhng xut loi tr ln nhau
nhanh hn s thc hin so vi mt nhn mutex v n ti u ha cho trng hp trong
khng c tht s tranh dnh ang xut hin. Ti cng s m t phm tr ca nhng
chc nng h tr m bao gm t Interlocked trong tn ca chng . Nhng chc nng
ny thc hin nhng thao tc chung nht nh nh tng hoc gim mt s nguyn hay
vic chn hoc loi b mt mc t mt bn k lin kt trong mt cch nguyn t iu
ngn nga giao thoa a nhim hay a x l.
140/369
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.
Bt ng, ti liu DDK v nhng i tng mutex nhn lu ni rng nhn a cho
mt quyn u tin s tng ti mt lung m i hi mt mutex. Ti c nhng thng tin
ng tin cy rng iu tht s khng ng t nm 1992 (nm, ngha l, khng phi
Windows xy dng s). Ti liu cng lu ni rng mt lung gi mt mutex khng
th c loi b t s cn bng c thit lp(iu , c chinh phc ti vic cho di
chuyn tt c nhng trang ca n ra khi b nh vt l) y ng khi Windows NT cn
mi m nhng khng ng trong mt thi gian di.
ExInitializeFastMutex(FastMutex);
141/369
ExAcquireFastMutex(FastMutex);
or
ExAcquireFastMutexUnsafe(FastMutex);
ExReleaseFastMutex(FastMutex);
or
142/369
ExReleaseFastMutexUnsafe(FastMutex);
Interlocked Arithmetic
143/369
ExInterlockedAddLargeStatistic Thm gi tr vo ULONG
Thm gi tr vo ULONG v gi tr ban
ExInterlockedAddUlong
u nhng tr li
ExInterlockedCompareExchange64 Trao i hai gi tr 64- bit
LONG target;
144/369
LONG result = InterlockedCompareExchange(&target,
newval, oldval);
if (value == oldval)
*ptarget = newval;
return value;
Ni cch khc, chc nng lun lun tr li gi tr trc y ca bin ch cho bn. Ngoi
ra, nu gi tr trc cn bng vi oldval, n t ch bng newval m bn ch r. Chc
nng s dng mt thao tc nguyn t lm s so snh v s trao i sao cho s thay th
xy ra ch khi bn ng trong phng on ca cc bn v ni dung trc y. Bn cng
c th gi l chc nng InterlockedCompareExchangePointer thc hin mt thao tc
loi so snh- v- trao i tng t vi mt con tr. Chc nng ny cng c nh ngha
nh mt ngi bin tp- bn tnh (Ngha l, mt chc nng cho ngi bin tp no cung
cp mt s thi hnh inline) hay mt chc nng thc s gi, tip tc ph thuc nhng
con tr rng trn nn tng no cho bn bin dch v trn kh nng ca ngi bin tp
pht sinh m inline. Chc nng cui cng trong lp ny l InterlockedExchange , m
n gin s dng mt thao tc nguyn t thay th gi tr ca mt bin s nguyn v
tr li gi tr trc y :
LONG value;
Nh bn c l on c, c mt InterlockedExchangePointer m trao i mt gi
tr con tr na (64- bit hay 32-bit, ph thuc trn nn tng). Chc chn nm ch ca
thao tc trao i rnh mt li khi bin tp 64- bit nhng trnh iu khin:
145/369
PIRP Irp = (PIRP) InterlockedExchangePointer(
if (InterlockedExchange(&lock, 42) == 0)
sharedthing++;
nh ny s thc hin tt trn my tnh Intel x86, ni mi CPU nhn thy k c vit
trong cng mnh lnh. Trn kiu CPU khc, tuy nhin, c th l mt vn .
Mt CPU c l tht s thay i s kha bin thin k c thnh 0 trc khi vic cp
nht k c cho s pht biu tng dn. Hnh vi c th cho php hai CPUs ng thi
truy nhp sharedthing. Vn ny c th xy ra v cch m CPU thc hin nhng
thao tc trong ng song song hay v nhng thi quen trong b iu khin k c. Vy
th, bn cn phi Rework m s dng mt thao tc kha lng cho c hai s thay i
hm li:
if (InterlockedExchange(&lock, 42) == 0)
sharedthing++;
InterlockedExchange(&lock, 0);
146/369
Cc chc nng (ExInterlockedXxx Functions):
KSPIN_LOCK spinlock;
increment, &spinlock);
*pvalue += increment;
return prev;
147/369
ULONG value, increment;
KSPIN_LOCK spinlock;
ULONG Increment);
Initialization
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
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);
Removing Items
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
150/369
// Access list using noninterlocked calls:
VOID Function1()
KIRQL oldirql;
KeAcquireSpinLock(spinlock, &oldirql);
InsertHeadList(...);
RemoveTailList(...);
KeReleaseSpinLock(spinlock, oldirql);
VOID Function2()
ExInterlockedInsertTailList(..., spinlock);
151/369
DISPATCH_LEVEL, v Function2 l ni thc t, d sao i na- HIGH_LEVEL khi
n th mt cch quy thu nhn s kha.
152/369
Bi 13: THC HNH LP TRNH
DRIVER C BN
Thc hnh lp trnh driver c bn
Bi 1
Bi 2
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
MdlAddress (PMDL) is the address of a memory descriptor list (MDL) describing
the user-mode buffer associated with this request. The I/O Manager creates this MDL
for IRP_MJ_READ and IRP_MJ_WRITE requests if the topmost device objects flags
indicate DO_DIRECT_IO. It creates an MDL for the output buffer used with an
IRP_MJ_DEVICE_CONTROL request if the control code indicates
METHOD_IN_DIRECT or METHOD_OUT_DIRECT. The MDL itself describes the
user-mode virtual buffer and also contains the physical addresses of locked pages
containing that buffer. A driver has to do additional work, which can be quite minimal,
to actually access the user-mode buffer.
Flags (ULONG) contains flags that a device driver can read but not directly alter. None
of these flags are relevant to a Windows Driver Model (WDM) driver.
155/369
PendingReturned (BOOLEAN) is meaningful in a completion routine and indicates
whether the next lower dispatch routine returned STATUS_PENDING. This chapter
contains a disagreeably long discussion of how to use this flag.
Cancel (BOOLEAN) is TRUE if IoCancelIrp has been called to cancel this request and
FALSE if it hasnt (yet) been called. IRP cancellation is a relatively complex topic that
Ill discuss fully later on in this chapter (in Cancelling I/O Requests).
CancelIrql (KIRQL) is the interrupt request level (IRQL) at which the special cancel
spin lock was acquired. You reference this field in a cancel routine when you release the
spin lock.
UserBuffer (PVOID) contains the user-mode virtual address of the output buffer for
an IRP_MJ_DEVICE_CONTROL request for which the control code specifies
METHOD_NEITHER. It also holds the user-mode virtual address of the buffer for
read and write requests, but a driver should usually specify one of the device flags
DO_BUFFERED_IO or DO_DIRECT_IO and should therefore not usually need to
access the field for reads or writes. When handling a METHOD_NEITHER control
operation, the driver can create its own MDL using this address.
156/369
Figure 5-2. Map of the Tail union in an IRP.
Whenever any kernel-mode program creates an IRP, it also creates an associated array
of IO_STACK_LOCATION structures: one stack location for each of the drivers that
will process the IRP and sometimes one more stack location for the use of the originator
of the IRP. (See Figure 5-3.) A stack location contains type codes and parameter
information for the IRP as well as the address of a completion routine. Refer to Figure
5-4 for an illustration of the stack structure.
157/369
Figure 5-3. Parallelism between driver and I/O stacks.
A final consideration in calling the two synchronous IRP routines is that you cant create
just any kind of IRP using these routines. See Table 5-1 for the details. A common trick
for creating another kind of synchronous IRP is to ask for an IRP_MJ_SHUTDOWN,
which has no parameters, and then alter the MajorFunction code in the first stack
location.
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.
IRP-handling scenario numbers 5 and 8 at the end of this chapter contain cookbook
code for using asynchronous IRPs.
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:
stack->MajorFunction = IRP_MJ_Xxx;
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.
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):
IoSetNextIrpStackLocation(Irp);
stack->DeviceObject = DeviceObject;
160/369
return (*driver->MajorFunction[fcn])(DeviceObject, Irp);
As you can see, IoCallDriver simply advances the stack pointer and calls the appropriate
dispatch routine in the driver for the target device object. It returns the status code
that that dispatch routine returns. Sometimes I see online help requests wherein people
attribute one or another unfortunate action to IoCallDriver. (For example, IoCallDriver
is returning an error code for my IRP.) As you can see, the real culprit is a dispatch
routine in another driver.
IoGetDeviceObjectPointer
If you know the name of the device object, you can call IoGetDeviceObjectPointer as
shown here:
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
NTSTATUS status;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
&FileObject, &DeviceObject);
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:
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.
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.
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.
163/369
Manifest Constant Numeric Priority Boost
IO_NO_INCREMENT 0
IO_CD_ROM_INCREMENT 1
IO_DISK_INCREMENT 1
IO_KEYBOARD_INCREMENT 6
IO_MAILSLOT_INCREMENT 2
IO_MOUSE_INCREMENT 6
IO_NAMED_PIPE_INCREMENT 2
IO_NETWORK_INCREMENT 2
IO_PARALLEL_INCREMENT 1
IO_SERIAL_INCREMENT 2
IO_SOUND_INCREMENT 8
IO_VIDEO_INCREMENT 1
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.
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.
164/369
PVOID context)
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:
Ill have more to say about these return codes a bit further on in this chapter.
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.
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.
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.
166/369
would be against all the rules for IRP handling and not just the rules for completion
routines.
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
Hng i yu cu Vora (Queuing IO Requests)
Sometimes your driver receives an IRP that it cant handle right away. Rather than reject
the IRP by causing it to fail with an error status, your dispatch routine places the IRP on
a queue. In another part of your driver, you provide logic that removes one IRP from the
queue and passes it to a StartIo routine.
Apart from this sidebar, Im omitting discussion of the functions IoStartPacket and
IoStartNextPacket, which have been part of Windows NT since the beginning. These
functions implement a queuing model thats inappropriate for WDM drivers. In that
model, a device is in one of three states: idle, busy with an empty queue, or busy
with a nonempty queue. If you call IoStartPacket at a time when the device is idle,
it unconditionally sends the IRP to your StartIo routine. Unfortunately, many times a
WDM driver needs to queue an IRP even though the device is idle. These functions
also rely heavily on a global spin lock whose overuse has created a serious performance
bottleneck.
Just in case you happen to be working on an old driver that uses these obsolete routines,
however, heres how they work. A dispatch routine would queue an IRP like this:
IoMarkIrpPending(Irp);
return STATUS_PENDING;
Your driver would have a single StartIo routine. Your DriverEntry routine would set the
DriverStartIo field of the driver object to point to this routine. If your StartIo routine
completes IRPs, you would also call IoSetStartIoAttributes (in Windows XP or later) to
help prevent excessive recursion into StartIo. IoStartPacket and IoStartNextPacket call
StartIo to process one IRP at a time. In other words, StartIo is the place where the I/O
manager serializes access to your hardware.
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:
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.
Queuing an IRP is conceptually very simple. You can provide a list anchor in your
device extension, which you initialize in your AddDevice function:
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:
169/369
{
if (pdx->DeviceBusy)
InsertTailList(&pdx->IrpQueue, &Irp->Tail.Overlay.ListEntry);
else
pdx->DeviceBusy = TRUE;
StartIo(pdx->DeviceObject, Irp);
if (IsListEmpty(&pdx->IrpQueue))
pdx->DeviceBusy = FALSE;
else
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:
LIST_ENTRY IrpQueue;
KSPIN_LOCK IrpQueueLock;
BOOLEAN DeviceBusy;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
InitializeListHead(&pdx->IrpQueue);
KeInitializeSpinLock(&pdx->IrpQueueLock);
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);
KIRQL oldirql;
KeAcquireSpinLock(&pdx->IrpQueueLock, &oldirql);
if (IsListEmpty(&pdx->IrpQueue)
pdx->DeviceBusy = FALSE;
KeReleaseSpinLock(&pdx->IrpQueueLock, oldirql);
else
172/369
KeReleaseSpinLock(&pdx->IrpQueueLock,
DISPATCH_LEVEL);
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.
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:
DEVQUEUE dqReadWrite;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
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(...)
InitializeQueue(&pdx->dqReadWrite, StartIo);
174/369
IRP flow with a DEVQUEUE and a StartIo routine.
You can specify a common dispatch function for both IRP_MJ_READ and
IRP_MJ_WRITE:
PUNICODE_STRING RegistryPath)
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;
#pragma PAGEDCODE
175/369
PAGED_CODE();
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoMarkIrpPending(Irp);
return STATUS_PENDING;
#pragma LOCKEDCODE
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.
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:
KDPC StartNextDpc;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS AddDevice(...)
KeInitializeDpc(&pdx->StartNextDpc,
VOID StartIo(...)
IoCompleteRequest(...);
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
StartIo returns. Therefore, StartNextDpcRoutine can call StartNextPacket without
worrying about recursion.
IO_CSQ_IRP_CONTEXT RedContext;
IO_CSQ_IRP_CONTEXT BlueContext;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
When you receive a red IRP, you specify the context structure in your call to
IoCsqInsertIrp:
When you later decide you want to complete a parked IRP, you write code like this:
if (RedIrp)
RedIrp->IoStatus.Status = STATUS_XXX;
RedIrp->IoStatus.Information = YYY;
IoCompleteRequest(RedIrp, IO_NO_INCREMENT);
IoCsqRemoveIrp will return NULL if the IRP associated with the context structure has
already been cancelled.
Its up to you to make sure that you havent previously parked an IRP using a
particular context structure. IoCsqInsertIrp is a VOID function and therefore
has no way to tell you when you violate this rule.
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
Hy b yu cu vora (Cancelling IO Requests )
Just as happens with people in real life, programs sometimes change their mind about
the I/O requests theyve asked you to perform for them. Were not talking about simple
fickleness here. Applications might terminate after issuing requests that will take a long
time to complete, leaving requests outstanding. Such an occurrence is especially likely
in the WDM world, where the insertion of new hardware might require you to stall
requests while the Configuration Manager rebalances resources or where you might be
told at any moment to power down your device.
To cancel a request in kernel mode, someone calls IoCancelIrp. The operating system
automatically calls IoCancelIrp for every IRP that belongs to a thread thats terminating
with requests still outstanding. A user-mode application can call CancelIo to cancel
all outstanding asynchronous operations issued by a given thread on a file handle.
IoCancelIrp would like to simply complete the IRP its given with
STATUS_CANCELLED, but theres a hitch: IoCancelIrp doesnt know where you have
salted away pointers to the IRP, and it doesnt know for sure whether youre currently
processing the IRP. So it relies on a cancel routine you provide to do most of the work
of cancelling an IRP.
When you queue an IRP, you set the CancelRoutine pointer in the IRP to the
address of your cancel routine. When you dequeue the IRP, you set
CancelRoutine to NULL.
IoCancelIrp unconditionally sets the Cancel flag in the IRP. Then it checks to
see whether the CancelRoutine pointer in the IRP is NULL. While the IRP is in
180/369
your queue, CancelRoutine will be non-NULL. In this case, IoCancelIrp calls
your cancel routine. Your cancel routine removes the IRP from the queue
where it currently resides and completes the IRP with
STATUS_CANCELLED.
Once you dequeue the IRP, IoCancelIrp finds the CancelRoutine pointer set to
NULL, so it doesnt call your cancel routine. You process the IRP to
completion with reasonable promptness (a concept that calls for engineering
judgment), and it doesnt matter to anyone that you didnt actually cancel the
IRP.
Synchronizing Cancellation
In earlier times, driver programmers dealt with the cancel races by using a global spin
lockthe cancel spin lock. Because you shouldnt use this spin lock for synchronization
in your own driver, Ive explained it briefly in the sidebar. Read the sidebar for its
historical perspective, but dont plan to use this lock.
Here is a sketch of IoCancelIrp. You need to know this to correctly write IRP-handling
code. (This isnt a copy of the Windows XP source codeits an abridged excerpt.)
IoAcquireCancelSpinLock(&Irp->CancelIrql);
Irp->Cancel = TRUE;
if (CancelRoutine)
181/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
Cancelling IRPs You Create or Handle
Sometimes youll want to cancel an IRP that youve created or passed to another driver.
Great care is required to avoid an obscure, low-probability problem. Just for the sake of
illustration, suppose you want to impose an overall 5-second timeout on a synchronous
I/O operation. If the time period elapses, you want to cancel the operation. Here is some
naive code that, you might suppose, would execute this plan:
SomeFunction()
KEVENT event;
IO_STATUS_BLOCK iosb;
KeInitializeEvent(&event, ...);
if (status == STATUS_PENDING)
LARGE_INTEGER timeout;
timeout.QuadPart = -5 * 10000000;
FALSE, NULL);
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.
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, ...);
if (status == STATUS_PENDING)
LARGE_INTEGER timeout;
185/369
timeout.QuadPart = -5 * 10000000;
FALSE, NULL);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
if (Irp->PendingReturned)
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.
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,
IoCallDriver(..., Irp);
If you decide later on that you want to cancel this IRP, do something like the following:
PIRP Irp =
if (Irp)
IoCancelIrp(Irp);
if (InterlockedExchange(&pdx->CancelFlag, 1)
IoFreeIrp(Irp);
This function dovetails with the completion routine you install for the 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 Cancel-
Routine 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.
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.
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:
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
KEVENT event;
if (status == STATUS_PENDING)
LARGE_INTEGER timeout;
timeout.QuadPart = -5 * 10000000;
190/369
{
IoCancelIrp(Irp);
FALSE, NULL);
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
if (Irp->PendingReturned)
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.
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.
PIRP TheIrp;
ULONG CancelFlag;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext(Irp);
(PVOID) pdx,
pdx->CancelFlag = 0;
pdx->TheIrp = Irp;
IoMarkIrpPending(Irp);
IoCallDriver(pdx->LowerDeviceObject, Irp);
return STATUS_PENDING;
192/369
VOID CancelTheIrp(PDEVICE_EXTENSION pdx)
if (Irp)
IoCancelIrp(Irp);
if (InterlockedExchange(&pdx->CancelFlag, 1))
IoCompleteRequest(Irp, IO_NO_INCREMENT);
PDEVICE_EXTENSION pdx)
InterlockedExchange(&pdx->CancelFlag, 1))
return STATUS_SUCCESS;
return STATUS_MORE_PROCESSING_REQUIRED;
This code is similar to the code I showed earlier for cancelling your own asynchronous
IRP. Here, however, allowing IoCompleteRequest to finish completing the IRP takes
the place of the call to IoFreeIrp we made when we were dealing with our own IRP.
If the completion routine is last on the scene, it returns STATUS_SUCCESS to allow
IoCompleteRequest to finish completing the IRP. If CancelTheIrp is last on the scene,
193/369
it calls IoCompleteRequest to resume the completion processing that the completion
routine short-circuited by returning STATUS_MORE_PROCESSING_REQUIRED.
One extremely subtle point regarding this example is the call to IoMarkIrpPending in
the dispatch routine. Ordinarily, it would be safe to just do this step conditionally in the
completion routine, but not this time. If we should happen to call CancelTheIrp in the
context of some thread other than the one in which the dispatch routine runs, the pending
flag is needed so that IoCompleteRequest will schedule an APC to clean up the IRP in
the proper thread. The easiest way to make that true is simplealways mark the IRP
pending.
Handling IRP_MJ_CLEANUP
Closely allied to the subject of IRP cancellation is the I/O request with the major
function code IRP_MJ_CLEANUP. To explain how you should process this request, I
need to give you a little additional background.
When applications and other drivers want to access your device, they first open a
handle to the device. Applications call CreateFile to do this; drivers call ZwCreateFile.
Internally, these functions create a kernel file object and send it to your driver in an
IRP_MJ_CREATE request. When the entity that opened the handle is done accessing
your driver, it will call another function, such as CloseHandle or ZwClose. Internally,
these functions send your driver an IRP_MJ_CLOSE request. Just before sending you
the IRP_MJ_CLOSE, however, the I/O Manager sends you an IRP_MJ_CLEANUP so
that you can cancel any IRPs that belong to the same file object but that are still sitting
in one of your queues. From the perspective of your driver, the one thing all the requests
have in common is that the stack location you receive points to the same file object in
every instance.
Figure 5-10 illustrates your responsibility when you receive IRP_MJ_CLEANUP. You
should run through your queues of IRPs, removing those that are tagged as belonging to
the same file object. You should complete those IRPs with STATUS_CANCELLED.
194/369
Driver responsibility for IRP_MJ_CLEANUP.
File Objects
Ordinarily, just one driver (the function driver, in fact) in a device stack implements
all three of the following requests: IRP_MJ_CREATE, IRP_MJ_CLOSE, and
IRP_MJ_CLEANUP. The I/O Manager creates a file object (a regular kernel object) and
passes it in the I/O stack to the dispatch routines for all three of these IRPs. Anybody
who sends an IRP to a device should have a pointer to the same file object and should
insert that pointer into the I/O stack as well. The driver that handles these three IRPs
acts as the owner of the file object in some sense, in that its the driver thats entitled to
use the FsContext and FsContext2 fields of the object. So your DispatchCreate routine
can put something into one of these context fields for use by other dispatch routines and
for eventual cleanup by your DispatchClose routine.
Its easy to get confused about IRP_MJ_CLEANUP. In fact, programmers who have a
hard time understanding IRP cancellation sometimes decide (incorrectly) to just ignore
this IRP. You need both cancel and cleanup logic in your driver, though:
IRP_MJ_CLEANUP means a handle is being closed. You should purge all the
IRPs that pertain to that handle.
The I/O Manager and other drivers cancel individual IRPs for a variety of
reasons that have nothing to do with closing handles.
195/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.
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
CleanupRequests(&pdx->dqReadWrite, fop,
STATUS_CANCELLED);
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.
196/369
NTSTATUS status)
LIST_ENTRY cancellist;
InitializeListHead(&cancellist);
KIRQL oldirql;
KeAcquireSpinLock(&pdq->lock, &oldirql);
PLIST_ENTRY next;
Tail.Overlay.ListEntry);
next = next->Flink;
continue;
if (!IoSetCancelRoutine(Irp, NULL))
continue;
RemoveEntryList(current);
InsertTailList(&cancellist, current);
197/369
KeReleaseSpinLock(&pdq->lock, oldirql);
while (!IsListEmpty(&cancellist))
next = RemoveHeadList(&cancellist);
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.
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):
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
PIRP qirp;
: pdx->IrpQueueAnchor.Flink;
199/369
while (next != &pdx->IrpQueueAnchor)
Tail.Overlay.ListEntry);
PIO_STACK_LOCATION stack =
IoGetCurrentIrpStackLocation(NextIrp);
== stack->FileObject)
return NextIrp;
next = next->Flink;
return NULL;
200/369
Tm lc cc kch bn x l (SummaryEight IRP-
Handling Scenarios)
Mc d chiu di ca nhng gii thch c trc, s dng IRP tht s hon ton d dng.
Bi s tnh ca ti, ch c tm kch bn mt cch ng k khc nhau thng dng, v m
c yu cu x l nhng kch bn tng i n gin. Trong mc cui cng ny
ca chng ny, Ti tp hp mt s bc tranh v m ly mu gip bn sp xp li
tt c kin thc l thuyt.
201/369
Hnh 5-11. S Chuyn xung vi s hon thnh th tc .
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
if (!NT_SUCCESS(status))
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) CompletionRoutine,
202/369
}
PDEVICE_EXTENSION pdx)
if (Irp->PendingReturned)
IoMarkIrpPending(Irp);
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
return STATUS_SUCCESS;
203/369
Hnh 5-12. S Chuyn xung khng c s hon thnh th tc .
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
if (!NT_SUCCESS(status))
IoSkipCurrentIrpStackLocation (Irp);
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
204/369
return status;
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
Irp->IoStatus.Status = STATUS_XXX;
Irp->IoStatus.Information = YYY;
205/369
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_XXX;
206/369
DEVQUEUE dqReadWrite;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
PDEVICE_OBJECT pdo)
InitializeQueue(&pdx->dqReadWrite, StartIo);
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
IoMarkIrpPending(Irp);
return STATUS_PENDING;
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
207/369
CancelRequest(&pdx->dqReadWrite, Irp);
Irp->IoStatus.Status = STATUS_XXX;
Irp->IoStatus.Information = YYY;
PDEVICE_EXTENSION pdx)
StartNextPacket(&pdx->dqReadWrite, fdo);
208/369
IoCompleteRequest(Irp, IO_NO_INCREMENT);
PDEVICE_OBJECT DeviceObject)
209/369
(PVOID) 42);
if (!NT_SUCCESS(status))
return <status>;
PIRP Irp;
...);
-or-
stack->MajorFunction = IRP_MJ_XXX;
<additional initialization)
IoSetCompletionRoutine[Ex]([pdx->DeviceObject,] Irp,
ObReferenceObject(DeviceObject);
IoCallDriver(DeviceObject, Irp);
ObDereferenceObject(DeviceObject);
210/369
NTSTATUS CompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp,
PDEVICE_EXTENSION pdx)
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
NTSTATUS CompletionRoutine(...)
211/369
{
PMDL mdl;
Irp->MdlAddress = mdl->Next;
// called MmProbeAndLockPages
IoFreeMdl(mdl);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
212/369
Trong kch bn ny bn to nn mt ng b IRP, bn chuyn tip ti trnh iu khin
khc. Xem hnh 5-16. Chp nhn chin lc ny khi tt c s theo sau ng:
PDEVICE_OBJECT DeviceObject)
213/369
(PVOID) 42);
if (!NT_SUCCESS(status))
return <status>;
PIRP Irp;
KEVENT event;
IO_STATUS_BLOCK iosb;
Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_XXX,
-or-
if (status == STATUS_PENDING)
FALSE, NULL);
status = iosb.Status;
214/369
IoReleaseRemoveLock(&pdx->RemoveLock, (PVOID) 42);
Bn khng phi lm qut dn sau khi IRP ny! Qun l vo/ra lm n t ng.
215/369
Hnh 5-17. S chuyn qua ng b xung .
KEVENT event;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)
if (status == STATUS_PENDING)
216/369
FALSE, NULL);
status = Irp->IoStatus.Status;
return status;
if (Irp->PendingReturned)
return STATUS_MORE_PROCESSING_REQUIRED;
217/369
Hnh 5-18. IRP khng ng b c x l ng b .
PDEVICE_OBJECT DeviceObject)
(PVOID) 42);
if (!NT_SUCCESS(status))
return <status>;
PIRP Irp;
218/369
Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_XXX, DeviceObject,
...);
-or-
Stack->MajorFunction = IRP_MJ_XXX;
<additional initialization)
KEVENT event;
IoSetCompletionRoutine[Ex]([pdx->DeviceObject], Irp,
(PIO_COMPLETION_ROUTINE) CompletionRoutine,
if (status == STATUS_PENDING)
FALSE, NULL);
PKEVENT pev)
219/369
if (Irp->PendingReturned)
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
220/369
Bi 15: THC HNH LP TRNH
DRIVER CHO X L IRP
Thc hnh mt s bi lp trnh driver c bn
Bi 1.
Bi 2.
Bi 3.
221/369
Bi 16: C V GHI D LIU
Cu hnh thit b ca bn (Configuring Your Device )
Trong chng trc, ti tho lun vi bn v IRP-MJ-PNP cho thit b cm v
chy (Plug and Play). IRP_MN_START_DEVICE l mt phng tin cung cp cho
bn cc thng tin v cc ngun vo/ra ci m c ch nh bi PnP Manager bn
s dng. Ti ch cho bn cch t c ng thi list cc cch thc n gin
(cha tinh t) v cch dch cc m t ngun v lm sao c th gi tr gip hm
StartDevice m bn c th thy nguyn mu nh sau:
PCM_PARTIAL_RESOURCE_LIST raw,
PCM_PARTIAL_RESOURCE_LIST translated)
222/369
Hnh 7-1. Structure of a partial resource list.
PCM_PARTIAL_RESOURCE_LIST raw,
PCM_PARTIAL_RESOURCE_LIST translated)
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource =
223/369
translated->PartialDescriptors;
switch (resource->Type)
case CmResourceTypePort:
break;
case CmResourceTypeInterrupt:
break;
case CmResourceTypeMemory:
break;
case CmResourceTypeDma:
break;
224/369
}
225/369
Possibly map port range; save base port address in
Port
device extension
Map memory range; save base address in device
Memory
extension
Dma Call IoGetDmaAdapter to create an adapter object
Call IoConnectInterrupt to create an interrupt object
Interrupt
that points to your interrupt service routine (ISR)
226/369
a ch mt B m d liu (Addressing a Data Buffer )
Khi mt ng dng bt u thao tc c hay ghi, n s cung cp mt vng m d liu
thng qua cch cung cp cho b qun l vo/ra mt ch ngi dung a ch o v
chiu di ca n. Nh ti trnh by trong chng 3 trc y, mt nhn iu khin
rt him khi truy xut vo b nh m s dng ch ngi dung vi a ch o bi v,
nhn chung, bn chc chn khng th cht c cc lung. Microsoft Windows XP cung
cp cho bn 3 cch truy xut mt b m d liu ch ngi dung:
Hnh 7.2 minh ho hai phng thc u. Phng thc cui cng, tt nhin l phng
thc m h thng khng lm g c c th gip bn n gn (ly c) d liu ca
bn.
227/369
Hnh 7-2. Accessing user-mode data buffers.
Bn tin hnh nh r mt phng thc vng m c hay ghi bng cch thit lp cc
bit c trong i tgn thit b ca bn ngay sau khi bn to ra hm AddDivice:
NTSTATUS AddDevice(...)
PDEVICE_OBJECT fdo;
IoCreateDevice(..., &fdo);
fdo->Flags = DO_BUFFERED_IO;
<or>
fdo->Flags = DO_DIRECT_IO;
<or>
length);
if (writing)
228/369
Irp->AssociatedIrp.SystemBuffer = sva;
if (reading)
stack->Parameters.Read.Length = length;else
stack->Parameters.Write.Length = length;
if (reading)
ExFreePool(sva);
CSHORT Size;
CSHORT MdlFlags;
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.
Theo cch ny, chng ta chng bao gi truy cp trc tip ti cc thnh phn ca cu trc
MDL. Chng ta s dng cc Macro v nng cp cc hm nh trong bng 7.2
230/369
Builds an MDL for a subset of an existing
IoBuildPartialMdl
MDL.
IoFreeMdl Destroys an MDL.
Modifies an MDL to describe a region of
MmBuildMdlForNonPagedPool
kernel-mode nonpaged memory.
MmGetMdlByteCount Determines byte size of buffer.
MmGetMdlByteOffset Gets buffer offset within first page.
MmGetMdlPfnArray Locates array of physical page pointers.
MmGetMdlVirtualAddress Gets virtual address.
Creates a kernel-mode virtual address that maps
MmGetSystemAddressForMdl
to the same locations in memory.
Same as MmGetSystemAddressForMdl but
MmGetSystemAddressForMdlSafe
preferred in Windows 2000 and later systems.
(Re)initializes an MDL to describe a given
MmInitializeMdl
virtual buffer.
Creates a kernel-mode virtual address that maps
MmMapLockedPages
to the same locations in memory.
Similar to MmMapLockedPages but preferred
MmMapLockedPagesSpecifyCache
in Windows 2000 and later systems.
MmPrepareMdlForReuse Reinitializes an MDL.
MmProbeAndLockPages Locks pages after verifying address validity.
Determines how much memory would be
needed to create an MDL to describe a given
MmSizeOfMdl virtual buffer. You dont need to call this
routine if you use IoAllocateMdl to create the
MDL in the first place.
MmUnlockPages Unlocks the pages for this MDL.
MmUnmapLockedPages Undoes a previous MmMapLockedPages.
231/369
PMDL mdl = IoAllocateMdl(uva, length, FALSE, TRUE, Irp);
MmProbeAndLockPages(mdl, mode,
MmUnlockPages(mdl);
IoFreeMdl(mdl);
232/369
Cc cng v cc thanh ghi (Ports and Registers )
Windows XP s dng m hnh my tnh tru tng nh c m t trong hnh 7.4
cung cp mt giao din driver hp nht nh trong kin trc ca CPU. Trong ch ny,
mt CPU c th c b nh ring bit v cc khng gian a ch. truy cp vo b nh
thit b, CPU s giao cng vic cho mt dng b nh khc nh l mt b nh load hay
lu truy cp trc tip n mt a ch o. CPU dch a ch o ra thnh a ch vt l
bng cch thit lp cc bng trang. truy cp vo mt thit b vo ra c s
ho, bng mt cch khc, CPU cu cu ti mt h thng c bit l x86 vi li ch dn
vo v ra.
Rng hn khi bn di chuyn c iu kin mt lot code c bin dch trong trnh iu
khin ca bn cho tt c cc th hin c th, cc nh thit k Windows Nt sng to
233/369
ra mt lp cc phn cng tru tng (Hal), ci m ti m ch mt vi ln trong cun
sch ny. Hal cung cp cc hm ci m bn s dng truy xut ti cc ti nguyn b
nh v cc cng.
Bng 7.3. Cc hm Hal cho vic truy cp cc cng v cc thanh ghi b nh.
Table 7-3.
HAL
Functions
for
Accessing
Ports and
Memory
Registers
Access
Functions for Port Access Functions for Memory Access
Width
READ_PORT_UCHAR READ_REGISTER_UCHAR
8 bits
WRITE_PORT_UCHAR WRITE_REGISTER_UCHAR
READ_PORT_USHORT READ_REGISTER_USHORT
16 bits
WRITE_PORT_USHORT WRITE_REGISTER_USHORT
READ_PORT_ULONG READ_REGISTER_ULONG
32 bits
WRITE_PORT_ULONG WRITE_REGISTER_ULONG
String of READ_PORT_BUFFER_UCHAR READ_REGISTER_BUFFER_UCHAR
8-bit bytes WRITE_PORT_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 READ_REGISTER_BUFFER_ULONG
32-bit -
WRITE_PORT_BUFFER_ULONG WRITE_REGISTER_BUFFER_ULONG
doublewords
234/369
Windows 98/ME tin xa hn .. lu tr trn li gi ca trnh iu khin vi mt li
gi IN hin ti trong mt s trng hp. The Alpha version of this routine performs
a memory fetch. Phin bn intel x86 ca Read_Register_uchar cng thc hin mt l
trnh b nh. . Theo cch khc, phin bn nh vng m ca hm ny (Read-regist-
unchar) thc hin thm mt s cng vic trong mi trng x86 chc chn rngtt c
cc b nh cache c xo (lm sch) mt cch hp l khi m hot ng ny kt thc.
PUCHAR portbase;
ULONG nports;
BOOLEAN mappedport;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
switch (resource->Type)
235/369
{
case CmResourceTypePort:
portbase = resource->u.Port.Start;
pdx->nports = resource->u.Port.Length;
pdx->mappedport =
break;
if (pdx->mappedport)
pdx->nports, MmNonCached);
if (!pdx->portbase)
return STATUS_NO_MEMORY;
else
236/369
pdx->portbase = (PUCHAR) portbase.QuadPart;
VOID StopDevice(...)
MmUnmapIoSpace(pdx->portbase, pdx->nports);
pdx->portbase = NULL;
237/369
}
PUCHAR membase;
ULONG nbytes;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
switch (resource->Type)
case CmResourceTypeMemory:
membase = resource->u.Memory.Start;
238/369
pdx->nbytes = resource->u.Memory.Length;
break;
MmNonCached);
if (!pdx->membase)
return STATUS_NO_MEMORY;
1. Trong sut phn ngun trn (code), u.memory c cc thong tin vti nguyn
b nh. U.memory.Start l a ch bt u ca mt khong (phm vi) lin tip
cc vng ca b nh, v u.memory.length l s byte ca c phm vi . a ch
bt u l mt gi tr a ch vt l 64 bits. Khng phi ngu nhin m u.port v
u.memory l gng nhau- l mt vic lm c mc ch v b c th kim tra
li thy iu ny ng nu bn mun
2. Bn phi gog hm MnMapopace t c nhn ch a ch o thong
qua phm vi b nh c th c truy xut.
VOID StopDevice(...)
if (pdx->membase)
MmUnmapIoSpace(pdx->membase, pdx->nbytes);
pdx->membase = NULL;
239/369
}
240/369
Phc v ngt (Servicing an Interrupt )
Cu hnh mt ngt (Configuring an Interrupt )
PKINTERRUPT InterruptObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
241/369
switch (resource->Type)
case CmResourceTypeInterrupt:
vector = resource->u.Interrupt.Vector;
affinity = resource->u.Interrupt.Affinity;
? Latched : LevelSensitive;
irqshare =
resource->ShareDisposition == CmResourceShareShared;
break;
status = IoConnectInterrupt(&pdx->InterruptObject,
242/369
vector, irql, irql, mode, irqshare, affinity, FALSE);
243/369
{
return FALSE;
<handle interrupt>
return TRUE;
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.
PDEVICE_EXTENSION pdx)
244/369
UCHAR devstatus = READ_PORT_UCHAR(pdx->portbase);
return FALSE;
<etc.>
NTSTATUS AddDevice(...)
PDEVICE_OBJECT fdo;
IoCreateDevice(..., &fdo);
IoInitializeDpcRequest(fdo, DpcForIsr);
245/369
}
BOOLEAN OnInterrupt(...)
246/369
Hnh 7-5. Tin trnh ca DPC requests.
PDEVICE_EXTENSION pdx)
VOID DpcForIsr(...)
StartNextPacket(&pdx->dqRead, fdo);
247/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..
KDPC CustomDpc;
};
KeInitializeDpc(&pdx->CustomDpc,
248/369
Ngoi ra, bn c th g b mt i tng DPC t mt hng i x l bng vic triu gi
KeRemoveQueueDpc.
NTSTATUS StartDevice(...)
ResetDevice(pdx);
status = IoConnectInterrupt(...);
KeSynchronizeExecution(pdx->InterruptObject,
return STATUS_SUCCESS;
249/369
PAGED_CODE();
LARGE_INTEGER timeout;
INTCSR_INTERRUPT_MASK);
250/369
nonarbitrary thread context. Cc iu kin c gp bi v b gi cui
cng l PnP Manager, m gi cho chng ta mt IRP_MN_START_DEVICE
trong s mong i y rng chng ta ang hn ch lung h thng
3. Bc cui cng trong vic thit lp thit bi l xa cc ngt cn treo pending
interupts.. S5933 c 6 c ngt trong mt iu khin ngt/i tng trng thi
(interrupt control/status register) (INTCSR). Vic vit mt 1 bits trong 6 v tr
ny s xa tt c cc ngt treo. (Nu chng ta vit li mt gi tr mt n m c
mt bit 0 trong cc v tr c ngt, trng thi ca ngt khng nh hng. Kiu
bit c ny c gi l read/write-clear hoc n gin l R/WC.) Cc bit khc
trong INTCSR cho php cc ngt ca cc kiu khc nhau. Bng vic vit 0 bit
(bit 0 ?) 0 bitstrong cc im ny, chng ta ang lm mt i kh nng thit b
t ti qui m ln nht c th.
Hm SetupDevice l kh n gin :
INTCSR_IMBI_ENABLE
);
251/369
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
if (!stack->Parameters.Read.Length)
StartNextPacket(&pdx->dqReadWrite, fdo);
return;
pdx->nbytes = stack->Parameters.Read.Length;
pdx->numxfer = 0;
KeSynchronizeExecution(pdx->InterruptObject,
252/369
By gi l lc thit lp c v gi tr TRUE. Ging nh thng thng khi chng ta gii
quyt vi mt ti nguyn chia s , chng ta cn phi ng b vic thit lp c vi on
m trong ISR m kim tra n, v theo cn phi vin dn mt th tc SynchCritSection
ging nh ti tho lun t trc. Ngai ra, c th xy ra mt byte d liu c sn
ri. trong trng hp th ngt u tin s khng bao gi xy ra . TransferFirst l mt
th tc tr gip m kim tra vic c v nhng kt qu c th xy ra cho byte u tin
ny. Hm thm vo add-on function c nhiu cch nhn bit vic xa sch hp
mail (hp mail rng), v th n c th on chng gi byte tip theo vo thi im
thch hp.
. y l TransferFirst:
253/369
S dng ngt (Handling the Interrupt )
Trong thao tc thng thng vi PCI42, cc ngt S5933 khi mt byte d liu mi n
mt hp th 1. ISR sau y s ginh c iu khin:
PDEVICE_EXTENSION pdx)
ULONG intcsr =
return FALSE;
if (pdx->busy)
if (Irp->Cancel)
status = STATUS_CANCELLED;
else
status = AreRequestsBeingAborted(&pdx->dqReadWrite);
if (!NT_SUCCESS(status))
254/369
}
++pdx->buffer;
++pdx->numxfer;
if (!--pdx->nbytes)
Irp->IoStatus.Information = pdx->numxfer;
dpc = TRUE;
status = STATUS_SUCCESS;
255/369
intcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR));
if (dpc)
pdx->busy = FALSE;
Irp->IoStatus.Status = status;
return TRUE;
256/369
mt yu cu ang hot ng l mt iu hp l lm vi mt thit b chng
hn nh s thu thp byte tng byte ny (proceeds byte by byte) . Tng t
nh vy, mt tng hay kim tra liu rng IRP c b dng li hay khng
nu nh n chim qu nhiu thi gian kt thc IRP. Nu cc thit b ngt ca
bn ch khi c thc hin vi mt vic truyn ti di, bn c th b i bc
kim tra ny ra khi ISR ca mnh.
4. By gi chng ta bt tay vo mt vng lp m s kt thc khi tt c cc ngt
thit b hin hnh c xa. cui vng lp, chng ta s c li INTCSR
quyt nh xem liu rng bt k cc iu kin ngt no c th pht sinh. Nu
nh vy, chng ta s lp li vng lp . Chng ta khng bn ti thi gian CPU
y- chng ta mun trnh vic cc ngt chy nh thc nc vo h thng
bi v vic phc v mt ngt l tng i t
5. Nu S5933 b ngt bi v mt s kin mailbox , chng ta s c mt byte d
liu mi t mailbox vo trong mt b m I/O cho IRP hin hnh. Nu bn tm
kim mt thanh ghi MBEF ngay sau khi c, bn s thy rng vic c xa bit
tng ng ca thanh ghi mailbox t 1 v 0 (inbound mailbox register 1, byte
0). Ch rng chng ta khng cn thit kim tra MBEF quyt nh xem liu
rng byte ca chng ta thc th c thay i hay khng bi v chng ta lp
trnh cho thit b ch ngt vo lc c mt thay i ti byte n.
6. Vic ghi INTCSR vi ni dung trc ca n c nh hng ti vic xa bit
ngt th 6 R/WC, khng thay i mt vi bit ch c (read-only bits), v bo
ton ci t gc ca tt c cc bit iu khin ch c
7. y chng ta c INTCSR quyt nh xem liu rng cc iu kin ngt
thm vo c xut hin hay khng. nu c chng ta s lp li vng lp
phc v cho chng.
8. Ging nh chng ta tin hnh trn cc on code trc, chng ta thit lp
bin BOOLEANdpc tr thnh TRUE nu mt DPC by gi thch hp hon
thnh IRP hin hnh.
PDEVICE_EXTENSION pdx)
StartNextPacket(&pdx->dqReadWrite, fdo);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
257/369
Testing PCI42
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
Truy nhp b nh trc tip (Direct Memory Access )
Windows XP h tr vic truy cp trc tip b nh thong qua mt m hnh my tnh tru
tng c m t hnh 7.6. Trong hnh ny, my tnh c coi nh l c mt tp hp
s cc thanh ghi ci m c chuyn i gia a ch vt l ca CPU v a ch bus.
Mi s a ch thanh ghi ny lu gi a ch ca mt trang vt l no . Phn cng
truy cp b nh c hay ghi bng cch ch ra a ch bus hay a ch logic. S cc
thanh ghi ny thc hin cng mt vai tr khi tip nhn bng trang cho phn mm bng
cch cho php phn cng s dng cc gi tr s khc nhau cho cc a ch ca n hn l
cho CPU hiu.
259/369
Nhn ca Windows XP s dng mt cu trc d liu c bit n nh l i tng iu
hp m t cc c tnh DMA ca thit b v iu khin truy cp n cc ngun
c chia s, nh l h thng cc knh DMA v s cc thanh ghi. Bn s ly mt
con tr tr ti i tng iu hp bi li gi IOGetDmAAdapter trong sut qu trnh
StartDevice ca bn. i tng iu hp s c mt con tr tr ti mt cu trc c
gi l DmaOperations ci m khi n bt th cha cc con tr tr ti cc hm m bn
mun gi. Hy xem bng 7.4. Cc hm ny ch ra v tr ch ca hm (v d nh ..) ci
m bn phi s dng phin bn trc ca Windown NT. Thc t, tn ch ny c trong
cc Macro cc m c khai bo trong hm DmaOperations.
260/369
1. Nu thit b ca bn c Bus-Mastering capability, tt nhin l n cn c in
truy cp vo b nh chnh nu nh bn yu cu n mt s chc nng c bn.
nh l ni bt u, bao nhiu n v d liu c chuyn, bn ang thc hin
vic vo hay ra d liu v nhiu iu khc. Bn s phi hi vi nhng ngi
thit k ra phn cng ca bn lc ra c cc chi tit ny hoc l bn s phi
lm vic vi bng hng dn bit c bn cn phi lm g vi cc mc
phn cng ny.
2. Mt thit b vi kh nng tp hp/tri ra c th chuyn cc khi ln d liu n
hoc i cc vng khng cu hnh ca b nh vt l. S dng scatter/gather l
mt li th ca phn mmbi v n gii hn yu cu v vi cc khi d liu ln
ca cc trang Frame cu hnh. Cc trang ny c th n gin l b kho khi m
chng c tm thy trong b nh vt l v thit b c th b m t bi chng.
3. Nu thit b ca bn khng c Bus ch, bn s s dng h thng iu khin
DMa trn bo mch ch ca my tnh. Kiu ca DMA i khi c gi l
DMA n l (Slave). H thng iu khin DMA lien kt vi cc bus ISA c mt
s gii hn v b nh no n c truy cp v rng ca mt b chuyn n
c th thc hin m khng c chng trnh nh trc. Trnh iu khin ny c
d nh l IESA thiu cc gii hn ny. t nht l trong Windows XP, bn s
khng cn phi bit kiu bus phn cng cu bn cm vo bi v h thng c th
ly ra cc hn ch ny mt cch t ng.
4. Thng thng, h thng DMA bao gm chng trnh s cc thanh ghi phn
cng hoc bn copy d liu trc hay sau ca h thng. nu thit bca bn cn
c hay ghi d liu lien tc, bn khng cn phi thc hin cc bc ny vi
mi yu cu vo.ra, n c th lm chm i qu trnh c chp nhn trong
trng hp c th rt nhiu. V vy bn c th ch nh ci no c bit nh l
vng m chung, ni m cc thit b v cc trnh iu khin ca bn c th
ng thi truy cp ti nhiu thi im.
Tuy nhin trong thc t nhiu chi tit ny s b ph thuc khc nhau vo cch m 4 tc
nhn ny nh hng ln nhau, cc bc m bn thc hin s c nhng c tnh chung.
Hnh 7.7 minh hoc qua t chc ca mt chuyn i. Bn bt u chuyn i t cng
vic StartIo bng cch yu cu quyn s hu ca chnh i tng iu hp.Quyn s
hu ny ch c gi tr khi bn chia s mt knh DMA h thng vi mt thit b khc,
nhng m m hnh DMA ca Windows XP yu cu bn cn phi thc hin cc bc
ny. Khi trnh qun l vo/ra c th cung cp cho bn quyn ny, n s ch nh cho bn
mt s s cc thanh ghi cho qu trnh s dng tm thi cu bnv gi li hnh ng
iu khin b iu hp bn cung cp. TRong hnh ng iu khin b iu hp ca bn,
bn thc hin mt s chuyn i tng bc sp xp phm vi chuyn i u tin
(cng c th l ch c mt). Mt s phm vi c th cn thit nu kh nng s cc
thanh ghi l khng th. Thit b ca bn phi c th cn tr v iu khin nhng iu c
th xy ra gia cc phm vi.
261/369
Figure 7-7. Flow of ownership during DMA.
i khi theo cch ny, bn s gii phng s cc thanh ghi v i tng iu hp.
S tnh ton thi gian ca hai s kin ny l mt trong s cc chi tit khc ci m phc
thuc vo cc tc nhn ti nu ra u ca phn ny.
262/369
vo ra s khng bt buc yu cu xp hang ca i tng thit b trn cc vng m
d liu ch ngi dng (n khng bt buc cc yu cu cho nhn ch li gi
trong ). Nu Hal hoc thit b ca bn yu cu cc vng m DMA bt u trong
mt ranh gii c th, v th bn c th copy t dui ln mt phn nh ca d liu ngi
dng ti hang chnh xc bn trong vng m c c mt hang i yu cu- hoc l
iu hoc nguyn nhn lm sai v yu cu iu c mt vng m khng sp
hng.
DEVICE_DESCRIPTION dd;
RtlZeroMemory(&dd, sizeof(dd));
dd.Version = DEVICE_DESCRIPTION_VERSION;
dd.Master = TRUE;
dd.InterfaceType = InterfaceTypeUndefined;
dd.MaximumLength = MAXTRANSFER;
dd.Dma32BitAddresses = TRUE;
&pdx->nMapRegisters);
263/369
typedef struct _DEVICE_EXTENSION {
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
pdx->numxfer = 0;
264/369
pdx->vaddr = MmGetMdlVirtualAddress(mdl);
pdx->nbytes);
nregs = pdx->nMapRegisters;
pdx->nMapRegistersAllocated = nregs;
if (!NT_SUCCESS(status))
StartNextPacket(&pdx->dqReadWrite, fdo);
265/369
3. y chng ta tnh ton s lng cc s cc thanh ghi chng ta yu cu h
thng lu tr cho chng ta trong sut qu trnh chuyn i ny. Chng ta bt
u bng vic tnh ton s lng c yu cu cho ton b s chuyn i ny.
Macro ADDRESS_AND_SIZE_TO_SPAN_PAGES c th a vo mt bn
k khai vng m c th ko di qua ranh gii ca mt trang. Tuy nhin con s
m chng ta i ngc t di ln vi kh nng c th vt qua s ln nht m
chng ta c cho phpbi li gi thong thng ti hm IoGetDmAAdapter.
TRong trng hp ny chng ta cn thc hin mt chuyn i trong nhiu
phm vi. Do vy chng ta o ngc tl ca trang u tin ch s dng con
s chp nhn c ca s cc thanh ghi. Chng ta cng cn phi nh c bao
nhiu s cc thanh ghi m chng ta ang cho php chng ta c th hu
chnh xc con s ny v sau.
4. TRong li gi ti hm AllocateAdapterChannel, chng ta ch ra a ch ca i
tng Adapter, a ch ca i tng thit b ca chng ta, s lng c
tnh ton ca s cc thanh ghi, v a ch ca th tc iu khin iu h ca
chng ta. Tham s cui cng pdx l tham s ng cnh cho th tc iu khin
iu hp ca chng ta.
266/369
PMDL mdl = Irp->MdlAddress;
pdx->regbase = regbase;
PHYSICAL_ADDRESS address =
(*pdx->AdapterObject->DmaOperations->MapTransfer)
!isread);
return DeallocateObjectKeepRegisters;
267/369
2. C mt s iu khc bit gia on code iu khin hot ng vo v ra s
dng DMA, v th n rt thun tin cho vic iu khin c hai hot ng ny
trong th tc con n. Dng code ny kim tra code cho hm chnh cho Irp
quyt nh khi no th hnh ng c hoc ghe xy ra.
3. Tham s regbase ti hm ny l mt iu khin khng r rngtrong vic ch
nh tp hp ca cc thanh ghi s c lu tr trong sut qu trnh s dng ca
bn. Sau ny bn s cn ti gi tr ny, v th bn cn lu tr n trong thit b
m rng ca mnh.
4. KeFlushIoBuffers chc chn rng ni dung ca ton b cc xl trong cc b
nh Cache cho vng m b nh bn ang s dng c lm sch b nh.
Tham s th 3 (TRUE)ch ra rng bn lm sch b nh Cache chun b cho
hot ng ca DMA. Kiu kin trc ca CPU c th yu cu bc ny, bi v
thong thng th hot ng ca DMA hng trc tip n hoc i t b nh m
khng nht thit phi ko theo cc b nh Cache.
5. Th tc Map Transfer thc hin phn cng ca DMA cho mt phm vi ca
chuyn i v tr v a ch vt l khi m vic chuyn i bt u. Ch rng
bn cung cp a ch ca mt MDL nh l tham s th hai ca hm ny. Bi v
bn cn mt MDL ti im ny, nn thong thng th bn cn phi la chn
phng thc DO_DIRECT_IOkhi ln u tin bn to i tng thit b ca
mnh, v trnh qun l vo ra v th s t ng to mt MDL cho bn. Bn cng
cn thong qua cng vi s thanh ghi a ch c s (regbase). Bn ch ra phn
no ca MDL b dnh lu n phm vi ca hot ng ny bng cch cung cp
mt a ch o (pxdvaddr) v mt bute m (pxdxfer). S chuyn i s
s dng tham s a ch o tnh ton i ch offset ca vng m. T n
c th xc nh cc trang vt l ang cha ng d liu ca bn.
6. l mt im m ti bn lp trnh phn cng ca mnh trong thit b theo
mt cch c bit l c yu cu. V d nh l bn c th s dng mt trong
s cc th tc ca WRITE_Xxx Hal gi a ch vt l v cc gi tr ca byte
m n cc thanh ghi trong card ca bn, v t v sau th bn c th iu
khin thanh ghi nhp nhy bt u chuyn i d liu.
7. Chng ta tr ra mt hng s DeAllocateKeepObjectRegister ch ra rng
chng ta khng s dng i tng iu hp nhng chng ta vn s dng s
cc thanh ghi. Trong m\v d c th (bus ch PCI), y khng bao gi c
s ganh ua vi i tng iu hp ti v tr u tin v kh khn ca n l vn
chng ta gii phng i tng iu hp . Trong mt s trng hp bus
ang lm ch khc (bus-mastering) chng ta c th chia s iu khin DMA
vi cc thit b khc. Vic gii phng i tng iu hp ny cho php cc
thit b khc bt u c thc hin chuyn i bng vic s dng cc phn tp
hp ri nhau ca s thanh ghi t mt khi lin m chng ta vn ang s
dng.
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:
->MajorFunction == IRP_MJ_READ;
(*pdx->AdapterObject->DmaOperations->FlushAdapterBuffers)
pdx->xfer, !isread);
pdx->nbytes -= pdx->xfer;
pdx->numxfer += pdx->xfer;
269/369
pdx->vaddr = (PVOID) ((PUCHAR) pdx->vaddr + pdx->xfer);
pdx->xfer = pdx->nbytes;
pdx->nbytes);
nregs = pdx->nMapRegistersAllocated;
PHYSICAL_ADDRESS address =
(*pdx->AdapterObject->DmaOperations->MapTransfer)
pdx->xfer, !isread);
else
(*pdx->AdapterObject->DmaOperations->FreeMapRegisters)
270/369
(pdx->AdapterObject, pdx->regbase,
pdx->nMapRegistersAllocated);
StartNextPacket(&pdx->dqReadWrite, fdo);
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.
271/369
hp; StartIo lu tr con s ny trong trng nMapRegistersAllocate ca thit b m
rng.
PHYSICAL_ADDRESS Address;
ULONG Length;
ULONG_PTR Reserved;
} SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT;
ULONG NumberOfElements;
ULONG_PTR Reserved;
SCATTER_GATHER_ELEMENT Elements[];
} SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST;
pdx->sglist = (PSCATTER_GATHER_LIST)
272/369
ExAllocatePool(NonPagedPool, sizeof(SCATTER_GATHER_LIST) +
MAXSG * sizeof(SCATTER_GATHER_ELEMENT));
->MajorFunction == IRP_MJ_READ;
pdx->regbase = regbase;
pdx->xfer = 0;
ULONG isg = 0;
273/369
ULONG elen = xfer;
sglist->Elements[isg].Address =
(*pdx->AdapterObject->DmaOperations->MapTransfer)
&elen, !isread);
sglist->Elements[isg].Length = elen;
xfer -= elen;
pdx->xfer += elen;
++isg;
sglist->NumberOfElements = isg;
return DeallocateObjectKeepRegisters;
274/369
d liu, nhng s lng cho php ca cc phn t ca Scatter/Gather c th
vt qu gii hn mt vi (trong s )chng ta c th chuyn i trong sut
phm vi ny. Trong sut vng lp di y, xfer s l s lng cc byte ci m
chng ta cha lp s , v chng ta s phi tnh ton li pdxxfer nh chng
ta i ( tin hnh thc hin)
3. y l vng lp m ti ha vi cc bn, ni m chng ta c th gi Map
transfer t cc phn t ca Scatter/Gather. Chng ta s tip tc vng lp
cho ti tn khi chng ta s ho ton b phm vi ca chuyn i ny hoc l
cho n tn khi chng ta ra khi cc phn t ca Scatter/Gather, bt c iu no
xy ra u tin.
4. Khi chng ta gi ti s chuyn i (map transfer) cho mt thit b Scatter/
Gather, n s sa i chiu di tham s ch ra c bao nhiu MDL bt u ti
a ch o c cung cp (vaddr) l lin tip nhau theo quy lut t nhin va
c th v th m c s ho bng mt phn t danh sch Scatter/Gather
n. N cng tr ra a ch vt l ca im bt u ca vng k tip.
5. y chnh l ni m chng ta cp nht cc bin ci m m t phm vi hin thi
ca chuyn i. Khi chng ta ri khi vng lp, xfer s b gim xung bng 0
(hoc l chng ta s chy ra ngoi cc phn t ca Scatter/Gather), pxdxfer
s tng n tng s ca tt c cc phn t chng ta c th s ho c.
Chng ta khng cp nht trng pdxxfer trong thit b mm rng- chng ta
ang lm vic trong th tc DPC. l mt trong nhng chi tit phin h khc.
6. y chnh l ni m chng ta tng ch s phn t ca Scatter/Gather phn
nh thc t l chng ta s dng n tng ln.
7. Ti v tr ny, chng ta c phn t Scatter/Gather isg ci m chng ta nn lp
trnh trong thit b ca mnh trong cc thit b ph thuc theo cch thch ng.
Sau chng ta nn khi ng hot ng ca thit b ny trong yu cu.
8. Tr v DeAllocateObjectKeepRegisters l hp l cho mt thit b bus ang lm
ch. V mt l thuyt bn c th c mt thit b khng lm ch vi kh nng
Scatter/Gather, v n s tr ra KeepObject thay v cc gi tr khc.
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
NTSTATUS status;
275/369
PMDL mdl = Irp->MdlAddress;
pdx->numxfer = 0;
pdx->nbytes = nbytes;
status =
(*pdx->AdapterObject->DmaOperations->GetScatterGatherList)
if (!NT_SUCCESS(status))
StartNextPacket(&pdx->dqReadWrite, fdo);
NTSTATUS StartDevice(...)
276/369
for (ULONG i = 0; i < nres; ++i, ++resource)
switch (resource->Type)
case CmResourceTypeDma:
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(...);
IO_ALLOCATION_ACTION AdapterControl(...)
return KeepObject;
VOID DpcForIsr(...)
278/369
{
(*pdx->AdapterObject->DmaOperations->FreeAdapterChannel)
(pdx->AdapterObject);
PVOID vaCommonBuffer;
PHYSICAL_ADDRESS paCommonBuffer;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
dd.Dma32BitAddresses = ??;
dd.Dma64BitAddresses = ??;
pdx->AdapterObject = IoGetDmaAdapter(...);
pdx->vaCommonBuffer =
(*pdx->AdapterObject->DmaOperations->AllocateCommonBuffer)
279/369
u tin cho gi IoGetDmAAdapter, bn thit lp cc c Dma32BitAddresses &
Dma64BitAddresses trong cu trc DEVICE_DESCRIPTION ni r v cc kh nng
a ch ca thit b ca bn. iu l: nu thit b ca bn c th nh a ch mt b
m s dng i ch vt l 32 bt, hy thit lp Dma32BitAddresses thnh true. Nu n
c th nh a ch b m s dng a ch 64 bt th hy thit lp Dma64BitAddresses
thnh True.
ULONG intcsr =
READ_PORT_ULONG((PULONG)(pdx->portbase + INTCSR);
if (isread)
280/369
mcsr = MCSR_WRITE_NEED4 MCSR_WRITE_ENABLE;
intcsr = INTCSR_WTCI_ENABLE;
WRITE_PORT_ULONG((PULONG)(pdx->portbase + MWAR),
address.LowPart);
else
intcsr = INTCSR_RTCI_ENABLE;
WRITE_PORT_ULONG((PULONG)(pdx->portbase + MRAR),
address.LowPart);
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.
PDEVICE_EXTENSION pdx)
ULONG intcsr =
return FALSE;
282/369
ULONG mcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + MCSR));
InterlockedOr(&pdx->intcsr, intcsr);
if (dpc)
return TRUE;
283/369
khng th sy ra thm ln no na. Mt ln na, trnh iu khin ca bn ci
m iu khin c v ghi ng thi c th khng ch c kh nng ngt ci m
xy ra.
mdl->MdlFlags = MDL_MAPPING_CAN_FAIL;
if (!oldfail)
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
Bi 17: IU KHIN VO/RA V HM
IU KHIN PLUG AND PLAY
Hm DeviceIoControl API (The DeviceIoControl API)
User-mode DeviceIoControl API c nguyn mu sau y:
if (Handle == INVALID_HANDLE_VALUE)
<error>
CloseHandle(Handle);
286/369
trnh iu khin.) Trnh iu khin s cp nht the Feedback variable (a DWORD)
ch bo bao nhiu nhng byte ca d liu ra n a cho bn mt sau. Hnh 9-1 minh
ha mi quan h ca nhng b m ny vi ng dng v trnh iu khin. Cu trc
Overlapped (OVERLAPPED) c dng gip kim sot mt tc v ng b, m
l ti ca mc tip theo. Nu bn c ch r FILE_FLAG_OVERLAPPED trong s
gi ti CreateFile, bn phi ch r OVERLAPPED con tr cu trc. Nu bn khng ch
r FILE_FLAG_OVERLAPPED, bn c l cung cp tt NULL cho i scui cng
ny bi v h thng s l i n.
287/369
Synchronous v Asynchronous gi ti DeviceIoControl
if (DeviceIoControl(Handle, IOCTL_GET_VERSION_BUFFERED,
LOWORD(version));
else
GetLastError());
FILE_FLAG_OVERLAPPED, NULL);
OVERLAPPED Overlapped;
DWORD code;
288/369
if (DeviceIoControl(Handle, ..., &Overlapped))
code = 0;
else
code = GetLastError();
<continue processing>
if (code == ERROR_IO_PENDING)
code = 0;
else
code = GetLastError();
CloseHandle(Overlapped.hEvent);
if (code != 0)
<error>
289/369
Kiu thit b (16 bt, i s u tin ti CTL_CODE) ch bo kiu ca thit b m thc
hin thao tc iu khin (php ton kim tra) ny.
290/369
iu khin IRP MJ DEVICE CONTROL
S nh v cha nhng tham s c lit k trong Bng 9-2. Nhng trnh iu khin
Lc t chng c l gii thch mt s mt m ring tr phi nh-nu chnh xc vit
m, ci -i qua tt c nhng ngi ci khc xung ngn xp. Tht ra, mt chc nng
lin lc m hiu x l IOCTL s c tr u nh th no trong chng trnh iu
khin-a s hp l trong trnh iu khin chc nng.
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
1->
PAGED_CODE();
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
291/369
ULONG info = 0;
2->
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;
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
3. y l ni bn sng to bi tp ca mnh bng vic chn nhng nhn trng hp (cho)
thao tc IOCTL khc nhau h tr bn..
293/369
Nhng thao tc bn trong iu khin IO (Internal IO
Control Operations)
H thng s dng IRP_MJ_DEVICE_CONTROL thc hin mt s gi
DeviceIoControl t kiu ngi s dng. Nhng trnh iu khin i khi cng cn ni
chuyn vi nhau, v h s dng IRP_MJ_INTERNAL_DEVICE_CONTROL lin quan
lm. Mt chui m tiu biu i theo Nh sau:
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
KEVENT event;
IO_STATUS_BLOCK iostatus;
if (NT_SUCCESS(status))
FALSE, NULL);
294/369
IoBuildDeviceIoControlRequest builds an IRP v khi to s nh v (v tr) chng u
tin m t m tc v v nhng b m bn ch r. N tr li con tr IRP cho bn
bn c th lm bt k s khi to b sung no m c l c yu cu. Trong Chng
12, chng hn, Ti s ch ra bn lm sao s dng mt yu cu kim sot ni b gi
mt khi yu cu USB (URB) ti trnh iu khin USB. Mt phn m qu trnh bao
gm t mt lnh vc tham s chng ti im ti URB. Bn gi l IoCallDriver gi
IRP cho thit b ch. Nu gi tr tr li i qua s th NT_SUCCESS, bn i trn i
tng s kin bn ch r nh i s(th) tm Ti IoBuildDeviceIoControlRequest. The
I/O Manager s t s kin khi kt thc IRP, v n s cng in vo cu trc iostatus
(ca) cc bn vi tnh trng cui v thng tin nhng gi tr. Cui cng n s gi l
IoFreeIrp gii phng IRP. Vy th, Bn khng mun truy nhp con tr IRP cht no
sau khi bn gi l IoCallDriver.
S khng phi l mt tng tt khi s dng cng s lin lc thng l (cho) iu khin
bn trong v ngoi, nhn tin, t nht khng phi khng c vic kim tra m chc nng
chnh (ca) IRP. y l mt v d ca ti sao khng: Gi thit trnh iu khin (ca)
cc bn c mt giao din iu khin ngoi m cho php mt ng dng hi giao din
kim sot ni b s lphaanjboj phn iu khin (ca) cc phin bn m cho php mt
ngi gi kiu nhn c th tin cn c xc nh mt b mt sng cn m bn khng
mun chia s vi ngi s dng- nhng
NTSTATUS DriverEntry(...)
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DispatchControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
DispatchControl;
NTSTATUS DispatchControl(...)
switch (code)
295/369
{
case IOCTL_GET_VERSION:
case IOCTL_INTERNAL_GET_SECRET:
DWORD junk;
NOTE Trnh iu khin mu EVWAIT minh ha phng php s kin dng chung ca
vic thng bo mt ng dng v mt s kin th v. Bn pht sinh s kin " th v "
bng vic nhn (nn) mt cha kha trn bn phm, do vic gy ra s th lp trnh
gi l mt IOCTL ca sau trong b phn iu khin. Trong cuc sng thc s, mt bin
c phn cng thc t s pht sinh s kin.
296/369
chuyn quyn ( Nh n thng lm ), n s khng c kh nng i vi s tham kho s
kin bng cch s dng iu khin .
PKEVENT pevent;
WaitForSingleObject(hEvent, INFINITE);
297/369
l ObDereferenceObject. i tng qun l vin khng c ph hy i tng s kin
cho n khi c hai th ny xut hin.
tng trung tm trong phng php thng bo IOCTL ang xem xt l khi ng dng
mun nhn c nhng thng bo s kin t trnh iu khin, n giDeviceIoControl:
);
Trnh iu khin cha quyt nh IOCTL ny v hon thnh n sau .Nu nhng xem
xt khc khng xm nhp m trong trnh iu khin c l n gin nh iu ny:
NTSTATUS DispatchControl(...)
switch (code)
case IOCTL_WAIT_NOTIFY:
IoMarkIrpPending(Irp);
pdx->NotifyIrp = Irp;
return STATUS_PENDING;
VOID OnInterestingEvent(...)
298/369
CompleteRequest(pdx->NotifyIrp,
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:
status = STATUS_INVALID_PARAMETER;
else
break;
299/369
}
Later , khi s kin no ng dng ang i cho xut hin, chng ti thc hin m nh
iu ny
<do something>
300/369
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):
KSPIN_LOCK IoctlListLock;
LIST_ENTRY PendingIoctlList;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
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);
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;
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) fdo->DeviceExtension;
KeAcquireSpinLockAtDpcLevel(&pdx->IoctlListLock);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
302/369
InterlockedCompareExchange((PVOID*) pIrp, Irp, NULL);
KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
KIRQL oldirql;
KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql);
if (Irp)
if (IoSetCancelRoutine(Irp, NULL))
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
else
Irp = NULL;
KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
return Irp;
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
7. Trong kha hc bnh thng (ca) nhng s kin, pht biu uncaches l mt IRP.
InterlockedExchange(&pdx->IoctlAbortStatus, status);
304/369
}
_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 18: THC HNH LP TRNH
DRIVER CHO IU KHIN VO/ RA
Thc hnh lp trnh driver cho iu khin Vora
Bi 1.
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
Bi 19: TRNH IU KHIN CHO USB
Gii thiu cng USB
USB - 10 nm ra i
2005 l nm th 10 k t khi phng thc kt ni USB chnh thc ra mt. Phng thc
truyn d liu ny gi tr thnh ph bin trong cng ngh thng tin, vin thng v
in t gia dng. Nhng t ai bit c qu trnh pht trin, nhng thi khc ng nh
cng nh nhng k nim kh qun v n.
307/369
Sn phm trang b USB u tin ra mt.
1996
Ra mt chun USB 1.0.
Intel gii thiu USB silic u tin. USB-
1995
IF c 340 thnh vin.
1994 Thnh lp nhm cng ty khai sinh USB.
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.
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.
Khng ch l kt ni
309/369
Apple iMAC G5 ch s dng kt ni USB v Wi-Fi.
nh USB 5 GB ca Seagate.
310/369
USB gi y c sc nh hng rt ln ti PC. T nm 2004, hu ht cc nh sn xut
PC u loi b a mm cho cc my tnh bn thay bng c a USB. T lc
, USB v ang tr thnh mt thit b lu tr in hnh l cng USB EZ bus mini
tc cao 20 GB ca Apricorn hay USB b ti 5 GB ca Seagate.
Kh nng c p dng rng ri nh ngy nay cng nh nhng ng dng ngoi lai
m USB hin ang kim nghim u ngoi s tin on ca Hip hi USB. V d, cng
USB cn c lm thit b ni ngun cho my hm nng cafe, hay dy ngun ca n
bn phm dnh cho my tnh xch tay c Kensington ch to thnh cng. Cc ng
dng hu ch khc ca USB bao gm cc adapter nh iu khin t xa, chuyn i USB
sang Bluetooth, chuyn i USB sang cc cng tun t (serial).
311/369
cng USB ca Apricorn.
Ngy nay, USB tr thnh giao din tin ch vi nhiu ng dng khc nhau, cho php lu
tr d liu d dng, gi nh s t camera, d dng kt ni vi my qut nh (scanner),
ti nhc ti my MP3, lu d liu vo th nh ng Steve Whalley, Gim c Tip th
USB 1.0 ca Intel kim chc Ch tch Hip hi USB sut thi gian duy tr cc sn phm
USB chun 1.1, nhc li cha kho thnh cng ca USB: USB c mt khi nim r
rng v c tp trung khai thc cc tnh nng kt ni tin dng thng thng, khi u
t cc kt ni ngoi vi ti PC ri dn dn mi c pht trin, m rng ng dng rng
ri v phong ph nh hin nay.
312/369
Ngy nay hu ht cc my tnh u c trang b mt hoc nhiu cng USB (Universal
Serial Bus). Cc cng USB (USB connector) gip ngi s dng gn mi thit b nh
chut, my in vi my tnh nhanh v d dng hn. Do cc h iu hnh u h tr USB
nn vic ci t cc thit b tht s nhanh v d dng.
So vi cch kt ni cc thit b vi my tnh dng cng song song (Parallel Port), dng
cng ni tip (Serial Port) hay dng cc Card c bit c thit k ci t sn bn trong
my tnh th USB nhanh hn nhiu.
Modem c ni vi my tnh qua cng ni tip ging nh mt vi dng thit
b khc nh Digital Camera, Palm Pilots trong khi mi my tnh thng ch c
hai cng ni tip v chng rt chm.
Cc thit b i hi cc kt ni nhanh hn nh cc Card c bit c cm trc
tip vo khe cm (Slot) trn bo mch. Thc t s lng cc khe cm (Slot) l c
hn v cn phi ci t cc phn mm cho thit b ny.
313/369
Mc ch ca USB l gii quyt cc vn ca ngi s dng khi cc cng kt ni trn
khng hiu qu. USB cung cp cho ngi s dng kh nng kt ni chun, d dng vi
127 thit b trn cng mt my tnh. Mi thit b ngoi vi hin nay u c th kt ni
trn cng mt phin bn USB chng hn nh: my in, my qut nh, chut, Joystick,
Digital Camera, Webcam, Modem, loa, in thoi, Network Connection, thit b lu
tr thng tin ( Zip)
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).
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
b nh my in, my qut s dng ngun in ring cung cp t b ngun (Power Supply)
ca chng trong khi cc thit b s dng rt t in nng nh chut, Digital Camera li
dng in nng (khong 500mA - 5V) t Bus.
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:
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.
316/369
Bi 20: THC HNH IU KHIN QUA
CNG USB
Thc hnh vi cc chng trnh v d iu khin qua cng
USB
Bi 1.
Hon thin lp trnh USB bi thc hnh trc (Plug and Play)
Bi 2.
317/369
Bi 21: TRNH IU KHIN CHO HID
Nhng b iu khin cho thit b HID (Drivers for HID
Devices )
Lp trnh iu khin cho cc thit b HID ca Microsoft, HIDCLASS.SYS, cung cp
khung tng th cho trnh iu khin WDM qun l cc thit b HID trn tt c cc
nn tng Windows. Microsoft cng cung cp mt trnh iu khin con HIDCLASS tn
HIDUSB.SYS x l cc thit b cm tay USB ca thit b hoc m t giao din ch
ra rng chng thuc v lp HID. Do , nu thit b cm tay USB ca bn thuc cc lp
HID, bn c th khng phi vit mt trnh iu khin c bit cho tt c bi v lp trnh
iu khin Microsoft v minidriver h tr y cc k thut ca USB.
318/369
khin con HIDCLASS thc t ch l cch lm thit b c th truy cp vo
DirectX v cc ng dng hin c.
319/369
Nhng m t bo co v nhng bo co (Reports and
Report Descriptors )
Mt thit b HID chuyn thng tin trong mt khi c bit n nh l mt bo co. Cc
bo co c cha bit v cc trng nh dng kiu s nguyn theo mt k hiu. Nhiu
c t HID v c im k thut lin quan n ti liu m t ni dung ca cc bo co
v bo co nhn din chi tit. Ti s phn tch hai mu bo co nhn din y gip
bn hiu cc k thut.
320/369
Th hai, xc nh mc s dng cho cc trang k tip gm c cc trang trong b su tp
nhn din cp cao . Trong c im k thut HID, mt nhm tp hp dch v d liu
lin quan n mc trn. V d, mt nhm tp hp vt l thu thp ti mt im hnh hc,
trong khi mt nhm tp hp ng dng cng c th lin h vi cc ng dng. Mt khi
nim thm na, nhng tp hp logic, cho php lin quan n mc c nhm vo bn
trong mt cu trc d liu hp li, chng hn nh mt byte d liu truy cp k tip.
Nhng khi nim tru tng nh vy l c gn v ngha, v Microsoft v ngha
gn thm, nh sau:
321/369
mt trng u vo trong mt bo co, trong khi mt mc OUTPUT tng ng vi mt
lnh vc sn xut trong mt bo co. Hin cng c th c dng xc nh c im
bi trong lnh vc bo co mt tnh nng, nhng bn phm mu khng bao gm bt k
ngi trong s h. Mt s bi ton cu vic chnh trong bi m t cc bn trnh by
v ngha ca cc d liu ring ca mnh.
322/369
(REPORT_COUNT) 3-bit (REPORT_SIZE) c gi tr. Nhng 3 bit pad ra, sn lng
t n mt bo co y byte. An u vo mc gm su (REPORT_COUNT)
8-bit, gi tr (REPORT_SIZE), khc nhau, t 0 thng qua 101 (LOGICAL_MINIMUM
v LOGICAL_MAXIMUM) v tng ng vi phm trn mt tiu chun 101-Kha
bn phm (USAGE_PAGE, USAGE_MINIMUM, v USAGE_MAXIMUM). Ni cch
khc, 2 byte thng qua 7 ca cc u vo cha cc m s bo co cho n su phm m
khng c s ng thi t chc xung.
HIDFAKE Descriptor
Cc n xin cp u ca cch s dng l "Gun thit b" t Gaming Kim sot trang.
iu ny c nhn to mt s la chn m ti lm trnh gp kh khn ci
t trnh iu khin mu. i vi bt k cch s dng c lit k trong bng 13-1,
HIDCLASS s cung cp mt thit b tng thch nh danh cng vi cc thit b c
th ca ID. Windows XP s thch, sau l mt k kt ph hp vi trnh iu khin
tng thch vi mt ID unsigned driver (nh HIDFAKE.SYS) ph hp vi cc thit b
c th ca ID. (Xem Chng 15 cho bit thm thng tin v cch chn trnh iu khin
Windows XP.) It's impossible gn chuyn i sang trnh iu khin c th.
323/369
Ti s dng trong vng ba l b su tp ca chnh b su tp. Cc b su tp logic
ch phc v nh du ba-bo co ca cc c cu descriptor. Cc mu s lm vic hon
ho cng khng c h.
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
Nhng iu khin nh HIDCLASS (HIDCLASS
Minidrivers)
Nh trc y tho lun, Microsoft cung cp mt trnh iu khin (HIDUSB.SYS)
cho bt k thit b USB c xy dng theo HID c im k thut. Phn ny m t
cch bn c th xy dng mt HIDCLASS minidriver cho mt s cc loi in thoi m
bn mun c masquerade nh HID.
326/369
Mt s thit b khng spontaneously to ra cc bo co. i vi cc loi thit b, thit
lp cc DevicesArePolled c TRUE. HIDCLASS sau s vn IRPs c bo
co trong mt thi gian loop. Minidriver ca bn c bo co d liu t in thoi ch
phn ng li mi IRP. cp cao hn cc thnh phn, chng hn nh mt ng dng bng
cch s dng giao din DirectX, c th ch nh cc polling chuyn. Ngh rng hai ln
trc khi ci t DevicesArePolled TRUE: hu ht cc thit b cn thit n c
FALSE. y l v d gn hon thnh ca DriverEntry chc nng trong mt HIDCLASS
minidriver:
PUNICODE_STRING RegistryPath)
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
DispatchInternalControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
HID_MINIDRIVER_REGISTRATION reg;
RtlZeroMemory(®, sizeof(reg));
reg.Revision = HID_REVISION;
reg.DriverObject = DriverObject;
reg.RegistryPath = RegistryPath;
reg.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
return HidRegisterMinidriver(®);
327/369
Driver gi li thi quen
PDEVICE_OBJECT PhysicalDeviceObject;
PDEVICE_OBJECT NextDeviceObject;
PVOID MiniDeviceExtension;
} HID_DEVICE_EXTENSION, *PHID_DEVICE_EXTENSION;
tm thy thit b m rng ca cc bn, bn phi i theo sau dy chuyn con tr ny:
(fdo->DeviceExtension))->MiniDeviceExtension;
328/369
Bn s dng cng trnh tng t c c nhng PDO a ch v c c nhng
g ti gi cho LowerDeviceObject trong cun sch ny. (HIDCLASS cuc gi l mt
NextDeviceObject.) L mt li typist, ti thng xc nh macros lm cho cuc
sng ca ti d dng hn trong khi ti ang vit minidriver:
((fdo)->DeviceExtension))->MiniDeviceExtension)
->PhysicalDeviceObject)
->NextDeviceObject)
329/369
IRP_MN_START_DEVICE handler nhu cu ca bn kim tra li bng cch t
c ca bn AddDevice gi (ti gi l n AddDeviceStatus trong sm hn fragment) v
tht bi trong IRP nu c cho bit mt li. y l cch bn i ph vi thc t l
nhng HIDCLASS khng mng bit cc m t AddDevice tr li trong phin bn ca
Windows trc khi Windows XP.
PCM_PARTIAL_RESOURCE_LIST raw,
PCM_PARTIAL_RESOURCE_LIST translated)
if (!NT_SUCCESS(pdx->AddDeviceStatus))
330/369
return pdx->AddDeviceStatus;
return STATUS_SUCCESS;
DispatchPower goi
Ch thch:
331/369
Nu bn minidriver s dng GENERIC.SYS, cn nhc vic s dng cc
GenericCacheControlRequest v GenericUncacheControlRequest chc nng theo
di IRPs rng bn pend. Cc chc nng ny bao gm cc chng tc-an ton hy b logic.
y l mt v d ca callback DispatchPower trong mt HIDCLASS minidriver:
IoCopyCurrentIrpStackLocationToNext(Irp);
if (stack->MinorFunction == IRP_MN_SET_POWER
DEVICE_POWER_STATE newstate =
stack->Parameters.Power.State.DeviceState;
if (newstate == PowerDeviceD0)
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)
pdx->devpower = newstate;
332/369
}
PDEVICE_EXTENSION pdx)
pdx->devpower = PowerDeviceD0;
return STATUS_SUCCESS;
333/369
driver ca i tng MajorFunction bng. HIDCLASS cuc gi ca bn nh l mt thi
quen gi subroutine c bo co v cc thng tin khc hoc cung cp hng dn
minidriver ca bn. Bn c th gi chng trnh ny nh th n l mt thi quen bnh
thng IRP dispatch x l s kim sot m s lit k trong bng 13-3.
M t kim sot ni b M s
IOCTL_HID_WRITE_REPORT v mt bo co
IOCTL_HID_GET_DEVICE_ATTRIBUTES HIDCLASS gi mt yu cu
IOCTL_HID_GET_DEVICE_ATTRIBUTES l mt phn ca cc ch bin ca
IRP_MN_START_DEVICE yu cu v conceivably, vo nhng thi gian khc, c
c thng tin rng mt thit b USB cc bn ghi trong mt lot cc thit b descriptor.
UserBuffer cc lnh vc ca IRP im n mt d sau y ca cc c cu, m bn nn
hon tt:
334/369
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
USHORT Reserved[11];
} HID_DEVICE_ATTRIBUTES, * PHID_DEVICE_ATTRIBUTES;
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
status = STATUS_BUFFER_TOO_SMALL;
break;
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;
HANDLE CtestDlg::FindFakeDevice()
GUID hidguid;
HidD_GetHidGuid(&hidguid);
CDeviceList devlist(hidguid);
336/369
HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
continue;
CloseHandle(h);
if (!okay)
continue;
if (attr.VendorID != HIDFAKE_VID
attr.ProductID != HIDFAKE_PID)
continue;
return CreateFile(devlist.m_list[i].m_linkname,
OPEN_EXISTING, 0, NULL);
return INVALID_HANDLE_VALUE;
337/369
trnh iu khin thit b, HIDCLASS tr gn quan tm n quyn truy cp v
chia s vi IRP_MJ_CREATE thuc tnh c xc nh, v chng ti ang li
dng cc tnh linh hot m rng hnh vi to ra bng cch m ra mt mt thit b
x l c th khng thc s c th truy cp c vi mt bnh thng m .
4. HidD_GetAttributes tr v mt thuc tnh c cu thu c t cc
HID_DEVICE_ATTRIBUTES in vo bi cc minidriver.
5. y l tuyn b quan trng trong v d ny. Nu in thoi v ID sn phm ph
hp vi nhng g chng ti ang tm kim, chng ti s b thuc l qut cc
thit b v m mt thc t x l mt ny.
6. iu ny s m ra cuc gi n CreateFile c quyn, nonoverlapped x l cho
c v vit. y l quyn hnh ng cho cc th nghim ca HIDFAKE dng
thc hin. Bn c th chia s cho cc yu cu khc nhau, quyn truy cp,
chng cho v I / O. Lu rng cc cuc gi n CreateFile c th b tht bi,
thm ch nu trc mt thnh cng, nu c mt ng dng khc, m snuck
trong mt x l.
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdHID;
UCHAR bCountry;
UCHAR bNumDescriptors;
struct _HID_DESCRIPTOR_DESC_LIST {
UCHAR bReportType;
USHORT wReportLength;
338/369
} DescriptorList [1];
} HID_DESCRIPTOR, * PHID_DESCRIPTOR;
case IOCTL_HID_GET_DEVICE_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;
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.
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
status = STATUS_BUFFER_TOO_SMALL;
break;
RtlCopyMemory(buffer, ReportDescriptor,
sizeof(ReportDescriptor));
340/369
info = sizeof(ReportDescriptor);
break;
char ReportDescriptor[64] = {
341/369
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
342/369
IOCTL_HID_READ_REPORT Workhorse c IOCTL_HID_READ_REPORT cc hot
ng ca mt HIDCLASS mini driver. HIDCLASS vn v yu cu ny
c c mt nguyn HID bo co. HIDCLASS s dng nguyn liu bo co
IRP_MJ_READ v IOCTL_HID_GET_INPUT_REPORT p ng yu cu pht hnh
cho n t cp cao hn cc thnh phn, bao gm c ngi s dng ch ng dng
m gi ReadFile, HidD_GetInputReport, IDirectInputDevice8: GetDeviceData, hoc
IDirectInputDevice8:: Thm d kin.
343/369
case IOCTL_HID_READ_REPORT:
status = STATUS_BUFFER_TOO_SMALL;
break;
break;
344/369
xut d liu v Parameters.DeviceIoControl.OutputBufferLength rng cc lnh vc ca
IO_STACK_LOCATION cha chiu di ca n.
IOCTL_HID_GET_FEATURE v IOCTL_HID_SET_FEATURE
Nhng I / O kim sot (IOCTL) hot ng cng l mt cch Microsoft mun bn thc
hin cc out-of-band giao tip gia mt ng dng v mt HID minidriver. Ghi nh rng
HIDCLASS khng cho php bt c ai m mt ca hng x l cc thit b gc (x
l c th c m ra ch cp cao b su tp) v khng kim sot bt k hot ng
nonstandard rng n s xy ra nhn c. Resorting m khng sleazy phng
php, nh l mt iu m ti s khng ni bt c iu g, c tht s l khng c cch
no khc cho cc ng dng HIDCLASS minidriver v mt giao tip.
PUCHAR reportBuffer;
ULONG reportBufferLen;
UCHAR reportId;
} HID_XFER_PACKET, *PHID_XFER_PACKET;
345/369
HIDCLASS l mt ch tin cy ht nhn-gi, c bit l khng c l do xc minh
di ca tham s ny c cu.)
case IOCTL_HID_GET_FEATURE:
switch (p->reportId)
case FEATURE_CODE_XX:
status = STATUS_BUFFER_TOO_SMALL;
break;
RtlCopyMemory(p->reportBuffer, FeatureReportXx,
sizeof(FEATURE_REPORT_XX));
info = sizeof(FEATURE_REPORT_XX);
break;
346/369
break;
#undef p
case IOCTL_HID_SET_FEATURE:
switch (p->reportId)
case FEATURE_CODE_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:
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;
348/369
IOCTL_HID_GET_STRING, ly mt chui m t nhng nh sn xut, sn phm,
hoc ni tip ca mt s in thoi. Mt ngi s dng-p dng ch ny c th
kch hot IOCTL bng cch gi in thoi HidD_GetManufacturerString, HidD_Get
ProductString, hoc HidD_GetSerialNumberString. The strings tng ng vi ty chn
xc nh bi nhng dy in thoi descriptor tiu chun ca mt thit b USB. Mt tham
s n hot ng cho bit chui m bn nn tr li, v trong ngn ng. A skeleton
x l kim sot hot ng ny l nh sau:
case IOCTL_HID_GET_STRING:
#define p ((PUSHORT) \
stack->Parameters.DeviceIoControl.Type3InputBuffer)
#undef p
switch (istring)
case HID_STRING_ID_IMANUFACTURER:
break;
case HID_STRING_ID_IPRODUCT:
break;
case HID_STRING_ID_ISERIALNUMBER:
349/369
break;
if (!string)
status = STATUS_INVALID_PARAMETER;
break;
status = STATUS_INVALID_BUFFER_SIZE;
break;
info += sizeof(WCHAR);
break;
350/369
Mt s tin v cc im cht ny l cc m fragment:
IOCTL_HID_GET_INDEXED_STRING HIDCLASS gi mt
IOCTL_HID_GET_INDEXED_STRING, ly mt chui c USB-tiu chun nh
danh mc cc ngn ng v c ch nh. Mt ngi s dng-ch c th kch hot
chng trnh ny IOCTL bng cch gi in thoi HidD_GetIndexedString. Bn x l
yu cu ny nhiu nh IOCTL_HID_GET_STRING ngoi tr cho hai im:
kim sot hot ng ny s dng mt s pha trn k l ca hai phng php buffering:
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.
HID_SEND_IDLE_CALLBACK IdleCallback;
PVOID IdleContext;
} HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO,
*PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO;
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
IoCopyCurrentIrpStackLocationToNext(Irp);
stack = IoGetNextIrpStackLocation(Irp);
stack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
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;
353/369
Bi 22: THC HNH LP TRNH HID
Thc hnh vi cc chng trnh v d iu khin cho HID
Bi 1.
Bi 2.
354/369
Bi 23: THC HNH LP TRNH
DRIVER GIAO TIP CC CNG
Thc hnh mt s bi tp tng hp
Bi 1.
Bi 2.
Bi 3.
Lp trnh USB
Bi 4.
Cc x l IRP
Bi 5.
Cc gi tin I/O
Bi 6.
355/369
TI LIU THAM KHO
Lp trnh h thng: Ti liu tham kho
Sch tham kho :
[3] Walter Oney, "Programming The Windows Driver Model, 2nd Edition (2003)".
[7] Nguyn Minh San, Cm nang Lp trnh h thng (bn dch). NXB Tng cc Thng
k.2001.
[8] Ng Din Tp, Lp trnh Ghp ni my tnh trong Windows. NXB Khoa hc v k
thut. 2001.
356/369
MC LC
Lp trnh h thng: Mc lc
Bi 1: TNG QUAN V LP TRNH H THNG 1
1.3 Lch s 1
Bi 4: C BN V CU TRC V DRIVER 10
Bi 6: CC K THUT LP TRNH C BN 20
357/369
6.2 X l li 21
6.3 Qun l b nh 33
6.4 X l chui 44
Bi 10: Thc hnh vi cc chng trnh giao tip qua cng COM 60
Bi 11: Thc hnh vi cc chng trnh giao tip qua cng COM 64
Bi 12: VN NG B 64
12.2 Mc yu cu Ngt 66
358/369
Bi 14: GI D LIU VO RA 90
359/369
Bi 21: TRNH IU KHIN CHO HID 185
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/
361/369
Giy php: http://creativecommons.org/licenses/by/3.0/
362/369
Module: Mi trng lp trnh kiu Kernel Mode
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/e7a02045
Giy php: http://creativecommons.org/licenses/by/3.0/
363/369
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/9677d96a
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Thc hnh vi cc chng trnh giao tip qua cng LPT
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/085b2a8a
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Thc hnh vi cc chng trnh giao tip qua cng COM
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/3a6f15ba
Giy php: http://creativecommons.org/licenses/by/3.0/
364/369
URL: http://www.voer.edu.vn/m/e6bcd0d2
Giy php: http://creativecommons.org/licenses/by/3.0/
365/369
Giy php: http://creativecommons.org/licenses/by/3.0/
366/369
Module: iu khin IRP MJ DEVICE CONTROL
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/53878970
Giy php: http://creativecommons.org/licenses/by/3.0/
Module: Nhng b iu khin cho thit b HID (Drivers for HID Devices )
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/90dff5b9
Giy php: http://creativecommons.org/licenses/by/3.0/
367/369
Cc tc gi: Khoa CNTT HSP KT Hng Yn
URL: http://www.voer.edu.vn/m/8c4f582d
Giy php: http://creativecommons.org/licenses/by/3.0/
368/369
Chng trnh Th vin Hc liu M Vit Nam
Chng trnh Th vin Hc liu M Vit Nam (Vietnam Open Educational Resources
VOER) c h tr bi Qu Vit Nam. Mc tiu ca chng trnh l xy dng kho
Ti nguyn gio dc M min ph ca ngi Vit v cho ngi Vit, c ni dung phong
ph. Cc ni dung u tun th Giy php Creative Commons Attribution (CC-by) 4.0
do cc ni dung u c th c s dng, ti s dng v truy nhp min ph trc
ht trong trong mi trng ging dy, hc tp v nghin cu sau cho ton x hi.
Hanoi Spring l mt nn tng cng ngh tin tin c thit k cho php cng chng d
dng chia s ti liu ging dy, hc tp cng nh ch ng pht trin chng trnh ging
dy da trn khi nim v hc liu m (OCW) v ti nguyn gio dc m (OER) . Khi
nim chia s tri thc c tnh cch mng c khi xng v pht trin tin phong
bi i hc MIT v i hc Rice Hoa K trong vng mt thp k qua. K t , phong
tro Ti nguyn Gio dc M pht trin nhanh chng, c UNESCO h tr v c
chp nhn nh mt chng trnh chnh thc nhiu nc trn th gii.
369/369