1 / 40

Ch 15. Layered Drivers

Ch 15. Layered Drivers. PartⅠ. Contents. 인터미디엇 드라이버의 개관 계층 드라이버의 작성 I/O 완료 루틴의 작성 IRP 의 추가 할당 PartⅠ. Summary 필터 드라이버의 작성 예제코드 : 필터 드라이버 커플 드라이버의 작성 Summary. 1. Intermediate 드라이버의 개관. Intermediate 드라이버의 정의. Intermediate 드라이버는 I/O 요청을 다른 드라이버에게 전달하는 커널 모드 드라이버이다 .

carson
Download Presentation

Ch 15. Layered Drivers

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Ch 15. Layered Drivers PartⅠ

  2. Contents • 인터미디엇 드라이버의 개관 • 계층 드라이버의 작성 • I/O 완료 루틴의 작성 • IRP의 추가 할당 • PartⅠ. Summary • 필터 드라이버의 작성 • 예제코드 : 필터 드라이버 • 커플 드라이버의 작성 • Summary Ch 15. Layered Drivers

  3. 1. Intermediate 드라이버의 개관

  4. Intermediate 드라이버의 정의 • Intermediate 드라이버는 I/O 요청을 다른 드라이버에게 전달하는 커널 모드 드라이버이다. • Intermediate 드라이버는 WDM 호환 드라이버를 구현할 때의 구조와 WDM 모델이 아닌 드라이버 구조로 구분된다. • Intermediate 드라이버의 대표적인 예로는 계층 드라이버를 들 수 있다. Ch 15. Layered Drivers

  5. Intermediate 드라이버 구분 <계층 드라이버의 구분> Ch 15. Layered Drivers

  6. 계층적 구조의 장점(1) • 상위 레벨의 프로토콜을 특정 하드웨어의 관리를 담당하는 하부의 코드와 구분 짓도록 할 수 있다. • 하드웨어를 담당하는 코드를 다시 재작성하지 않고 보다 다양한 종류의 하드웨어를 지원할 수 있게 된다는 것을 뜻한다. • 동일한 프로토콜 드라이버를 다른 하드웨어에 실시간으로 플러그인시키는 것을 허락함으로써 보다 많은 유연성을 제공하게 된다. Ch 15. Layered Drivers

  7. 계층적 구조의 장점(2) • 포트 드라이버–디바이스 컨트롤러를 위한 단일 디바이스 드라이버 • 클래스 드라이버–디바이스 컨트롤러에 붙는 각의 개별적인 상위 레벨(작고 가볍다) • 드라이버를 드라이버 계층에 삽입시키는 것은 동일한 제품을 위해 다수의 코드를 작성하지 않고 제품의 특성을 추가시키거나 제거하는 투명한 방법을 제공하는 것이다. Ch 15. Layered Drivers

  8. 계층적 구조의 단점 • I/O 관리자를 통해 각각의 IRP가 매번 한 드라이버에서 다른 드라이버로 전달됨으로 인해 I/O 요청이 과도한 오버헤드가 발생할 수 있다. • 계층적 구조를 구현하기 위해 각 드라이버 구성 요소를 서로 잘 맞게 접목시키는 설계에 대한 많은 노력을 기울여야 한다. • 드라이버들을 관리한데 있어서는 부기(簿記, bookkeeping)와도 같이 각 드라이버 인터페이스에 대한 문서화가 더욱 필요하다. • 계층적 구조의 드라이버를 설치하는 것은 각 드라이버가 적절한 설치 과정을 거쳐야 한다는 점이 따르게 된다. Ch 15. Layered Drivers

  9. 2. 계층 드라이버의 작성

  10. 계층 드라이버가 동작하는 방식 IRP For Hi0 HI0 I/O Completion return IoCallDriver 바로 IRP를 하위 드라이버로 내려 보냄 LO0 IoCompleteRequest <계층 드라이버의 동작> IRP를 처리중의 상태로 유지하고 추가적으로 IRP를 생성 하위 드라이버에게 이를 보낸다. Ch 15. Layered Drivers

  11. 계층 드라이버의 초기화와 정리 루틴(1) • DriverEntry • 계층 드라이버에서 수행되는 초기화 과정은 일반 드라이버에서 수행되는 초기화 과정과 비슷하다. • 차이점은 상단에서 내려온 I/O 요청을 직접 처리할 것인지 아니면 하위 레벨의 드라이버로 보내어 처리할 것인지 결정하는데 있다. • IRP요청에 대해 적당한 처리를 수행할 수 있도록 초기화시키는 역할을 담당 Ch 15. Layered Drivers

  12. 계층 드라이버의 초기화와 정리 루틴(2) • AddDevice 루틴 ① 상위레벨 디바이스 객체 생성 AddDevice 루틴 ① IoCreateDevice ② push ② ② 타겟 디바이스 객체의 포인터 저장(익스텐션) ② IoAttatchDeviceToDeviceStack ③ 상위 레벨 디바이스 객체 StackSize > 타겟 디바이스 객체 StackSize 디바이스 스택 ② 포인터 ④ IRP 전달 ④ IRP_MJ_CREATE 타겟 디바이스 ⑤ IoCreateSymbolicLink 객체 관리자 “\device\Hi ⑤ 추가 W?? Ch 15. Layered Drivers

  13. 계층 드라이버의 초기화와 정리 루틴(3) • RemoveDevice • IRP_MN_REMOVE_DEVICE 요청이 계층 드라이버로 보내어졌을 때 드라이버는 반드시 AddDevice 루틴에서 수행했던 동작을 거꾸로 수행해야 한다. 객체 관리자 RemoveDevice 루틴 \device\Hi ① IoCreateSymbolicLink ① 제거 ② IRP_MJ_CLOSE ② IRP 전달 타겟 디바이스 ③ ioDetachDevice 레퍼런스 카운트-- ④ IoDeleteDevice 상위 레벨의 디바이스 객체 삭제 Ch 15. Layered Drivers

  14. 계층 드라이버를 위한 초기화(1) • 투명형 계층 드라이버/가상(논리)형 계층 드라이버 두가지 방식 중 한가지로 동작 • 투명형 계층 드라이버 • 어떤 계층 드라이버들은 하위 계층의 드라이버와 그 드라이버의 클라이언트 사이에서 투명하게 동작하도록 만들어진다. • DriverEntry • 하위 드라이버에 의해 제공되는 MajorFunction코드의 세트를 모두 지원해야 하고, IRP 요청이 내려왔을 때 아무 동작을 수행하지 않고 이를 통과시키거나 아니면 하위 드라이버의 동작을 수정하도록 한다. • AddDevice • 타겟 디바이스 객체의 DeviceType과 Characteristics 필드를 계층 드라이버 디바이스 객체로 복사해둔다. • 타겟 디바이스의 Flags 필드로부터 DO_DIRECT_IO 또는 DO_BUFFERED_IO 비트를 복사한다. Ch 15. Layered Drivers

  15. 계층 드라이버를 위한 초기화(2) • 가상(논리)형 계층 드라이버 • 계층 드라이버의 또 다른 형태는 계층 드라이버가 가상 혹은 논리 디바이스 객체를 익스포트시키는 드라이버이다. • 가상 계층은 실제적인 하부의 물리적인 구현에 대한 어떠한 유사점을 담당하는 디바이스 추상화를 종합하도록 하는 것이 가능하다. • 자신의 디바이스 객체의 Type과 Characteristic필드에 적당한 값을 선택해야만 한다. 또한, 계층 드라이버에 의해 제공되는 MajorFunction 디스패치 함수의 전체 세트를 논리 디바이스 객체에 적당하게 설정해야 한다. Ch 15. Layered Drivers

  16. 계층 드라이버에서 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 값으로 전달한다. Ch 15. Layered Drivers

  17. 계층 드라이버에서 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 리턴 Ch 15. Layered Drivers

  18. 계층 드라이버에서 I/O 요청 처리(3) • IRP를 새로 할당하기 • 계층 드라이버의 디스패치 루틴은 하위 드라이버로 보내게 될 하나 또는 그 이상의 추가 IRP를 할당하는 것이 필요할 지도 모른다. • 새로 생성한 IRP가 완료될 때까지 기다리거나 또는 비동기 호출과 같은 방식 중 하나를 선택할 수 있다. • 비동기 호출의 경우에는 새로 할당한 IRP를 정리하는 코드가 I/O 완료 루틴 내에서 일어나게 된다. Ch 15. Layered Drivers

  19. 3. I/O 완료 루틴의 작성

  20. I/O 완료 콜백을 요청하기 • IoSetCompletionRoutine 함수 • I/O 완료 루틴의 주소를 하위 레벨 드라이버의 I/O 스택 로케이션 안에 넣는 역할을 한다. <IoSetCompletionRoutine 함수 원형> Ch 15. Layered Drivers

  21. 실행 컨텍스트 • I/O 완료 루틴이 호출되는 시점에 I/O 관리자는 I/O 스택 포인터를 스택에서 꺼낸다. <I/O 완료 루틴의 함수 원형> Ch 15. Layered Drivers

  22. I/O 완료 루틴의 수행 동작(1) • 원본 IRP를 해제하기 • 만약 완료된 IRP가 외부 드라이버의 IoCompletionRequest 호출에 의한 것이라면 몇가지 드라이버 전용의 해제 과정을 필요로 할 것이다. • IRP의 PendingReturned 플래그 값을 체크한다. • 만약 이 플래그가 TRUE이면, I/O 완료 루틴은 IoMarkIrpPending을 호출하여 현재 I/O 스택 로케이션을 처리 중 상태로 설정한다. • STATUS_SUCCESS 값으로 리턴하여 완료 처리가 계속 되도록 한다. Ch 15. Layered Drivers

  23. I/O 완료 루틴의 수행 동작(2) • IRP의 해제 • 만약 IRP가 이 드라이버에 의해 할당되었다면, I/O 완료 루틴에서 IRP를 해제해야 할 책임이 있다. • IRP가 할당된 방식에 근거하여, 적절한 IRP의 해제 기법이 뒤따라야만 한다. Ch 15. Layered Drivers

  24. I/O 완료 루틴의 수행 동작(3) • IRP의 재사용 • 일반적으로 데이터를 분할하는 가장 효율적인 방법은 동일한 IRP를 재사용하여 하위 드라이버로 각 데이터를 전송하는 것이다. • IRP가 마지막 데이터 전송인지, 아닌지를 판단하기 위해 IRP 안에 저장된 컨텍스트 정보를 체크한다. • STATUS_MORE_PROCESSING_REQUIRED를 리턴하여 상위 드라이버에서 더 이상 완료 처리가 일어나지 않도록 한다. • IoSetCompletionRoutine을 호출하여 해당 IRP에 I/O 완료 루틴의 주소를 설정한다. • IoCallDriver를 사용하여 IRP에 타겟 디바이스 객체를 전달한다. • 마지막으로 STATUS_MORE_PROCESSING_REQUIRED를 리턴하여 이 IRP에 대한 더 이상의 완료 처리가 수행되지 않도록 한다. Ch 15. Layered Drivers

  25. 4. IRP의 추가 할당

  26. IRP의 I/O 스택 재방문(Revisited) <I/O 스택 포인터에 영향을 주는 함수들> Ch 15. Layered Drivers

  27. 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를 다른 드라이버에게 전달 Ch 15. Layered Drivers

  28. IoBuildSynchronousFsdRequest로 IRP 생성 • Read, write, flush, shutdown IRP를 동기적으로 만드는데 사용한다. <IoBuildSynchronousFsdRequest 함수 원형> Ch 15. Layered Drivers

  29. Read, write, flush, shutdown IRP를 비동기적으로 만드는데 사용 IoBuildAsynchronousFsdRequest로 IRP 생성 <IoBuildSynchronousFsdRequest 함수 원형> Ch 15. Layered Drivers

  30. IoBuildDeviceIoControlRequest로 IRP 생성 • IOCTL IRP를 만드는 작업을 제공한다. • Custom IOCTL을 통해 어떤 특정 동작을 드라이버에서 익스포트시킨 인터페이스를 사용하는 일반적인 방법 < IoBuildDeviceControlRequest 함수 원형> Ch 15. Layered Drivers

  31. 다른 방법으로 IRP 할당하기(1) • IoAllocateIrp를 사용하여 IRP 할당하기 • 하부의 드라이버의 요구 사항을 만족시킬 만큼의 충분한 크기의 스택 로케이션을 가진 IRP를 할당한다. • DMA를 위한 메모리 디스크립터 리스트를 할당한다. • 새로운 IRP에 읽기 요청을 설정한다. • 읽기 요청을 위한 매개변수들을 채운다. • 하위 드라이버에게 어느 쓰레드가 원본 요청을 만들었는지 알 수 있게 보장한다.(에러가 발생했을 경우 반드시 보고되어야 하기 때문이다.) • 마지막으로 새로 생성한 IRP를 아래로 내려보낸다. NTSTATUS IoCompletion( IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext ) { ... IoFreeMdl( pIrp->MdlAddress ); IoFreeIrp( pIrp ); return STATUS_MORE_PROCESSING_REQUIRED; } Ch 15. Layered Drivers

  32. 다른 방법으로 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; } Ch 15. Layered Drivers

  33. 다른 방법으로 IRP 할당하기(3) • 드라이버에서 관리하는 메모리로 IRP 할당하기 • IRP를 드라이버 전용 zone 버퍼 또는 lookaside 리스트 내에 할당하는 방식으로 개별적인 공간에 유지시키는 설계를 해야 하는 경우가 있을 수 있다. • 그러한 IRP들 또한 IoInitializeIrp를 사용하여 초기화 • I/O 관리자는 이러한 IRP에 대한 드라이버의 메모리 할당 정책을 알 수 없기 때문에, IoFreeIrp 함수를 사용할 수 없다. • 대신 I/O완료 루틴에서 IRP를 해제할 수 있도록 하는 드라이버의 자체 함수로 IRP를 해제시켜야 한다. Ch 15. Layered Drivers

  34. 하위 드라이버를 위한 버퍼 설정(1) • Buffered I/O 요청 • 인터미디엇 드라이버 내의 디스패치 루틴에서 버퍼를 할당하기 위해 ExAllocatePool함수를 호출 • 드라이버에서 할당된 IRP의 AssociatedIrp.SystemBuffer필드 안에 이 버퍼의 주소를 저장하게 된다. • IRP에 지정된 I/O 완료 루틴은 반드시 ExFreePool함수로 해제되어야 한다. Ch 15. Layered Drivers

  35. 하위 드라이버를 위한 버퍼 설정(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를 하위 레벨 드라이버로 보낸다. Ch 15. Layered Drivers

  36. 드라이버에서 할당된 IRP를 기억하기(1) • 동기 I/O • 드라이버에서 IoBuildSynchronousFsdRequest 함수를 호출하여 IRP 몇 개를 할당하여 생성시킨다. • 디스패치 루틴에서 IoCallDriver를 호출하여 할당한 IRP를 다른 드라이버들에게 전달한다. • KeWaitForMultipleObjects를 호출하여 할당된 IRP가 완료될 때까지 멈춰서 기다린다. • IoCompleteRequest를 호출하여 원래의 IRP를 호출자로 돌려보낸다. Ch 15. Layered Drivers

  37. 드라이버에서 할당된 IRP를 기억하기(2) • 비동기 I/O • IoMarkPending을 호출하여 원래 호출자의 IRP를 처리중 상태로 지정한다. • 디스패치 루틴에서 IRP를 새로 할당하는 메소드들 중 하나를 사용하여 추가적으로 IRP를 생성한다. • 디스패치 루틴은 IoSetCompletionRoutine을 사용하여 생성한 각각의 IRP에 I/O 완료 루틴을 붙인다. IoSetCompletionRoutine을 호출할 때 원래 호출자의 IRP 포인터를 pContext 인자를 통해 전달한다. • 디스패치 루틴은 원래 IRP의 사용되지 않는 필드 안에 할당된 IRP 중 미결된 IRP의 카운트를 저장한다. • IoCallDriver를 사용하여 IRP를 다른 드라이버로 전달한다. • 디스패치 루틴에서 STATUS_PENDING 값을 리턴 값으로 돌려보낸다. Ch 15. Layered Drivers

  38. 드라이버에서 할당된 IRP를 기억하기(3) • 비동기 I/O에서의 I/O 완료 루틴 수행 • 먼저, 정리할 필요가 있는 작업을 모두 수행하고 드라이버에서 할당된 IRP를 삭제한다. • I/O 완료 루틴에서 ExInterlockedDecrementLong 함수를 호출하여 원래 호출자의 IRP 안에 포함되어 있는 미해결된 IRP의 카운트를 감소시킨다. • 미해결된 IRP의 카운트가 0이면 드라이버에서 할당된 IRP 중 미해결된 마지막 IRP가 완료되었다는 것을 의미한다. IoCompleteRequest를 사용하여 IRP를 완료 • STATUS_MORE_PROCESSING_REQUIRED를 리턴하여 드라이버에서 할당된 IRP에 대한 처리를 더 이상 하지 못하게 한다. Ch 15. Layered Drivers

  39. Part1. Summary

  40. Summary • 계층 드라이버 • 유지보수가 쉽다. • 디버깅 시간을 단축시킨다. • 소프트웨어 재사용 • IRP 전달하는 I/O 관리자의 호출 메커니즘 Ch 15. Layered Drivers

More Related