Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье описывается создание уникального кода элемента управления ввода-вывода (IOCTL). IoCTLs может быть следующим:
- Общедоступные IOCTLs, которые обычно задаются системой и документируются корпорацией Майкрософт.
- Частные IOCTLs, которые обычно предназначены исключительно для использования компонентами программного обеспечения поставщика для обмена данными друг с другом. Они обычно определяются в файле заголовка поставщика и не документируются корпорацией Майкрософт.
Макет IOCTL
IOCTL — это 32-разрядное значение, состоящее из нескольких полей. На следующем рисунке показан битовый макет IOCTL:
Каждое поле в 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.
Используйте одну из следующих системных констант, чтобы задать поле метода .
METHOD_BUFFERED
Задает буферный метод ввода-вывода , который обычно используется для передачи небольших объемов данных на запрос. Большинство кодов управления ввода-вывода для драйверов устройств и промежуточных драйверов используют это значение.
Сведения о том, как система задает буферы данных для кодов управления METHOD_BUFFERED ввода-вывода, см. в описаниях буферов для кодов управления ввода-вывода.
Дополнительные сведения об буферизованном ввод-выводе см. в разделе "Использование буферизованного ввода-вывода".
METHOD_IN_DIRECT или METHOD_OUT_DIRECT
Указывает прямой метод ввода-вывода , который обычно используется для чтения или записи больших объемов данных с помощью DMA или PIO, которые необходимо быстро передать.
Укажите METHOD_IN_DIRECT, если вызывающий объект DeviceIoControl или IoBuildDeviceIoControlRequest передает данные драйверу.
Укажите METHOD_OUT_DIRECT, если вызывающий объект DeviceIoControl или IoBuildDeviceIoControlRequest получит данные от драйвера.
Сведения о том, как система задает буферы данных для METHOD_IN_DIRECT и кодов управления METHOD_OUT_DIRECT ввода-вывода, см. в описаниях буферов для кодов управления ввода-вывода.
Дополнительные сведения об использовании прямых операций ввода-вывода см. в разделе "Использование прямого ввода-вывода".
МЕТОД_НИ ОДИН
Указывает , что метод ввода-вывода не буферичен или не является прямым. Диспетчер операций ввода-вывода не предоставляет системные буферы или списки дескрипторов памяти. IRP предоставляет виртуальные адреса в пользовательском режиме входных и выходных буферов, указанные DeviceIoControl или IoBuildDeviceIoControlRequest, не проверяя или не сопоставляя их.
Сведения о том, как система задает буферы данных для кодов управления METHOD_NEITHER ввода-вывода, см. в описаниях буферов для кодов управления ввода-вывода.
Этот метод можно использовать только в том случае, если драйвер гарантированно работает в контексте потока, созданного запросом на управление ввода-вывода. Только драйвер в режиме ядра высокого уровня гарантированно соответствует этому условию, поэтому METHOD_NEITHER редко используется для ioCTLs, передаваемых драйверам устройств низкого уровня.
С помощью этого метода драйвер верхнего уровня:
- Необходимо определить, следует ли настроить буферный или прямой доступ к данным пользователя при получении запроса.
- Возможно, необходимо заблокировать буфер пользователя.
- Должен упаковать доступ к буферу пользователя в структурированном обработчике исключений (см. раздел "Обработка исключений").
В противном случае вызывающий пользователь может изменить буферные данные, прежде чем драйвер сможет использовать его, или вызывающий объект может быть переключен так же, как драйвер обращается к буферу пользователя.
Дополнительные сведения см. в разделе "Использование ни буферизованного, ни прямого ввода-вывода".
Другие полезные макросы
Следующие макросы полезны для извлечения 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.