Udostępnij przez


Definiowanie kodów kontrolek we/wy

W tym artykule opisano sposób tworzenia unikatowego kodu sterującego wejścia/wyjścia (IOCTL). Listy IOCTL mogą być następujące:

  • Publiczne IOCTL-e, które są zwykle definiowane przez system i udokumentowane przez firmę Microsoft.
  • Prywatne IOCTL, które zwykle są używane wyłącznie przez składniki oprogramowania producenta do wzajemnej komunikacji. Są one zwykle definiowane w pliku nagłówkowym dostawcy i nie są udokumentowane przez firmę Microsoft.

Układ IOCTL

IOCTL to wartość 32-bitowa, która składa się z kilku pól. Na poniższej ilustracji przedstawiono układ bitowy IOCTL:

Diagram przedstawiający układ bitowy 32-bitowego kodu sterującego we/wy.

Każde pole w IOCTL ma określony cel, zgodnie z opisem w poniższej tabeli:

(No changes needed) Bity w IOCTL Opis
common 31 Dostawcy muszą ustawić ten bit, gdy używają wartości przypisanej przez dostawcę dla parametru DeviceType.
Typ urządzenia 16-30 Określa typ urządzenia. Ta wartość musi być zgodna z wartością ustawioną w elemencie DeviceType struktury DEVICE_OBJECT sterownika. Dostawcy powinni użyć wartości z zakresu od 32768 do 65535 (0x8000 do 0xffff) i powinni ustawić bit Common. Wartości od 0 do 32767 (0x0000 za pośrednictwem 0x7fff) są zarezerwowane dla firmy Microsoft. Aby uzyskać więcej informacji, zobacz Określanie typów urządzeń.
Uzyskaj dostęp 14-15 Wskazuje typ dostępu, którego obiekt wywołujący musi zażądać podczas otwierania obiektu pliku reprezentującego urządzenie (zobacz IRP_MJ_CREATE). Menedżer we/wy utworzy IRPs i wywoła sterownik z określonym kodem IOCTL tylko wtedy, gdy wywołujący zażądał określonych praw dostępu. To pole jest określane przy użyciu następujących stałych zdefiniowanych przez system: FILE_ANY_ACCESS, FILE_READ_DATA i FILE_WRITE_DATA.
Niestandardowe Rozwiązanie 13 Po ustawieniu wskazuje, że IOCTL jest IOCTL określonym przez dostawcę.
Funkcja 2-12 Unikatowy kod sterownika identyfikujący funkcję, którą należy wykonać. W przypadku identyfikatora IOCTL utworzonego przez dostawcę użyj wartości od 2048 do 4095 (0x800 do 0xfff) i ustaw bit Niestandardowy. Wartości niższe niż 2048 (0x000 do 0x7ff) są zarezerwowane dla firmy Microsoft.
Metoda 0-1 Wskazuje, w jaki sposób system przekazuje dane między obiektem wywołującym deviceIoControl (lub IoBuildDeviceIoControlRequest) i sterownikiem obsługującym protokół IRP. Aby uzyskać więcej informacji, zobacz Wskazówki dotyczące ustawiania bitów metody.

Makro służące do definiowania kodów kontrolek we/wy

Użyj makra CTL_CODE dostarczonego przez system, aby zdefiniować nowe kody kontrolek we/wy. To makro jest zdefiniowane w pliku devioctl.h w następujący sposób:

#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

Zapoznaj się z poprzednią sekcją, aby zapoznać się z opisem typu urządzenia, funkcji, metody i dostępu.

Podczas definiowania nowych kodów kontrolek we/wy należy pamiętać o następujących regułach:

Definicja nowego kodu IOCTL, niezależnie od tego, czy jest przeznaczona do użytku z żądaniami IRP_MJ_DEVICE_CONTROL czy IRP_MJ_INTERNAL_DEVICE_CONTROL , używa następującego formatu:

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

Wybierz opisową nazwę stałej dla IOCTL formularza IOCTL_Device_Function, gdzie urządzenie wskazuje typ urządzenia i funkcja wskazuje operację. Na przykład stała dostarczana przez system IOCTL_VIDEO_ENABLE_CURSOR używa wartości "VIDEO" dla urządzenia i "ENABLE_CURSOR" dla funkcji.

Wskazówki dotyczące ustawiania bitów dostępu

Podczas definiowania nowego IOCTL należy wybrać wartość pola bitowego Access, która wskazuje typ dostępu, jakiego interfejs musi zażądać podczas otwierania obiektu pliku reprezentującego urządzenie. Menedżer we/wy utworzy IRPs i wywoła sterownik z określonym poleceniem IOCTL tylko wtedy, gdy wywołujący zażądał określonych praw dostępu.

Dostęp jest określany przy użyciu następujących stałych zdefiniowanych przez system:

  • DOWOLNY_DOSTĘP_DO_PLIKU

    Menedżer we/wy wysyła protokół IRP dla każdego obiektu wywołującego, który ma uchwyt do obiektu pliku, który reprezentuje obiekt urządzenia docelowego. Przed określeniem FILE_ANY_ACCESS dla nowego kodu IOCTL należy mieć absolutną pewność, że zezwolenie na nieograniczony dostęp do urządzenia nie tworzy możliwej ścieżki dla złośliwych użytkowników w celu naruszenia bezpieczeństwa systemu.

  • FILE_READ_DATA

    Menedżer we/wy wysyła IRP tylko podmiotom z prawami dostępu do odczytu, umożliwiając podstawowemu sterownikowi urządzenia przesyłanie danych z urządzenia do pamięci systemowej.

  • FILE_WRITE_DATA

    Menedżer we/wy wysyła IRP tylko dla podmiotu wywołującego z prawami dostępu do zapisu, co umożliwia podstawowemu sterownikowi urządzenia przesyłanie danych z pamięci systemowej do urządzenia.

