I/O 제어 코드 정의

새 IOCTL을 정의할 때는 다음 규칙을 기억해야 합니다.

  • 사용자 모드 소프트웨어 구성 요소에 새 IOCTL을 사용할 수 있는 경우 IOCTL을 IRP_MJ_DEVICE_CONTROL 요청과 함께 사용해야 합니다. 사용자 모드 구성 요소는 Win32 함수인 DeviceIoControl을 호출하여 IRP_MJ_DEVICE_CONTROL 요청을 보냅니다.
  • 커널 모드 드라이버 구성 요소에만 새 IOCTL을 사용할 수 있는 경우 IOCTL을 IRP_MJ_INTERNAL_DEVICE_CONTROL 요청과 함께 사용해야 합니다. 커널 모드 구성 요소는 IoBuildDeviceIoControlRequest를 호출하여 IRP_MJ_INTERNAL_DEVICE_CONTROL 요청을 만듭니다. 자세한 내용은 드라이버에서 IOCTL 요청 만들기를 참조하세요.

I/O 컨트롤 코드는 여러 필드로 구성된 32비트 값입니다. 다음 그림에서는 I/O 컨트롤 코드의 레이아웃을 보여 줍니다.

i/o 컨트롤 코드 레이아웃을 보여 주는 다이어그램

Wdm.h 및 Ntddk.h에 정의된 시스템 제공 CTL_CODE 매크로를 사용하여 새 I/O 제어 코드를 정의합니다. 새 IOCTL 코드의 정의는 IRP_MJ_DEVICE_CONTROL 또는 IRP_MJ_INTERNAL_DEVICE_CONTROL 요청에 사용할지 여부에 관계없이 다음 형식을 사용합니다.

#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)

IOCTL의 설명 상수 이름을 선택합니다. 여기서 디바이스는 디바이스 유형을 나타내고 Function은 작업을 나타내는 형식인 IOCTL_Device_Function 형식입니다. 예제 상수 이름은 IOCTL_VIDEO_ENABLE_CURSOR.

CTL_CODE 매크로에 다음 매개 변수를 제공합니다.

DeviceType
디바이스 유형을 식별합니다. 이 값은 드라이버의 DEVICE_OBJECT 구조체의 DeviceType 멤버에 설정된 값과 일치해야 합니다. ( 디바이스 유형 지정 참조). 0x8000 미만의 값은 Microsoft용으로 예약되어 있습니다. 0x8000 이상의 값은 공급업체에서 사용할 수 있습니다. 공급업체가 할당한 값은 Common 비트를 설정합니다.

FunctionCode
드라이버에서 수행할 함수를 식별합니다. 0x800 미만의 값은 Microsoft용으로 예약되어 있습니다. 0x800 이상의 값은 공급업체에서 사용할 수 있습니다. 공급업체에서 할당한 값은 사용자 지정 비트를 설정합니다.

TransferType
시스템이 DeviceIoControl 호출자(또는 IoBuildDeviceIoControlRequest)와 IRP를 처리하는 드라이버 간에 데이터를 전달하는 방법을 나타냅니다.

다음 시스템 정의 상수 중 하나를 사용합니다.

METHOD_BUFFERED
일반적으로 요청당 소량의 데이터를 전송하는 데 사용되는 버퍼링된 I/O 메서드를 지정합니다. 디바이스 및 중간 드라이버에 대한 대부분의 I/O 제어 코드는 이 TransferType 값을 사용합니다.

시스템에서 METHOD_BUFFERED I/O 제어 코드에 대한 데이터 버퍼를 지정하는 방법에 대한 자세한 내용은 I/O 제어 코드에 대한 버퍼 설명을 참조하세요.

버퍼링된 I/O에 대한 자세한 내용은 버퍼링된 I/O 사용을 참조하세요.

METHOD_IN_DIRECT 또는 METHOD_OUT_DIRECT
DMA 또는 PIO를 사용하여 대량의 데이터를 읽거나 쓰는 데 일반적으로 사용되는 직접 I/O 메서드를 지정합니다. 이 메서드는 신속하게 전송해야 합니다.

DeviceIoControl 또는 IoBuildDeviceIoControlRequest 호출자가 드라이버에 데이터를 전달할지 여부를 METHOD_IN_DIRECT 지정합니다.

DeviceIoControl 또는 IoBuildDeviceIoControlRequest 호출자가 드라이버에서 데이터를 받을지 여부를 METHOD_OUT_DIRECT 지정합니다.

시스템에서 METHOD_IN_DIRECT 및 METHOD_OUT_DIRECT I/O 제어 코드에 대한 데이터 버퍼를 지정하는 방법에 대한 자세한 내용은 I/O 제어 코드에 대한 버퍼 설명을 참조하세요.

직접 I/O에 대한 자세한 내용은 Direct I/O 사용을 참조하세요.

