Win2k_driver_ch_15

Download Report

Transcript Win2k_driver_ch_15

ISLab Flash Team
Ch 15. Layered Drivers
PartⅠ
Contents
•
•
•
•
•
인터미디엇 드라이버의 개관
계층 드라이버의 작성
I/O 완료 루틴의 작성
IRP의 추가 할당
PartⅠ. Summary
•
•
•
•
필터 드라이버의 작성
예제코드 : 필터 드라이버
커플 드라이버의 작성
Summary
ISLab Flash Team
Ch 15. Layered Drivers
2
Made By ICEUNI
ISLab Flash Team
1. Intermediate 드라이버의 개관
Intermediate 드라이버의 정의
• Intermediate 드라이버는 I/O 요청을 다른 드라이버에게
전달하는 커널 모드 드라이버이다.
• Intermediate 드라이버는 WDM 호환 드라이버를 구현할
때의 구조와 WDM 모델이 아닌 드라이버 구조로 구분된
다.
• Intermediate 드라이버의 대표적인 예로는 계층 드라이
버를 들 수 있다.
ISLab Flash Team
Ch 15. Layered Drivers
4
Made By ICEUNI
Intermediate 드라이버 구분
WDM 호환 계층 드라이버 구조
버스 드라이버
하드웨어 버스와의 인터페이스를 한 개의 슬롯을 기준으로 제
공하고, 한 개 또는 그 이상의 PDO를 생성
Function 드라이버
디바이스를 위한 읽기, 쓰기 그리고 여타 기능적인 로직을 제
공하는 드라이버. 한 개 또는 그 이상의 FDO를 생성/관리
필터 드라이버
하위 계층 드라이버로 전송되기 전에 I/O 요청을 중간에서 수
정하는 기능을 제공하는 드라이버 필터 드라이버는 펑션 드라
이버의 위 또는 아래에 위치할 수 있고 또는 버스 드라이버의
상단에 위치할 수 있다.
WDM 모델이 아닌 계층 드라이버 구조
필터 드라이버
드라이버는 다른 드라이버를 위한 요청을 중간에서 가로챌 수
있도록 작성될 수 있다. 이것은 이미 설치되어 구동중인 드라
이버를 수정하는 것과도 같은 효과를 볼 수 있다.
커플 드라이버
이 범주의 드라이버는 두 개의 드라이버 사이에서 개별적으로
인터페이스를 정의한 드라이버들을 가리킨다. 이 인터페이스
는 드라이버끼리의 통신을 위한 I/O 관리자의 호출 메커니즘
을 사용하지 않는다.
<계층 드라이버의 구분>
Ch 15. Layered Drivers
ISLab Flash Team
5
Made By ICEUNI
계층적 구조의 장점(1)
• 상위 레벨의 프로토콜을 특정 하드웨어의 관리를 담당하
는 하부의 코드와 구분 짓도록 할 수 있다.
• 하드웨어를 담당하는 코드를 다시 재작성하지 않고 보다
다양한 종류의 하드웨어를 지원할 수 있게 된다는 것을
뜻한다.
• 동일한 프로토콜 드라이버를 다른 하드웨어에 실시간으
로 플러그인시키는 것을 허락함으로써 보다 많은 유연성
을 제공하게 된다.
ISLab Flash Team
Ch 15. Layered Drivers
6
Made By ICEUNI
계층적 구조의 장점(2)
포트 드라이버 – 디바이스 컨트롤러를 위한 단일 디바이
스 드라이버
• 클래스 드라이버 – 디바이스 컨트롤러에 붙는 각의 개별
적인 상위 레벨(작고 가볍다)
• 드라이버를 드라이버 계층에 삽입시키는 것은 동일한 제
품을 위해 다수의 코드를 작성하지 않고 제품의 특성을
추가시키거나 제거하는 투명한 방법을 제공하는 것이다.
•
ISLab Flash Team
Ch 15. Layered Drivers
7
Made By ICEUNI
계층적 구조의 단점
• I/O 관리자를 통해 각각의 IRP가 매번 한 드라이버에서
다른 드라이버로 전달됨으로 인해 I/O 요청이 과도한 오
버헤드가 발생할 수 있다.
• 계층적 구조를 구현하기 위해 각 드라이버 구성 요소를
서로 잘 맞게 접목시키는 설계에 대한 많은 노력을 기울
여야 한다.
• 드라이버들을 관리한데 있어서는 부기(簿記,
bookkeeping)와도 같이 각 드라이버 인터페이스에 대한
문서화가 더욱 필요하다.
• 계층적 구조의 드라이버를 설치하는 것은 각 드라이버가
적절한 설치 과정을 거쳐야 한다는 점이 따르게 된다.
ISLab Flash Team
Ch 15. Layered Drivers
8
Made By ICEUNI
ISLab Flash Team
2. 계층 드라이버의 작성
계층 드라이버가 동작하는 방식
IRP
For
Hi0
HIDRIVER
HI0
I/O Completion
Dispatch
:
:
IoCallDriver
:
return
바로 IRP를 하위 드라이버로 내려 보냄
LODRIVER
LO0
Dispatch
Dispatch or
DpcForIsr
:
IoCompleteRequest
<계층 드라이버의 동작>
IRP를 처리중의 상태로 유지하고 추가적으로 IRP를 생성
하위 드라이버에게 이를 보낸다.
ISLab Flash Team
Ch 15. Layered Drivers
10
Made By ICEUNI
계층 드라이버의 초기화와 정리 루틴(1)
• DriverEntry
– 계층 드라이버에서 수행되는 초기화 과정은 일반 드라이버에서
수행되는 초기화 과정과 비슷하다.
– 차이점은 상단에서 내려온 I/O 요청을 직접 처리할 것인지 아니
면 하위 레벨의 드라이버로 보내어 처리할 것인지 결정하는데 있
다.
– IRP요청에 대해 적당한 처리를 수행할 수 있도록 초기화시키는
역할을 담당
ISLab Flash Team
Ch 15. Layered Drivers
11
Made By ICEUNI
계층 드라이버의 초기화와 정리 루틴(2)
• AddDevice 루틴
①
AddDevice 루틴
상위레벨 디바이스 객체 생성
① IoCreateDevice
② push
② IoAttatchDeviceToDeviceStack
②
②
타겟 디바이스
객체의 포인터
저장(익스텐션)
③ 상위 레벨 디바이스 객체 StackSize
> 타겟 디바이스 객체 StackSize
디바이스 스택
② 포인터
④ IRP 전달
④ IRP_MJ_CREATE
타겟 디바이스
⑤ IoCreateSymbolicLink
“\device\Hi
객체 관리자
⑤ 추가
W??
ISLab Flash Team
Ch 15. Layered Drivers
12
Made By ICEUNI
계층 드라이버의 초기화와 정리 루틴(3)
• RemoveDevice
• IRP_MN_REMOVE_DEVICE 요청이 계층 드라이버로 보
내어졌을 때 드라이버는 반드시 AddDevice 루틴에서 수
행했던 동작을 거꾸로 수행해야 한다.
객체 관리자
RemoveDevice 루틴
\device\Hi
① IoCreateSymbolicLink
② IRP_MJ_CLOSE
① 제거
② IRP 전달
타겟 디바이스
③ ioDetachDevice
레퍼런스 카운트-④ IoDeleteDevice
상위 레벨의 디바이스 객체 삭제
ISLab Flash Team
Ch 15. Layered Drivers
13
Made By ICEUNI
계층 드라이버를 위한 초기화(1)
• 투명형 계층 드라이버/가상(논리)형 계층 드라이버
두가지 방식 중 한가지로 동작
• 투명형 계층 드라이버
– 어떤 계층 드라이버들은 하위 계층의 드라이버와 그 드라이버의
클라이언트 사이에서 투명하게 동작하도록 만들어진다.
– DriverEntry
• 하위 드라이버에 의해 제공되는 MajorFunction코드의 세트를 모두
지원해야 하고, IRP 요청이 내려왔을 때 아무 동작을 수행하지 않고
이를 통과시키거나 아니면 하위 드라이버의 동작을 수정하도록 한
다.
– AddDevice
• 타겟 디바이스 객체의 DeviceType과 Characteristics 필드를 계층
드라이버 디바이스 객체로 복사해둔다.
• 타겟 디바이스의 Flags 필드로부터 DO_DIRECT_IO 또는
DO_BUFFERED_IO 비트를 복사한다.
ISLab Flash Team
Ch 15. Layered Drivers
14
Made By ICEUNI
계층 드라이버를 위한 초기화(2)
• 가상(논리)형 계층 드라이버
– 계층 드라이버의 또 다른 형태는 계층 드라이버가 가상 혹은 논
리 디바이스 객체를 익스포트시키는 드라이버이다.
– 가상 계층은 실제적인 하부의 물리적인 구현에 대한 어떠한 유사
점을 담당하는 디바이스 추상화를 종합하도록 하는 것이 가능하
다.
– 자신의 디바이스 객체의 Type과 Characteristic필드에 적당한 값
을 선택해야만 한다. 또한, 계층 드라이버에 의해 제공되는
MajorFunction 디스패치 함수의 전체 세트를 논리 디바이스 객
체에 적당하게 설정해야 한다.
ISLab Flash Team
Ch 15. Layered Drivers
15
Made By ICEUNI
계층 드라이버에서 I/O 요청 처리(1)
• IRP 완료시키기
– IoGetCurrentIrpStackLocation 함수를 호출하여 드라이버의 I/O
스택 슬롯의 포인터를 획득한다.
– 디스패치 루틴은 IRP 안의 다양한 필드와 I/O 스택 로케이션을 사
용하여 요청을 처리한다.
– IRP의 IoStatus.Information 필드에 적당한 값을 채워둔다.
– 디스패치 루틴은 또한 IRP의 IoStatus.Status 필드를 적당한
STATUS_XXX 코드로 채운다.
– IO_NO_INCREMENT를 priority-boost 인자로 하여
IoCompleteRequest를 호출하고, I/O관리자에게 IRP를 돌려보낸
다.
– 디스패치 루틴의 리턴 값으로는 IRP에 채워둔 동일한
STATUS_XXX 값으로 전달한다.
ISLab Flash Team
Ch 15. Layered Drivers
16
Made By ICEUNI
계층 드라이버에서 I/O 요청 처리(2)
• IRP를 다른 드라이버로 전달하기
– IoGetCurrentIrpStackLocation을 호출하여 자신의 I/O 스택 로케
이션의 포인터를 획득한다.
– 디스패치 루틴에서 IoGetNextIrpStackLocation을 호출하여 다음
하위 드라이버의 스택 로케이션의 포인터를 얻어낸다.
– 다음 하위 드라이버의 I/O 스택 로케이션의 MajorFunction 필드
와 Parameters 필드의 각종 멤버를 설정한다.
– 디스패치 루틴에서 IoSetCompletionRoutine 함수를 호출하여
IRP와 연관된 I/O 완료 루틴을 설정한다. (IRP를 처리 중 상태로
지정)
– IoCallDriver를 호출하여 IRP를 다음 하위 드라이버로 보낸다.
(비동기 호출)
– STATUS_SUCCESS, STATUS_PENDING 또는 STATUS_XXX
리턴
ISLab Flash Team
Ch 15. Layered Drivers
17
Made By ICEUNI
계층 드라이버에서 I/O 요청 처리(3)
• IRP를 새로 할당하기
– 계층 드라이버의 디스패치 루틴은 하위 드라이버로 보내게 될 하
나 또는 그 이상의 추가 IRP를 할당하는 것이 필요할 지도 모른
다.
– 새로 생성한 IRP가 완료될 때까지 기다리거나 또는 비동기 호출
과 같은 방식 중 하나를 선택할 수 있다.
– 비동기 호출의 경우에는 새로 할당한 IRP를 정리하는 코드가 I/O
완료 루틴 내에서 일어나게 된다.
ISLab Flash Team
Ch 15. Layered Drivers
18
Made By ICEUNI
ISLab Flash Team
3. I/O 완료 루틴의 작성
I/O 완료 콜백을 요청하기
• IoSetCompletionRoutine 함수
• I/O 완료 루틴의 주소를 하위 레벨 드라이버의 I/O 스택
로케이션 안에 넣는 역할을 한다.
VOID IoSetCompletionRoutine
IRQL <= DISPATCH_LEVEL
인자
설명
IN PIRP pIrp
드라이버에서 추적하려는 IRP의 주소
IN PIO_COMPLETION_ROUTINE
CompletionRoutine
하위 드라이버가 IRP를 완료했을 때 호출
되는 루틴
IN PVOID pContex
I/O 완료 루틴으로 전달되는 인자
IN BOOLEAN bInvokeOnSuccess
IRP가 성공적으로 수행되었을 때 호출
IN BOOLEAN bInvokeOnError
IRP 처리에 에러가 발생했을 때 호출
IN BOOLEAN bInvokeOnCancel
IRP가 취소되었을 때 호출
리턴
void
<IoSetCompletionRoutine 함수 원형>
ISLab Flash Team
Ch 15. Layered Drivers
20
Made By ICEUNI
실행 컨텍스트
• I/O 완료 루틴이 호출되는 시점에 I/O 관리자는 I/O 스택
포인터를 스택에서 꺼낸다.
NTSTATUS IoCompletion
IRQL == PASSIVE_LEVEL
IRQL == DISPATCH_LEVEL
인자
설명
IN PDEVICE_OBJECT pDevObj
방금 완료된 요청의 디바이스 객체
IN PIRP pIrp
완료된 IRP
IN PVOID pContext
IoSetCompletionRoutine으로부터 전달된 컨
텍스트
리턴
STATUS_MORE_PROCESSING_REQUIRED
STATUS_SUCCESS
<I/O 완료 루틴의 함수 원형>
ISLab Flash Team
Ch 15. Layered Drivers
21
Made By ICEUNI
I/O 완료 루틴의 수행 동작(1)
• 원본 IRP를 해제하기
– 만약 완료된 IRP가 외부 드라이버의 IoCompletionRequest 호출
에 의한 것이라면 몇가지 드라이버 전용의 해제 과정을 필요로
할 것이다.
• IRP의 PendingReturned 플래그 값을 체크한다.
• 만약 이 플래그가 TRUE이면, I/O 완료 루틴은 IoMarkIrpPending을
호출하여 현재 I/O 스택 로케이션을 처리 중 상태로 설정한다.
• STATUS_SUCCESS 값으로 리턴하여 완료 처리가 계속 되도록 한
다.
ISLab Flash Team
Ch 15. Layered Drivers
22
Made By ICEUNI
I/O 완료 루틴의 수행 동작(2)
• IRP의 해제
– 만약 IRP가 이 드라이버에 의해 할당되었다면, I/O 완료 루틴에
서 IRP를 해제해야 할 책임이 있다.
– IRP가 할당된 방식에 근거하여, 적절한 IRP의 해제 기법이 뒤따
라야만 한다.
ISLab Flash Team
Ch 15. Layered Drivers
23
Made By ICEUNI
I/O 완료 루틴의 수행 동작(3)
• IRP의 재사용
– 일반적으로 데이터를 분할하는 가장 효율적인 방법은 동일한
IRP를 재사용하여 하위 드라이버로 각 데이터를 전송하는 것이
다.
• IRP가 마지막 데이터 전송인지, 아닌지를 판단하기 위해 IRP 안에
저장된 컨텍스트 정보를 체크한다.
• STATUS_MORE_PROCESSING_REQUIRED를 리턴하여 상위 드라이
버에서 더 이상 완료 처리가 일어나지 않도록 한다.
• IoSetCompletionRoutine을 호출하여 해당 IRP에 I/O 완료 루틴의
주소를 설정한다.
• IoCallDriver를 사용하여 IRP에 타겟 디바이스 객체를 전달한다.
• 마지막으로 STATUS_MORE_PROCESSING_REQUIRED를 리턴하여
이 IRP에 대한 더 이상의 완료 처리가 수행되지 않도록 한다.
ISLab Flash Team
Ch 15. Layered Drivers
24
Made By ICEUNI
ISLab Flash Team
4. IRP의 추가 할당
IRP의 I/O 스택 재방문(Revisited)
IRP 스택 포인터로 작업하기
함수
IRP 스택 포인터의 영향
IoGetCurrentIrpStackLocation
변화 없음
IoGetNextIrpStackLocation
변화 없음
IoSetNextIrpStackLocation
스택 포인터를 한 위치 push한다
IoCallDriver
스택 포인터를 한 위치 push한다
IoCompleteRequest
스택 포인터를 한 위치 pop한다
<I/O 스택 포인터에 영향을 주는 함수들>
ISLab Flash Team
Ch 15. Layered Drivers
26
Made By ICEUNI
IRP의 스택 크기 조정하기
• I/O관리자는 드라이버에서 다음의 함수들이 호출될 때
IRP를 생성한다.
– IoBuildAsychronousFsdRequest
– IoBuildDeviceIoControlRequest
– IoBuildSychronousFsdRequest
• 이 함수들을 사용하여 생성된 IRP는 IRP가 보내질 타겟 디바이스 객
체의 StackSize 필드에 기록된 스택 슬롯의 개수를 포함하고 있다.
// IRP를 할당할 때에는 StackSize+1로 할당
// IRP의 StackLocation에 설정
// 다음 드라이버의 I/O 스택 슬롯을 설정한다.
pNextDriverSlot->MajorFunction = IRP_MJ_XXX;
...
// I/O 완료 루틴 호출
// IRP를 다른 드라이버에게 전달
ISLab Flash Team
Ch 15. Layered Drivers
27
Made By ICEUNI
IoBuildSynchronousFsdRequest로 IRP 생성
• Read, write, flush, shutdown IRP를 동기적으로 만드는데 사용한다.
PIRP IoBuildSynchronousFsdRequest
IRQL == PASSIVE_LEVEL
인자
설명
IN ULONG MajorFunction
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IN PDEVICE_OBJECT pTargetDevice
IRP를 보낼 디바이스 객체
IN OUT PVOID pBuffer
I/O 버퍼의 주소
INULONG Length
버퍼의 바이트 크기
IN PLARGE_INTEGER startingOffset
I/O가 시작되는 디바이스의 바이트 오프셋
IN PKEVENT pEvent
I/O완료의 시그널로 사용되는 이벤트 객체
OUT PIO_STATUS_BLOCK losb
I/O 수행 동작의 마지막 결과를 받는다.
리턴
Non-NULL : 새로 생성된 IRP의 주소
NULL : IRP가 생성되지 않음
<IoBuildSynchronousFsdRequest 함수 원형>
ISLab Flash Team
Ch 15. Layered Drivers
28
Made By ICEUNI
IoBuildAsynchronousFsdRequest로 IRP 생성
• Read, write, flush, shutdown IRP를 비동기적으로 만드는데 사용
PIRP IoBuildAsynchronousFsdRequest
IRQL <= DISPATCH_LEVEL
인자
설명
IN ULONG MajorFunction
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IN PDEVICE_OBJECT pTargetDevice
IRP를 보낼 디바이스 객체
IN OUT PVOID pBuffer
I/O 버퍼의 주소
INULONG Length
버퍼의 바이트 크기
IN PLARGE_INTEGER startingOffset
I/O가 시작되는 디바이스의 바이트 오프셋
OUT PIO_STATUS_BLOCK losb
I/O 수행 동작의 마지막 결과를 받는다.
리턴
Non-NULL : 새로 생성된 IRP의 주소
NULL : IRP가 생성되지 않음
<IoBuildSynchronousFsdRequest 함수 원형>
ISLab Flash Team
Ch 15. Layered Drivers
29
Made By ICEUNI
IoBuildDeviceIoControlRequest로 IRP 생성
• IOCTL IRP를 만드는 작업을 제공한다.
• Custom IOCTL을 통해 어떤 특정 동작을 드라이버에서 익스포트시
킨 인터페이스를 사용하는 일반적인 방법
PIRP IoBuildDeviceControlRequest
IRQL == PASSIVE_LEVEL
인자
설명
IN ULONG Io ControlCode
타겟 디바이스에 의해 인식되는 IOCTL 코드
IN PDEVICE_OBJECT pTargetDevice
IRP를 보낼 디바이스 객체
IN PVOID inputBuffer
하위 드라이버로 전달되는 버퍼
IN ULONG inputLength
입력 버퍼의 바이트 길이
OUT PVOID outputBuffer
하위 드라이버에 의해 리턴된 버퍼
IN ULONG outputLength
출력 버퍼의 바이트 길이
IN BOOLEAN InternalDeviceIoControl
TRUE – Internal 요청, FALSE – External 요청
IN PKEVENT pEvent
I/O 완료에 시그널로 사용되는 이벤트 객체
OUT PIO_STATUS_BLOCK losb
I/O 수행동작의 마지막 결과를 받는다.
리턴
Non-NULL : 새로 생성된 IRP의 주소
NULL : IRP가 생성되지 않음
< IoBuildDeviceControlRequest 함수 원형>
ISLab Flash Team
Ch 15. Layered Drivers
30
Made By ICEUNI
다른 방법으로 IRP 할당하기(1)
•
IoAllocateIrp를 사용하여 IRP 할당하기
1. 하부의 드라이버의 요구 사항을 만족시킬 만큼의 충분한 크기의 스택
로케이션을 가진 IRP를 할당한다.
2. DMA를 위한 메모리 디스크립터 리스트를 할당한다.
3. 새로운 IRP에 읽기 요청을 설정한다.
4. 읽기 요청을 위한 매개변수들을 채운다.
5. 하위 드라이버에게 어느 쓰레드가 원본 요청을 만들었는지 알 수 있게
보장한다.(에러가 발생했을 경우 반드시 보고되어야 하기 때문이다.)
6. 마지막으로 새로 생성한 IRP를 아래로 내려보낸다.
NTSTATUS IoCompletion(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp,
IN PVOID pContext ) {
...
IoFreeMdl( pIrp->MdlAddress );
IoFreeIrp( pIrp );
return STATUS_MORE_PROCESSING_REQUIRED;
}
ISLab Flash Team
Ch 15. Layered Drivers
31
Made By ICEUNI
다른 방법으로 IRP 할당하기(2)
• ExAllocatePool로 IRP 할당하기
– 읽기 동작이라고 가정하고, 설정한다.
– MDL 대신 커스텀 버퍼를 사용한다.
– 이전 예제에서 보여주었듯이, 원래 호출자의 쓰레드 정보를 복사
한다.
NTSTATUS IoCompletion(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp,
IN PVOID pContext ) {
...
// 하위 드라이버에 의해 사용된 커스텀 버퍼를 해제한다.
ExFreePool( pIrp->AssociatedIrp.SystemBuffer );
// 수동으로 할당된 IRP를 해제한다.
IoFreeIrp( pIrp );
return STATUS_MORE_PROCESSING_REQUIRED;
}
ISLab Flash Team
Ch 15. Layered Drivers
32
Made By ICEUNI
다른 방법으로 IRP 할당하기(3)
• 드라이버에서 관리하는 메모리로 IRP 할당하기
– IRP를 드라이버 전용 zone 버퍼 또는 lookaside 리스트 내에 할
당하는 방식으로 개별적인 공간에 유지시키는 설계를 해야 하는
경우가 있을 수 있다.
– 그러한 IRP들 또한 IoInitializeIrp를 사용하여 초기화
– I/O 관리자는 이러한 IRP에 대한 드라이버의 메모리 할당 정책을
알 수 없기 때문에, IoFreeIrp 함수를 사용할 수 없다.
– 대신 I/O완료 루틴에서 IRP를 해제할 수 있도록 하는 드라이버의
자체 함수로 IRP를 해제시켜야 한다.
ISLab Flash Team
Ch 15. Layered Drivers
33
Made By ICEUNI
하위 드라이버를 위한 버퍼 설정(1)
• Buffered I/O 요청
– 인터미디엇 드라이버 내의 디스패치 루틴에서 버퍼를 할당하기
위해 ExAllocatePool함수를 호출
– 드라이버에서 할당된 IRP의 AssociatedIrp.SystemBuffer필드 안
에 이 버퍼의 주소를 저장하게 된다.
– IRP에 지정된 I/O 완료 루틴은 반드시 ExFreePool함수로 해제되
어야 한다.
ISLab Flash Team
Ch 15. Layered Drivers
34
Made By ICEUNI
하위 드라이버를 위한 버퍼 설정(2)
• Direct I/O 요청
– 인터미디엇 드라이버에서 I/O 버퍼를 기술하는 MDL을 설정해야
하는 것을 의미한다.
– 인터미디엇 드라이버의 디스패치 동작
• IoAllocateMdl을 호출하여 버퍼에 맵핑시키기에 충분한 크기의 MDL
을 생성한다. 이 MDL의 주소를 드라이버에서 할당된 IRP의
MdlAddress 필등 안에 저장한다.
• 디스패치 루틴에서 MDL을 채운다. I/O 요청자의 IRP와 연관된 버퍼
를 맵핑시키기 위해서 IoBuildPartialMdl 함수를 호출한다. 시스템 메
모리를 MDL로 맵핑시키기 위해 MmBuildMdlForNonPagedPool 함
수를 호출한다.
• IoSetCompletionRoutine 함수를 사용하여 드라이버에서 할당된 IRP
에 I/O완료 루틴을 붙인다.
• 디스페치 루틴은 IoCallDriver를 호출하여 IRP를 하위 레벨 드라이버
로 보낸다.
ISLab Flash Team
Ch 15. Layered Drivers
35
Made By ICEUNI
드라이버에서 할당된 IRP를 기억하기(1)
• 동기 I/O
– 드라이버에서 IoBuildSynchronousFsdRequest 함수를 호출하여
IRP 몇 개를 할당하여 생성시킨다.
– 디스패치 루틴에서 IoCallDriver를 호출하여 할당한 IRP를 다른
드라이버들에게 전달한다.
– KeWaitForMultipleObjects를 호출하여 할당된 IRP가 완료될 때
까지 멈춰서 기다린다.
– IoCompleteRequest를 호출하여 원래의 IRP를 호출자로 돌려보
낸다.
ISLab Flash Team
Ch 15. Layered Drivers
36
Made By ICEUNI
드라이버에서 할당된 IRP를 기억하기(2)
• 비동기 I/O
– IoMarkPending을 호출하여 원래 호출자의 IRP를 처리중 상태로
지정한다.
– 디스패치 루틴에서 IRP를 새로 할당하는 메소드들 중 하나를 사
용하여 추가적으로 IRP를 생성한다.
– 디스패치 루틴은 IoSetCompletionRoutine을 사용하여 생성한 각
각의 IRP에 I/O 완료 루틴을 붙인다. IoSetCompletionRoutine을
호출할 때 원래 호출자의 IRP 포인터를 pContext 인자를 통해 전
달한다.
– 디스패치 루틴은 원래 IRP의 사용되지 않는 필드 안에 할당된
IRP 중 미결된 IRP의 카운트를 저장한다.
– IoCallDriver를 사용하여 IRP를 다른 드라이버로 전달한다.
– 디스패치 루틴에서 STATUS_PENDING 값을 리턴 값으로 돌려보
낸다.
ISLab Flash Team
Ch 15. Layered Drivers
37
Made By ICEUNI
드라이버에서 할당된 IRP를 기억하기(3)
• 비동기 I/O에서의 I/O 완료 루틴 수행
– 먼저, 정리할 필요가 있는 작업을 모두 수행하고 드라이버에서
할당된 IRP를 삭제한다.
– I/O 완료 루틴에서 ExInterlockedDecrementLong 함수를 호출하
여 원래 호출자의 IRP 안에 포함되어 있는 미해결된 IRP의 카운
트를 감소시킨다.
– 미해결된 IRP의 카운트가 0이면 드라이버에서 할당된 IRP 중 미
해결된 마지막 IRP가 완료되었다는 것을 의미한다.
IoCompleteRequest를 사용하여 IRP를 완료
– STATUS_MORE_PROCESSING_REQUIRED를 리턴하여 드라이
버에서 할당된 IRP에 대한 처리를 더 이상 하지 못하게 한다.
ISLab Flash Team
Ch 15. Layered Drivers
38
Made By ICEUNI
ISLab Flash Team
Part1. Summary
Summary
•
•
•
•
•
계층 드라이버
유지보수가 쉽다.
디버깅 시간을 단축시킨다.
소프트웨어 재사용
IRP 전달하는 I/O 관리자의 호출 메커니즘
ISLab Flash Team
Ch 15. Layered Drivers
40
Made By ICEUNI