Partilhar via


Definição de códigos de controle de E/S

Este artigo descreve como criar um código de controle de E/S exclusivo (IOCTL). IOCTLs podem ser:

  • IOCTLs públicas, que normalmente são definidas pelo sistema e documentadas pela Microsoft.
  • IOCTLs privadas, que normalmente se destinam a ser usadas exclusivamente pelos componentes de software de um fornecedor para se comunicarem entre si. Eles geralmente são definidos no arquivo de cabeçalho de um fornecedor e não são documentados pela Microsoft.

IOCTL layout

Um IOCTL é um valor de 32 bits que consiste em vários campos. A figura a seguir ilustra o layout ao nível de bits de um IOCTL.

Diagrama ilustrando o layout bit a bit de um código de controle de E/S de 32 bits.

Cada campo na IOCTL tem uma finalidade específica, conforme descrito na tabela a seguir:

Campo Bits em IOCTL Descrição
Comum 31 Os fornecedores devem definir esse bit quando usam um valor atribuído pelo fornecedor para DeviceType.
Tipo de dispositivo 16-30 Identifica o tipo de dispositivo. Esse valor deve corresponder ao valor definido no membro DeviceType da estrutura DEVICE_OBJECT do driver. Os fornecedores devem usar um valor de 32768 a 65535 (0x8000 a 0xffff) e devem definir o bit Comum . Os valores de 0 a 32767 (0x0000 a 0x7fff) estão reservados para a Microsoft. Para obter mais informações, consulte Especificando tipos de dispositivo.
Acesso 14-15 Indica o tipo de acesso que um chamador deve solicitar ao abrir o objeto de arquivo que representa o dispositivo (consulte IRP_MJ_CREATE). O gestor de E/S criará IRPs e chamará o driver com IOCTL específica somente se o chamador solicitar os direitos de acesso especificados. Este campo é especificado usando as seguintes constantes definidas pelo sistema: FILE_ANY_ACCESS, FILE_READ_DATA e FILE_WRITE_DATA.
Personalizado 13 Quando definido, indica que o IOCTL é um IOCTL definido pelo fornecedor.
Função 2-12 Código exclusivo para o driver que identifica a função que ele deve executar. Para um IOCTL criado pelo fornecedor, use um valor de 2048 a 4095 (0x800 a 0xfff) e defina o bit personalizado . Valores inferiores a 2048 (0x000 a 0x7ff) estão reservados para a Microsoft.
Método 0-1 Indica como o sistema deve passar dados entre o chamador de DeviceIoControl (ou IoBuildDeviceIoControlRequest) e o driver que manipula o IRP. Para obter mais informações, consulte Orientação para definir os bits do método.

Macro para definir códigos de controle de E/S

Use a macro CTL_CODE fornecida pelo sistema para definir novos códigos de controle de E/S. Esta macro é definida em devioctl.h da seguinte forma:

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

Consulte a seção anterior para obter uma descrição de DeviceType, Function, Method e Access.

Tenha em mente as seguintes regras ao definir novos códigos de controle de E/S:

A definição de um novo código IOCTL, seja destinado a ser utilizado com os pedidos IRP_MJ_DEVICE_CONTROL ou IRP_MJ_INTERNAL_DEVICE_CONTROL, utiliza o seguinte formato:

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

Escolha um nome constante descritivo para o IOCTL, do formato IOCTL_Device_Function, onde Device indica o tipo de dispositivo e Function indica a operação. Por exemplo, a constante de IOCTL_VIDEO_ENABLE_CURSOR fornecida pelo sistema usa "VIDEO" para Dispositivo e "ENABLE_CURSOR" para Função.

Orientação para definir os bits de acesso

Ao definir um novo IOCTL, você deve escolher um valor para o campo Bit de acesso que indique o tipo de acesso que um chamador deve solicitar ao abrir o objeto de arquivo que representa o dispositivo. O gestor de E/S criará IRPs e chamará o driver com uma IOCTL específica somente se o chamador tiver solicitado os direitos de acesso especificados.

O acesso é especificado usando as seguintes constantes definidas pelo sistema:

  • FILE_ANY_ACCESS

    O gerenciador de E/S envia o IRP para qualquer chamador que tenha um identificador para o objeto de arquivo que representa o objeto de dispositivo de destino. Antes de especificar FILE_ANY_ACCESS para um novo código IOCTL, você deve ter certeza absoluta de que permitir acesso irrestrito ao seu dispositivo não cria um caminho possível para usuários mal-intencionados comprometerem o sistema.

  • Leitura_de_Dados_de_Ficheiro (FILE_READ_DATA)

    O gerenciador de E/S envia o IRP apenas para um chamador com direitos de acesso de leitura, permitindo que o driver de dispositivo subjacente transfira dados do dispositivo para a memória do sistema.

  • ESCREVER_DADOS_FICHEIRO

    O gerenciador de E/S envia o IRP apenas para um chamador com direitos de acesso de gravação, permitindo que o driver de dispositivo subjacente transfira dados da memória do sistema para seu dispositivo.

