Поделиться через


Определение кодов элементов управления ввода-вывода

В этой статье описывается создание уникального кода элемента управления ввода-вывода (IOCTL). IoCTLs может быть следующим:

  • Общедоступные IOCTLs, которые обычно задаются системой и документируются корпорацией Майкрософт.
  • Частные IOCTLs, которые обычно предназначены исключительно для использования компонентами программного обеспечения поставщика для обмена данными друг с другом. Они обычно определяются в файле заголовка поставщика и не документируются корпорацией Майкрософт.

Макет IOCTL

IOCTL — это 32-разрядное значение, состоящее из нескольких полей. На следующем рисунке показан битовый макет IOCTL:

Схема, иллюстрирующая побитовый макет 32-разрядного кода элемента управления ввода-вывода.

Каждое поле в IOCTL имеет определенное назначение, как описано в следующей таблице:

Поле Биты в IOCTL Описание
Общий 31 Поставщики должны задать этот бит, если они используют назначенное поставщиком значение для DeviceType.
DeviceType 16-30 Определяет тип устройства. Это значение должно соответствовать значению, заданному в элементе DeviceTypeDEVICE_OBJECT структуры драйвера . Поставщики должны использовать значение от 32768 до 65535 (0x8000 до 0xffff) и должны задать бит Common. Значения от 0 до 32767 (0x0000 по 0x7fff) зарезервированы для Корпорации Майкрософт. Дополнительные сведения см. в разделе Указание типов устройств.
Открыть 14-15 Указывает тип доступа, который вызывающий объект должен запрашивать при открытии объекта файла, представляющего устройство (см. IRP_MJ_CREATE). Диспетчер ввода-вывода создаст irps и вызовет драйвер с определенным IOCTL только в том случае, если вызывающий запрос запрашивал указанные права доступа. Это поле указывается с помощью следующих системных констант: FILE_ANY_ACCESS, FILE_READ_DATA и FILE_WRITE_DATA.
Настройка 13 (тринадцать) Если задано, указывает, что IOCTL является определяемым поставщиком IOCTL.
Функция 2-12 Уникальный код драйвера, идентифицирующий функцию, которую он выполняет. Для созданного поставщиком IOCTL используйте значение в диапазоне от 2048 до 4095 (от 0x800 до 0xfff) и установите настраиваемый бит. Значения менее 2048 (0x000 по 0x7ff) зарезервированы для Корпорации Майкрософт.
Метод 0-1 Указывает, как система передает данные между вызывающим объектом DeviceIoControl (или IoBuildDeviceIoControlRequest) и драйвером, обрабатывающим IRP. Дополнительные сведения см. в руководстве по настройке битов метода.

Макрос для определения кодов элементов управления ввода-вывода

Используйте предоставленный системой макрос CTL_CODE для определения новых кодов управления ввода-вывода. Этот макрос определен в devioctl.h следующим образом:

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

Описание DeviceType, Function, Method и Access см. в предыдущем разделе.

При определении новых кодов управления ввода-вывода следует учитывать следующие правила:

  • Если новый IOCTL станет доступным для пользовательских программных компонентов, его следует использовать с запросами IRP_MJ_DEVICE_CONTROL. Компоненты пользовательского режима вызывают DeviceIoControl для отправки IRP_MJ_DEVICE_CONTROL запросов.

  • Если новый IOCTL будет доступен только для компонентов драйвера в режиме ядра, он должен использоваться с запросами IRP_MJ_INTERNAL_DEVICE_CONTROL . Компоненты режима ядра могут создавать запросы IRP_MJ_INTERNAL_DEVICE_CONTROL путем вызова IoBuildDeviceIoControlRequest. Дополнительные сведения см. в создании запросов IOCTL в драйверах.

Определение нового кода IOCTL, предназначенного для использования с запросами IRP_MJ_DEVICE_CONTROL или IRP_MJ_INTERNAL_DEVICE_CONTROL, использует следующий формат:

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

Выберите описательное имя константы для IOCTL формы IOCTL_Device_Function, где устройство указывает тип устройства и функции указывает операцию. Например, системная константа IOCTL_VIDEO_ENABLE_CURSOR использует "VIDEO" для устройства и "ENABLE_CURSOR" для функции.

Руководство по настройке битов Access

При определении нового IOCTL необходимо выбрать значение для битового поля Access , указывающее тип доступа, который вызывающий объект должен запрашивать при открытии объекта файла, представляющего устройство. Диспетчер ввода-вывода создаст IRPs и вызовет драйвер с определенным IOCTL только в том случае, если вызывающий запросил указанные права доступа.

Доступ задается с помощью следующих системных констант:

  • FILE_ANY_ACCESS

    Диспетчер ввода-вывода отправляет IRP для любого вызывающего объекта, имеющего дескриптор, в объект файла, представляющий целевой объект устройства. Перед указанием FILE_ANY_ACCESS для нового кода IOCTL необходимо быть абсолютно уверены, что разрешение неограниченного доступа к вашему устройству не создает возможный путь для злоумышленников, чтобы скомпрометировать систему.

  • ЧТЕНИЕ_ДАННЫХ_ФАЙЛА

    Диспетчер ввода-вывода отправляет IRP только вызывающему объекту с правами доступа на чтение, что позволяет базовому драйверу устройства передавать данные с устройства в системную память.

  • Запись данных в файл

    Диспетчер ввода-вывода отправляет IRP только вызывающему объекту с правами доступа на запись, что позволяет базовому драйверу устройства передавать данные из системной памяти на свое устройство.

FILE_READ_DATA и FILE_WRITE_DATA могут быть объединены, если вызывающий должен иметь права доступа на чтение и запись.

Некоторые системные коды управления ввода-вывода имеют значение Access FILE_ANY_ACCESS, что позволяет вызывающему объекту отправлять определенный IOCTL независимо от доступа, предоставленного устройству. К примерам относятся коды управления ввода-вывода, которые отправляются драйверам эксклюзивных устройств.

Другие системные коды управления ввода-вывода требуют, чтобы вызывающий объект имеет права доступа на чтение, права доступа на запись или оба. Например, следующее определение общедоступного IOCTL_DISK_SET_PARTITION_INFO IOCTL показывает, что этот запрос ввода-вывода может быть отправлен драйверу только в том случае, если вызывающий объект имеет права доступа на чтение и запись:

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

Драйверы могут использовать IoValidateDeviceIoControlAccess для выполнения более строгой проверки доступа, чем предусмотрено в битах Доступа IOCTL.

Руководство по настройке битов метода

При определении нового IOCTL необходимо выбрать значение битового поля метода, указывающее, как система должна передавать данные между вызывающим объектом DeviceIoControl (или IoBuildDeviceIoControlRequest) и драйвером, обрабатывающим IRP.

Используйте одну из следующих системных констант, чтобы задать поле метода .

Другие полезные макросы

Следующие макросы полезны для извлечения 16-разрядных полей DeviceType и 2-разрядных методов из IOCTL.

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

Эти макросы определены в Wdm.h и Ntddk.h.