FILE_READ_DATA i FILE_WRITE_DATA mogą być połączone za pomocą operatora OR, jeżeli obiekt wywołujący musi mieć prawa dostępu do odczytu i zapisu.

Niektóre kody kontroli we/wy zdefiniowane przez system mają wartość Dostępu FILE_ANY_ACCESS, która umożliwia wywołującemu wysyłanie konkretnego IOCTL bez względu na przyznany dostęp do urządzenia. Przykłady obejmują kody kontrolek we/wy wysyłane do sterowników urządzeń wyłącznych.

Inne kody kontroli we/wy zdefiniowane przez system wymagają, aby obiekt wywołujący miał prawa dostępu do odczytu, prawa dostępu do zapisu lub oba te elementy. Na przykład następująca definicja publicznego IOCTL_DISK_SET_PARTITION_INFO IOCTL pokazuje, że to żądanie I/O można wysłać do sterownika tylko wtedy, gdy dzwoniący ma prawa dostępu zarówno do odczytu, jak i zapisu:

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

Sterowniki mogą używać funkcji IoValidateDeviceIoControlAccess do przeprowadzania bardziej rygorystycznego sprawdzania dostępu niż zapewniane przez bity dostępu IOCTL.

Wskazówki dotyczące ustawiania bitów metody

Podczas definiowania nowego IOCTL należy wybrać wartość dla pola bitowego metody, która wskazuje, jak system przesyła dane między wywołującym DeviceIoControl (lub IoBuildDeviceIoControlRequest) a sterownikiem obsługującym IRP.

Użyj jednej z następujących stałych zdefiniowanych przez system, aby ustawić pole Metoda .

  • METODA_BUFOROWANA

    Określa buforowaną metodę I/O, która jest typowo używana do przesyłania małych ilości danych na każde żądanie. Większość kodów kontroli wejścia/wyjścia dla sterowników urządzeń i sterowników pośrednich używa tej wartości.

    Aby uzyskać informacje na temat sposobu, w jaki system określa bufory danych dla kodów sterowania I/O METHOD_BUFFERED, zobacz Opisy buforów dla kodów sterowania I/O.

    Aby uzyskać więcej informacji na temat buforowanych operacji we/wy, zobacz Using Buffered I/O (Używanie buforowanych operacji we/wy).

  • METHOD_IN_DIRECT lub METHOD_OUT_DIRECT

    Określa metodę we/wy bezpośrednią , która jest zwykle używana do odczytywania lub zapisywania dużych ilości danych przy użyciu dmA lub PIO, które muszą być szybko przesyłane.

    • Określ METHOD_IN_DIRECT, jeśli obiekt wywołujący deviceIoControl lub IoBuildDeviceIoControlRequest przekaże dane do sterownika.

    • Określ METHOD_OUT_DIRECT, jeśli obiekt wywołujący deviceIoControl lub IoBuildDeviceIoControlRequest otrzyma dane ze sterownika.

    Aby uzyskać informacje na temat sposobu, w jaki system określa bufory danych dla kodów sterowania I/O METHOD_IN_DIRECT i METHOD_OUT_DIRECT, zobacz Opisy buforów dla kodów sterowania I/O.

    Aby uzyskać więcej informacji na temat bezpośredniego I/O, zobacz Używanie bezpośredniego I/O.

  • METODA_BRAK

    Określa, że metoda We/Wy nie jest ani buforowana, ani bezpośrednia. Menedżer we/wy nie udostępnia żadnych buforów systemowych ani MDL. IRP dostarcza wirtualne adresy trybu użytkownika dla buforów wejściowych i wyjściowych, które zostały określone dla DeviceIoControl lub IoBuildDeviceIoControlRequest, bez weryfikacji lub mapowania tych adresów.

    Aby uzyskać informacje na temat sposobu, w jaki system określa bufory danych dla kodów sterowania we/wy METHOD_NEITHER, zobacz w Opisach buforów dla kodów sterowania we/wy.

    Tej metody można użyć tylko wtedy, gdy jest zagwarantowane, że sterownik działa w kontekście wątku, który zainicjował żądanie sterowania we/wy. Tylko sterownik trybu jądra najwyższego poziomu ma gwarancję spełnienia tego warunku, więc METHOD_NEITHER jest rzadko używany dla IOCTLs, które są przekazywane do sterowników urządzeń niskiego poziomu.

    Za pomocą tej metody sterownik najwyższego poziomu:

    • Należy określić, czy skonfigurować buforowany, czy bezpośredni dostęp do danych użytkownika po otrzymaniu żądania.
    • Być może musi zablokować bufor użytkownika.
    • Musi opakowować dostęp do buforu użytkownika w programie obsługi wyjątków ustrukturyzowanych (zobacz Obsługa wyjątków).

    W przeciwnym razie wywołujący w trybie użytkownika może zmienić buforowane dane, zanim sterownik będzie mógł je używać, lub obiekt wywołujący może zostać przełączony w momencie, gdy sterownik uzyskuje dostęp do bufora użytkownika.

    Aby uzyskać więcej informacji, zobacz Używanie ani buforowanych, ani bezpośrednich operacji we/wy.

Inne przydatne makra

Poniższe makra są przydatne do wyodrębniania 16-bitowych pól DeviceType i 2-bitowej metody z biblioteki IOCTL.

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

Te makra są definiowane w plikach Wdm.h i Ntddk.h.