Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se describe cómo crear un código de control de E/S único (IOCTL). Los IOCTL pueden ser:
- Los IOCTLs públicos, que normalmente están definidos por el sistema y documentados por Microsoft.
- IOCTL privados, que suelen estar destinados para usarlos en exclusiva en los componentes de software de un proveedor para comunicarse entre sí. Normalmente se definen en el archivo de encabezado de un proveedor y Microsoft no los documenta.
Diseño de IOCTL
Un IOCTL es un valor de 32 bits que consta de varios campos. En la ilustración siguiente se muestra el diseño bit a bit de un IOCTL:
Cada campo del IOCTL tiene un propósito específico, como se describe en la tabla siguiente:
Campo | Bits en IOCTL | Descripción |
---|---|---|
Común | 31 | Los proveedores deben establecer este bit cuando usen un valor asignado por el proveedor para DeviceType. |
DeviceType | 16-30 | Identifica el tipo de dispositivo. Este valor debe coincidir con el valor establecido en el miembro DeviceType de la estructura DEVICE_OBJECT del controlador. Los proveedores deben usar un valor de 32768 a 65535 (0x8000 a 0xffff) y establecer el bit común. Los valores de 0 a 32767 (0x0000 a 0x7fff) están reservados para Microsoft. Para obtener más información, vea Especificar tipos de dispositivo. |
Acceso | 14-15 | Indica el tipo de acceso que un autor de llamada debe solicitar al abrir el objeto de archivo que representa el dispositivo (consulte IRP_MJ_CREATE). El administrador de E/S creará IRP y llamará al controlador con un IOCTL determinado únicamente si el autor de la llamada solicitó derechos de acceso especificados. Este campo se especifica mediante las siguientes constantes definidas por el sistema: FILE_ANY_ACCESS, FILE_READ_DATA y FILE_WRITE_DATA. |
Personalizada | 13 | Cuando se establece, indica que el IOCTL es un IOCTL definido por el proveedor. |
Función | 2-12 | Código único para el controlador que identifica la función que se va a realizar. Para un IOCTL creado por el proveedor, use un valor de 2048 a 4095 (0x800 a 0xfff) y establezca el bit Custom. Los valores inferiores a 2048 (0x000 a través de 0x7ff) están reservados para Microsoft. |
Método | 0-1 | Indica cómo el sistema debe pasar datos entre el autor de la llamada de DeviceIoControl (o IoBuildDeviceIoControlRequest) y el controlador que controla el IRP. Para obtener más información, vea Guía para establecer los bits de método. |
Macro para definir códigos de control de E/S
Use la macro CTL_CODE proporcionada por el sistema para definir nuevos códigos de control de E/S. Esta macro se define en devioctl.h como se indica a continuación:
#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)
Consulte la sección anterior para obtener una descripción de DeviceType, Function, Method y Access.
Tenga en cuenta las siguientes reglas al definir nuevos códigos de control de E/S:
Si un nuevo IOCTL estará disponible para los componentes de software en modo de usuario, debe usarse con solicitudes IRP_MJ_DEVICE_CONTROL. Los componentes de modo usuario llaman a DeviceIoControl para enviar solicitudes IRP_MJ_DEVICE_CONTROL.
Si un nuevo IOCTL estará disponible únicamente para los componentes del controlador en modo kernel, debe usarse con solicitudes IRP_MJ_INTERNAL_DEVICE_CONTROL. Los componentes en modo kernel pueden crear solicitudes de IRP_MJ_INTERNAL_DEVICE_CONTROL mediante una llamada a IoBuildDeviceIoControlRequest. Para obtener más información, vea Creación de solicitudes de IOCTL en controladores.
La definición de un nuevo código IOCTL, ya sea para solicitudes IRP_MJ_DEVICE_CONTROL o IRP_MJ_INTERNAL_DEVICE_CONTROL, usa el siguiente formato:
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
Elija un nombre de constante descriptivo para el IOCTL, del formulario IOCTL_Device_Function, donde Device indica el tipo de dispositivo y Function indica la operación. Por ejemplo, la constante IOCTL_VIDEO_ENABLE_CURSOR proporcionada por el sistema usa "VIDEO" para Device y "ENABLE_CURSOR" para Function.
Guía para establecer los bits de acceso
Al definir un nuevo IOCTL, debe elegir un valor para el campo de bits Access que indica el tipo de acceso que el llamador debe solicitar al abrir el archivo que representa al dispositivo. El administrador de E/S creará IRP y llamará al controlador con un IOCTL determinado únicamente si el autor de la llamada solicitó derechos de acceso especificados.
El acceso se especifica mediante las siguientes constantes definidas por el sistema:
FILE_ANY_ACCESS
El administrador de E/S envía el IRP para cualquier autor de llamada que tenga un controlador del objeto de archivo que representa el objeto del dispositivo de destino. Antes de especificar FILE_ANY_ACCESS para un nuevo código IOCTL, debe estar absolutamente seguro de que permitir el acceso sin restricciones al dispositivo no crea una posible ruta de acceso para que los usuarios malintencionados pongan en peligro el sistema.
LEER_DATOS_DE_ARCHIVO
El administrador de E/S envía el IRP solo para un autor de llamada con derechos de acceso de lectura, lo que permite al controlador de dispositivo subyacente transferir datos del dispositivo a la memoria del sistema.
ESCRIBIR_DATOS_EN_ARCHIVO
El administrador de E/S envía el IRP solo para un autor de la llamada con derechos de acceso de escritura, lo que permite al controlador de dispositivo subyacente transferir datos de la memoria del sistema a su dispositivo.
FILE_READ_DATA y FILE_WRITE_DATA pueden combinarse con OR si el autor de la llamada debe tener derechos de acceso tanto de lectura como de escritura.
Algunos códigos de control de E/S definidos por el sistema tienen un valor de acceso de FILE_ANY_ACCESS, lo que permite al autor de la llamada enviar el IOCTL determinado independientemente del acceso concedido al dispositivo. Algunos ejemplos son los códigos de control de E/S que se envían a los controladores de dispositivos exclusivos.
Otros códigos de control de E/S definidos por el sistema requieren que el autor de la llamada tenga derechos de acceso de lectura, derechos de acceso de escritura o ambos. Por ejemplo, la siguiente definición del IOCTL público IOCTL_DISK_SET_PARTITION_INFO muestra que esta solicitud de E/S se puede enviar a un controlador solo si el autor de la llamada tiene derechos de acceso de lectura y escritura:
#define IOCTL_DISK_SET_PARTITION_INFO\
CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
FILE_READ_DATA | FILE_WRITE_DATA)
Los controladores pueden usar IoValidateDeviceIoControlAccess para realizar comprobaciones de acceso más estrictas de las proporcionadas por los bits de acceso de un IOCTL.
Instrucciones para establecer los bits de método
Al definir un nuevo IOCTL, debe elegir un valor para el campo Bit de método que indica cómo el sistema debe pasar datos entre el autor de la llamada de DeviceIoControl (o IoBuildDeviceIoControlRequest) y el controlador que controla el IRP.
Use una de las siguientes constantes definidas por el sistema para establecer el campo Método .
MÉTODO_ALMOHADILLADO
Especifica el método de E/S con búfer, que normalmente se usa para transferir pequeñas cantidades de datos por solicitud. La mayoría de los códigos de control de E/S para los controladores intermedios y de dispositivo usan este valor.
Para obtener información sobre cómo el sistema especifica búferes de datos para METHOD_BUFFERED códigos de control de E/S, consulte Descripción del búfer para códigos de control de E/S.
Para obtener más información sobre la E/S almacenada en búfer, consulte Uso de la E/S almacenada en búfer.
METHOD_IN_DIRECT o METHOD_OUT_DIRECT
Especifica el método de E/S directo , que normalmente se usa para leer o escribir grandes cantidades de datos mediante DMA o PIO que se deben transferir rápidamente.
Especifique METHOD_IN_DIRECT si el autor de la llamada de DeviceIoControl o IoBuildDeviceIoControlRequest pasará los datos al controlador.
Especifique METHOD_OUT_DIRECT si el llamador de DeviceIoControl o IoBuildDeviceIoControlRequest recibirá datos del controlador.
Para obtener información sobre cómo el sistema especifica búferes de datos para METHOD_IN_DIRECT y códigos de control de E/S de METHOD_OUT_DIRECT, vea Descripción del búfer para códigos de control de E/S.
Para obtener más información sobre la E/S directa, consulte Uso de E/S directa.
METHOD_NEITHER
Especifica que el método es sin uso de búfer ni E/S directa. El administrador de E/S no proporciona ningún búfer del sistema ni MDL. IRP proporciona las direcciones virtuales en modo de usuario de los búferes de entrada y salida especificados en DeviceIoControl o IoBuildDeviceIoControlRequest, sin validarlos ni asignarlos.
Para obtener información sobre cómo el sistema especifica búferes de datos para METHOD_NEITHER códigos de control de E/S, consulte Descripción del búfer para códigos de control de E/S.
Este método solo se puede usar si se garantiza que el controlador se esté ejecutando en el contexto del subproceso que originó la solicitud de control de E/S. Solo se garantiza que un controlador en modo kernel de nivel más alto cumpla esta condición, por lo que METHOD_NEITHER rara vez se usa para IOCTL que se pasan a controladores de dispositivos de bajo nivel.
Con este método, el controlador de nivel superior:
- Debe determinar si se debe configurar el acceso directo o almacenado en búfer a los datos de usuario al recibir la solicitud.
- Posiblemente debe bloquear el búfer de usuario.
- Debe ajustar su acceso al búfer de usuario en un controlador de excepciones estructurado (consulte Control de excepciones).
De lo contrario, el autor de la llamada de origen en modo usuario podría cambiar los datos almacenados en búfer antes de que el controlador los use, o se podría intercambiar al autor de la llamada justo cuando el controlador esté accediendo al búfer de usuario.
Para obtener más información, consulte Sin uso de búfer ni E/S directa.
Otras macros útiles
Las macros siguientes son útiles para extraer los campos DeviceType de 16 bits y Método de 2 bits de un IOCTL.
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3))
Estas macros se definen en Wdm.h y Ntddk.h.