METHOD_NEITHER
버퍼링되거나 직접 I/O를 지정하지 않습니다. I/O 관리자는 시스템 버퍼 또는 MDL을 제공하지 않습니다. IRP는 유효성을 검사하거나 매핑하지 않고 DeviceIoControl 또는 IoBuildDeviceIoControlRequest에 지정된 입력 및 출력 버퍼의 사용자 모드 가상 주소를 제공합니다.

시스템에서 METHOD_NEITHER I/O 제어 코드에 대한 데이터 버퍼를 지정하는 방법에 대한 자세한 내용은 I/O 제어 코드에 대한 버퍼 설명을 참조하세요.

이 메서드는 드라이버가 I/O 컨트롤 요청을 시작한 스레드의 컨텍스트에서 실행되도록 보장할 수 있는 경우에만 사용할 수 있습니다. 최상위 커널 모드 드라이버만 이 조건을 충족하도록 보장되므로 METHOD_NEITHER 하위 수준 디바이스 드라이버에 전달되는 I/O 제어 코드에 거의 사용되지 않습니다.

이 메서드를 사용하면 최고 수준의 드라이버가 요청을 수신할 때 사용자 데이터에 대한 버퍼링 또는 직접 액세스를 설정할지, 사용자 버퍼를 잠글지 여부를 결정해야 하며, 구조적 예외 처리기에서 사용자 버퍼에 대한 액세스를 래핑해야 합니다( 예외 처리 참조). 그렇지 않으면 원래 사용자 모드 호출자가 버퍼링된 데이터를 드라이버가 사용하기 전에 변경하거나 드라이버가 사용자 버퍼에 액세스하는 것처럼 호출자를 교체할 수 있습니다.

자세한 내용은 버퍼링되지 않은 I/O 또는 직접 I/O 사용을 참조하세요.

RequiredAccess
디바이스를 나타내는 파일 개체를 열 때 호출자가 요청해야 하는 액세스 유형을 나타냅니다( IRP_MJ_CREATE 참조). I/O 관리자는 호출자가 지정된 액세스 권한을 요청한 경우에만 IRP를 만들고 특정 I/O 제어 코드로 드라이버를 호출합니다. RequiredAccess 는 다음 시스템 정의 상수를 사용하여 지정됩니다.

FILE_ANY_ACCESS
I/O 관리자는 대상 디바이스 개체를 나타내는 파일 개체에 대한 핸들이 있는 호출자에 대해 IRP를 보냅니다.

FILE_READ_DATA
I/O 관리자는 읽기 액세스 권한이 있는 호출자에 대해서만 IRP를 보내 기본 디바이스 드라이버가 디바이스에서 시스템 메모리로 데이터를 전송할 수 있도록 합니다.

FILE_WRITE_DATA
I/O 관리자는 쓰기 액세스 권한이 있는 호출자에 대해서만 IRP를 보내 기본 디바이스 드라이버가 시스템 메모리에서 해당 디바이스로 데이터를 전송할 수 있도록 합니다.

호출자에게 읽기 및 쓰기 액세스 권한이 모두 있어야 하는 경우 FILE_READ_DATA 및 FILE_WRITE_DATA 함께 ORed할 수 있습니다.

일부 시스템 정의 I/O 제어 코드에는 FILE_ANY_ACCESS RequiredAccess 값이 있으며, 이를 통해 호출자는 디바이스에 부여된 액세스 권한에 관계없이 특정 IOCTL을 보낼 수 있습니다. 예를 들어 전용 디바이스의 드라이버로 전송되는 I/O 제어 코드가 있습니다.

다른 시스템 정의 I/O 제어 코드는 호출자에게 읽기 액세스 권한, 쓰기 액세스 권한 또는 둘 다를 포함해야 합니다. 예를 들어 다음 공용 I/O 제어 코드 IOCTL_DISK_SET_PARTITION_INFO 정의는 호출자에게 읽기 및 쓰기 액세스 권한이 모두 있는 경우에만 이 I/O 요청을 드라이버로 보낼 수 있음을 보여 줍니다.

#define IOCTL_DISK_SET_PARTITION_INFO\
        CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
        FILE_READ_DATA | FILE_WRITE_DATA)

참고

새 IOCTL 코드에 대한 FILE_ANY_ACCESS 지정하기 전에 디바이스에 대한 무제한 액세스를 허용해도 악의적인 사용자가 시스템을 손상할 수 있는 경로가 만들어지지 않는다는 것을 절대적으로 확신할 수 있어야 합니다.

드라이버는 IoValidateDeviceIoControlAccess 를 사용하여 IOCTL의 RequiredAccess 비트에서 제공하는 것보다 더 엄격한 액세스 검사를 수행할 수 있습니다.

기타 유용한 매크로

다음 매크로는 IOCTL 코드에서 16비 트 DeviceType 및 2비 트 TransferType 필드를 추출하는 데 유용합니다.

#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode)   (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode)        ((ULONG)(ctrlCode & 3))

이러한 매크로는 Wdm.h 및 Ntddk.h에 정의되어 있습니다.