1 / 39

Ch 7. Driver Dispatch Routines

Ch 7. Driver Dispatch Routines. Goals. 드라이버와 드라이버 디스패치 루틴 점진적인 개발 방법론. Kernel Mode Object Type 결정 Driver 에 필요한 Context 결정 및 Store Place 결정 DriverEntry, Unload Routine 을 작성 (6 장 ) IRP_MJ_CREATE, IRP_MJ_CLOSE dispatch Routine(7 장 ) CreateFile , CloseHandle

renee
Télécharger la présentation

Ch 7. Driver Dispatch Routines

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 7. Driver Dispatch Routines

  2. Goals • 드라이버와 드라이버 디스패치 루틴 • 점진적인 개발 방법론 • Kernel Mode Object Type 결정 • Driver에 필요한 Context결정 및 Store Place 결정 • DriverEntry, Unload Routine을 작성(6장) • IRP_MJ_CREATE, IRP_MJ_CLOSE dispatch Routine(7장) • CreateFile , CloseHandle • Hardware 검색및 자원을 할당하는 Code 추가 • Unload시 할당된 자원을 해제하는 Code 추가 • IRP_MJ_XXX 함수를 처리하는 dispatch Routine 추가 • Win32 App에서 ReadFile, WriteFile 등으로 Test 가능 • 실질적인 Routine 작성 • Start I/O Routine • Interrupt Service Routine • DPC Routine • DeviceIOControl Code 추가 • Win32 App가 직접 Hardware Register를 제어할수 있음 Ch 7. Driver Dispatch Routines

  3. Contents • Driver Dispatch Routines • Writing Driver Dispatch Routines • Processing Read and Write Requests • Code Example : Loop-back Device • Extending the Dispatch interface • Testing Driver Dispatch Routine • Summary Ch 7. Driver Dispatch Routines

  4. Driver Dispatch Routines

  5. 디스패치 루틴에서의 I/O 요청 메커니즘(1) <IRP의 구조> <DriverObject 구조> <IRP 외부로 보여지는 IRP 스택 로케이션 필드> Ch 7. Driver Dispatch Routines

  6. 디스패치 루틴에서의 I/O 요청 메커니즘(2) MajorFunction [IRP_MJ_CREATE] MajorFunction[] . . . [IRP_MJ_READ] [IRP_MJ_WRITE] . . . 쓰기 디스패치 루틴 ※ _IopInvalidDeviceRequest는 올바르지 않은 I/O 요청일 경우에 불리는 함수로써 에러를 I/O요청자에게 리턴 Ch 7. Driver Dispatch Routines

  7. 특정 함수 코드의 활성화 NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDO, IN PUNICODE_STRING pRegPath) { : pDO->MajorFunction[ IRP_MJ_CREATE ] = DispCreate; pDO->MajorFunction[ IRP_MJ_CLOSE ] = DispClose; pDO->MajorFunction[ IRP_MJ_CLEANUP ] = DispCleanup; pDO->MajorFunction[ IRP_MJ_READ ] = DispRead; pDO->MajorFunction[ IRP_MJ_WRITE ] = DispWrite; : return STATUS_SUCCESS; } • IRP_MJ_XXX(NTDDK.h, WDM.h) • DriverEntry가 호출되기 전에 _IopInvalidDeviceRequest 포인터로 다채운다. Ch 7. Driver Dispatch Routines

  8. 어떤 함수 코드를 지원할 지 결정하기 Ch 7. Driver Dispatch Routines

  9. Writing Driver Dispatch Routines

  10. 실행 컨텍스트 • 디스패치 루틴은 비슷한 형태를 가진다. • PASSIVE_LEVEL IRQL <디스패치 루틴의 함수 원형> • Buffered I/O 와 Direct I/O 문제 • IRP와 IRP이외의 구조체의 사용에 대한 문제 • 공유 데이터 구조 IRP에 따른 문제 Ch 7. Driver Dispatch Routines

  11. 디스패치 루틴에서 수행하는 동작 • IoGetCurrentIrpStackLocation • IRP에 대한 유효성 체크 • 하부 드라이버로 전달 • 에러발생시 _IopInvalidDeviceRequest를 리턴하고 수행중지 Ch 7. Driver Dispatch Routines

  12. 디스패치 루틴에서 빠져나오기(1) • 에러 통보 • 요청 완료 • 디바이스 동작을 스케줄링 Ch 7. Driver Dispatch Routines

  13. 디스패치 루틴에서 빠져나오기(2) • 에러의 통보 NTSTATUS DispatchWrite(IN PDEVICE_OBJECT pDO, IN PIRP pIrp) { : // 만약 해당 요청이 이 디바이스에서 지원되지 않는 것이라면 // 결과를 보고하고 요청을 거절한다. pIrp->IoStatus.Status = STATUS_NOT_INCREMENT_SUPPORTED; // 전송된 데이터가 없음을 보고한다. pIrp->IoStatus.Information = 0; //우선순위의 증가 없이 IRP를 완료시킨다. IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_NOT_SUPPORTED; } Ch 7. Driver Dispatch Routines

  14. 디스패치 루틴에서 빠져나오기(3) • 요청의 완료 NTSTATUS DispatchClose(IN PDEVICE_OBJECT pDO, IN PIRP pIrp) { : pIrp->IoStatus.Status = STATUS_SUCCESS; // 전송된 데이터가 0바이트라고 지정한다. pIrp->IoStatus.Information = 0; // IRP를 완료로 지정한다. – 더 이상의 처리를 수행하지 않는다. IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } Ch 7. Driver Dispatch Routines

  15. 디스패치 루틴에서 빠져나오기(4) • 디바이스 동작을 스케줄링 NTSTATUS DispatchWrite(IN PDEVICE_OBJECT pDO, IN PIRP pIrp) { : // IRP를 진행중으로 설정한다. IoMarkIrpPending(pIrp); // 드라이버의 Start I/O 루틴을 통해 이벤트 처리의 // IRP를 큐잉(스케줄링)한다. // 세 번째 매개변수는 해당 I/O 요청을 큐의 끝에 삽입되도록 한다. // 네 번째 매개변수는 Cancel 루틴에 대한 지점이다. IoStartPacket(pDO, pIrp, 0, NULL); return STATUS_PENDING; } Ch 7. Driver Dispatch Routines

  16. Processing Read and Write Requests

  17. 사용자 버퍼로의 접근 • 디바이스 객체의 Flags 필드(DO_BUFFERED_IO, DO_DIRECT_IO) • BUFFERED I/O - Non-paged 풀(pool) 버퍼를 할당 - IRP의 AssociatedIrp.SystemBuffer 필드에 위치 • DIRECT I/O - 사용자 버퍼에 해당하는 물리 메모리 페이지를 잠근다(lock) - MDL(Memory Descriptor List) - IRP의 MdlAddress 필드에 저장 • NEITHER Method - Flags필드 세팅이 되지 않았을 경우 - I/O 관리자는 어떤 버퍼 관리도 처리하지 않는다. Ch 7. Driver Dispatch Routines

  18. Code Example loop-back routine

  19. Code Example : 루프백 디바이스(1) Write 요청에 대한 디스패치루틴(1) NTSTATUS DispatchWrite ( IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PVOID userBuffer; ULONG xferSize; // 스택 로케이션은 사용자 버퍼의 정보를 갖고 있다. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp ); // 현재 버퍼의 포인터는 디바이스 객체 내에 포함된 DEVICE_EXTENSION 안에 저장된다. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; // 버퍼가 이미 할당되어 있다면 해제한다. if (pDevExt->deviceBuffer != NULL) { ExFreePool(pDevExt->deviceBuffer); pDevExt->deviceBuffer = NULL; pDevExt->deviceBufferSize = 0; } xferSize = pIrpStack->Parameters.Write.Length; // 이 예제에서는 디바이스가 Buffered I/O를 사용하고 있다고 가정 userBuffer = pIrp->AssociatedIrp.SystemBuffer; Ch 7. Driver Dispatch Routines

  20. Code Example : 루프백 디바이스(2) Write 요청에 대한 디스패치루틴(2) pDevExt->deviceBuffer = ExAllocatePool( PagedPool, xferSize ); if (pDevExt->deviceBuffer == NULL) { // 버퍼 할당에 실패 status = STATUS_INSUFFICIENT_RESOURCES; xferSize = 0; } else { // 버퍼를 복사 pDevExt->deviceBufferSize = xferSize; RtlCopyMemory( pDevExt->deviceBuffer, userBuffer, xferSize ); } // 디바이스 동작을 수행하지 않고 IRP를 완료한다. pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = xferSize; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); return status; } Ch 7. Driver Dispatch Routines

  21. Code Example : 루프백 디바이스(3) Read 요청에 대한 디스패치루틴(1) NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; PVOID userBuffer; ULONG xferSize; // 스택 로케이션은 사용자 버퍼의 정보를 가지고 있다. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp ); // 현재 버퍼의 포인터는 디바이스 객체 내에 포함된 DEVICE_EXTENSION 안에 저장 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; xferSize = pIrpStack->Parameters.Read.Length; userBuffer = pIrp->AssociatedIrp.SystemBuffer; // 사용자의 요청에 대해 더 이상 전송을 수행하지 않는다. xferSize = (xferSize < pDevExt->deviceBufferSize) ? xferSize : pDevExt->deviceBufferSize; Ch 7. Driver Dispatch Routines

  22. Code Example : 루프백 디바이스(4) Read 요청에 대한 디스패치루틴(1) // 현재 버퍼를 사용자 공간으로 복사한다. RtlCopyMemory( userBuffer, pDevExt->deviceBuffer, xferSize ); // 현재 paged 풀 버퍼를 해제한다. ExFreePool( pDevExt->deviceBuffer ); pDevExt->deviceBuffer = NULL; pDevExt->deviceBufferSize = 0; // 그리고 I/O 요청을 완료한다. pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = xferSize; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); return status; } Ch 7. Driver Dispatch Routines

  23. Code Example : 루프백 디바이스(5) Ch 7. Driver Dispatch Routines

  24. Extending the Dispatch Interface

  25. 디스패치 인터페이스의 확장 • read/write 동작 이외에 다른 동작 (예 : 디스크 포맷, 파티션) • IRP_MJ_DEVICE_CONTROL - IoControl(IOCTL 디바이스 컨트롤 값) • IRP_MJ_INTERNAL_DEVICE_CONTROL - 커널 모드에서의 확장 - IRP_MJ_DEVICE_CONTROL와 유사 Ch 7. Driver Dispatch Routines

  26. 개별적인 IOCTL 값에 대한 정의(1) 0 31 디바이스 타입 요청된 접근 컨트롤 코드 전송 타입 <IOCTL 코드 구조체의 레이아웃> Ch 7. Driver Dispatch Routines

  27. 개별적인 IOCTL 값에 대한 정의(2) <CTL_CODE 매크로 인자> Ch 7. Driver Dispatch Routines

  28. IOCTL 인자 전달 방법 • CTL_CODE의 TransferType(2bit) • METHOD_BUFFERED • METHOD_IN_DIRECT • METHOD_OUT_DIRECT • METHOD_NEITHER Ch 7. Driver Dispatch Routines

  29. IOCTL 헤더 파일 작성하기 #define IOCTL_MISSLEDEVICE_AIM CTL_CODE( FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ACCESS_ANY) // IOCTL_MISSLEDEVICE_AIM 에서 사용된 구조체 Typedef struct _AIM_IN_BUFFER { ULONG Longitude; ULONG Latitude; } AIM_IN_BUFFER, *PAIM_IN_BUFFER; Typedef struct _AIM_OUT_BUFFER { ULONG ExtendedStatus; } AIM_OUT_BUFFER, *PAIM_OUT_BUFFER; #define IOCTL_MISSLEDEVICE_LAUNCH CTL_CODE( \ FILE_DEVICE_UNKNOWN, \ 0x802, \ METHOD_NEITHER, \ FILE_ACCESS_ANY) Ch 7. Driver Dispatch Routines

  30. IOCTL 요청의 처리(1) • I/O 관리자가 아닌 드라이버의 책임 NTSTATUS DispatchIoControl(IN PDEVICE_OBJECT pDO, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION pDE; PVOID userBuffer; ULONG inSize; ULONG outSize; ULONG controlCode; // IOCTL 요청 변수 // 스택 로케이션은 사용자 버퍼의 정보를 담고 있다. PIO_STACK_LOCATION pIrpStack; pIrpStack = IoGetCurrentIrpStackLocation(pIrp); // IOCTL 요청을 뽑아낸다. controlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode; // 그리고 요청된 전송 크기도 알아낸다. inSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength; outSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; Ch 7. Driver Dispatch Routines

  31. // // 두 번째 Switch 문을 구현한다. switch (controlCode) { case IOCTL_MISSLEDEVICEAIM : // 각 case에서 항상 매개변수의 유효함을 확인하다. if(inSize < sizeof(AIM_IN_BUFFER) || outSize < sizeof(AIM_OUT_BUFFER)) { status = STATUS_INVALID_BUFFER_SIZE; break; } // 유효한 IRP이므로 디바이스를 구동한다. IoMarkIrpPending(pIrp); IoStartPacket(pDO, pIrp, 0, NULL); return STATUS_PENDING; case IOCTL_DEVICE_LAUNCH : if(inSize > 0 || outSize >0) // 진짜 에러는 아니다. 그러나 호출자에게 해당 호출의 //목적에 대해 다시 생각하도록 주의를 준다. { status = STATUS_INVALID_PARAMETER; break; } // 디바이스를 구동하게 하는 동일한 코드를 넣는다. // : return STATUS_PENDING; default : // 드라이버에서 인식할 수 없는 요청을 받았다. status = STATUS_INVALID_DEVICE_REQUEST; break; } IOCTL 요청의 처리(2) Ch 7. Driver Dispatch Routines

  32. IOCTL 요청의 처리(3) // 유효한 컨트롤 코드의 경우는 상위 계층으로 리턴된다. // 이 부분에서의 실행은 에러가 발생했을 경우이다. // IRP 요청을 실패 처리한다. pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; //아무런 데이터가 없음을 지정한다. IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; } Ch 7. Driver Dispatch Routines

  33. IOCTL 버퍼 관리 • 독립적인 버퍼 전송 메커니즘 • 입력과 출력의 2개의 버퍼 • METHOD_BUFFERED • METHOD_IN_DIRECT • METHOD_OUT_DIRECT • METHOD_NEITHER Ch 7. Driver Dispatch Routines

  34. Testing Driver Dispatch Routines

  35. 테스트 과정 • 디바이스의 핸들을 제대로 열고 닫을 수 있는지 • 비록 데이터의 전송은 수행하지 않는다 하더라도, Win32 I/O 함수의 호출이 성공적인지 • 다수의 I/O요청에 대해 정상동작을 하는지 Ch 7. Driver Dispatch Routines

  36. 예제 테스트 프로그램 #include <windows.h> #include <stdio.h> Void main() { HANDLE hDevice; BOOL status; hDevice = CreateFile(\\\\.\\LBK1 ...); : status = ReadFile(hDevice, ...); : status = WriteFile(hDevice, ...); : status = DeviceIoControl(hDevice, ...); : status = CloseHandle(hDevice, ...); } <Win32 콘솔 테스트 프로그램> Ch 7. Driver Dispatch Routines

  37. 예제 테스트 프로그램 결과 Ch 7. Driver Dispatch Routines

  38. Summary

  39. Summary • 드라이버 디스패치 루틴은 드라이버와 I/O 요청자 간의 인터페이스를 제공한다. • 드라이버는 읽기, 쓰기 그리고 디바이스 I/O 컨트롤을 지원한다. Ch 7. Driver Dispatch Routines

More Related