FILE_READ_DATA e FILE_WRITE_DATA podem ser combinados com OR quando o chamador deve ter direitos de acesso tanto de leitura quanto de gravação.

Alguns códigos de controle de E/S definidos pelo sistema têm um valor de acesso de FILE_ANY_ACCESS, que permite que o chamador envie a IOCTL específica, independentemente do acesso concedido ao dispositivo. Exemplos incluem códigos de controlo de E/S que são enviados aos drivers de dispositivos exclusivos.

Outros códigos de controle de E/S definidos pelo sistema exigem que o chamador tenha direitos de acesso de leitura, direitos de acesso de gravação ou ambos. Por exemplo, a seguinte definição do IOCTL público IOCTL_DISK_SET_PARTITION_INFO mostra que esta solicitação de E/S pode ser enviada a um controlador apenas se o chamador tiver direitos de acesso tanto de leitura como de escrita:

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

Os drivers podem usar IoValidateDeviceIoControlAccess para executar uma verificação de acesso mais rigorosa do que a fornecida pelos bits de acesso de um IOCTL.

Orientação para definir os bits do método

Ao definir um novo IOCTL, você deve escolher um valor para o campo de bit Method que indica como o sistema deve passar dados entre o chamador de DeviceIoControl (ou IoBuildDeviceIoControlRequest) e o driver que manipula o IRP.

Use uma das seguintes constantes definidas pelo sistema para definir o campo Método .

  • Método com Buffer

    Especifica o método de E/S em buffer , que normalmente é usado para transferir pequenas quantidades de dados por solicitação. A maioria dos códigos de controle de E/S para dispositivos e drivers intermediários usam esse valor.

    Para obter informações sobre como o sistema especifica buffers de dados para códigos de controle de E/S METHOD_BUFFERED, consulte Descrições de buffer para códigos de controle de E/S.

    Para obter mais informações sobre E/S em buffer, consulte Usando E/S em buffer.

  • METHOD_IN_DIRECT ou METHOD_OUT_DIRECT

    Especifica o método de E/S direta , que normalmente é usado para ler ou gravar grandes quantidades de dados usando DMA ou PIO que devem ser transferidos rapidamente.

    • Especifique METHOD_IN_DIRECT se o chamador de DeviceIoControl ou IoBuildDeviceIoControlRequest passará dados para o driver.

    • Especifique METHOD_OUT_DIRECT se o chamador de DeviceIoControl ou IoBuildDeviceIoControlRequest receberá dados do driver.

    Para obter informações sobre como o sistema especifica buffers de dados para códigos de controle de E/S METHOD_IN_DIRECT e METHOD_OUT_DIRECT, consulte Descrições de buffer para códigos de controle de E/S.

    Para obter mais informações sobre E/S direta, consulte Usando E/S direta.

  • METHOD_NEITHER

    Especifica que o método de E/S não é armazenado em buffer ou direto. O gestor de E/S não fornece buffers de sistema ou MDLs. O IRP fornece os endereços virtuais de modo de usuário dos buffers de entrada e saída que foram especificados para DeviceIoControl ou IoBuildDeviceIoControlRequest, sem validá-los ou mapeá-los.

    Para obter informações sobre como o sistema especifica buffers de dados para códigos de controle de E/S METHOD_NEITHER, consulte Descrições de buffer para códigos de controle de E/S.

    Esse método pode ser usado somente se o driver estiver garantido para ser executado no contexto do thread que originou a solicitação de controle de E/S. Apenas um driver de modo kernel de nível mais alto é garantido para atender a essa condição, portanto, METHOD_NEITHER raramente é usado para IOCTLs que são passados para drivers de dispositivo de baixo nível.

    Com este método, o controlador de nível mais alto:

    • Deve determinar se deve configurar o acesso em buffer ou direto aos dados do usuário no recebimento da solicitação.
    • Pode ser necessário bloquear o buffer do utilizador.
    • Deve encapsular seu acesso ao buffer do usuário em um manipulador de exceção estruturado (consulte Manipulando exceções).

    Caso contrário, o chamador de modo de usuário de origem pode alterar os dados armazenados em buffer antes que o driver possa usá-los, ou o chamador pode ser substituído no momento em que o driver está acessando o buffer do usuário.

    Para obter mais informações, consulte Usar sem buffer nem E/S direta.

Outras macros úteis

As macros a seguir são úteis para extrair os campos DeviceType de 16 bits e Método de 2 bits de um IOCTL.

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

Essas macros são definidas em Wdm.h e Ntddk.h.