Definizione dei codici di controllo di I/O
Quando si definiscono nuovi IOCTLs, è importante ricordare le regole seguenti:
- Se un nuovo IOCTL sarà disponibile per i componenti software in modalità utente, l'IOCTL deve essere usato con IRP_MJ_DEVICE_CONTROL richieste. I componenti in modalità utente inviano richieste IRP_MJ_DEVICE_CONTROL chiamando DeviceIoControl, che è una funzione Win32.
- Se un nuovo IOCTL sarà disponibile solo per i componenti driver in modalità kernel, l'IOCTL deve essere usato con IRP_MJ_INTERNAL_DEVICE_CONTROL richieste. I componenti in modalità kernel creano richieste IRP_MJ_INTERNAL_DEVICE_CONTROL chiamando IoBuildDeviceIoControlRequest. Per altre informazioni, vedere Creazione di richieste IOCTL nei driver.
Un codice di controllo di I/O è un valore a 32 bit costituito da diversi campi. La figura seguente illustra il layout dei codici di controllo di I/O.
Usare la macro di CTL_CODE fornita dal sistema, definita in Wdm.h e Ntddk.h, per definire nuovi codici di controllo di I/O. La definizione di un nuovo codice IOCTL, destinato all'uso con richieste di IRP_MJ_DEVICE_CONTROL o di IRP_MJ_INTERNAL_DEVICE_CONTROL , usa il formato seguente:
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
Scegliere un nome di costante descrittivo per IOCTL, del modulo IOCTL_Device_Function, dove Device indica il tipo di dispositivo e Funzione indica l'operazione. Un nome costante di esempio è IOCTL_VIDEO_ENABLE_CURSOR.
Specificare i parametri seguenti alla macro CTL_CODE :
Devicetype
Identifica il tipo di dispositivo. Questo valore deve corrispondere al valore impostato nel membro DeviceType della struttura DEVICE_OBJECT del driver. Vedere Specifica dei tipi di dispositivo. I valori minori di 0x8000 sono riservati a Microsoft. I valori di 0x8000 e superiori possono essere usati dai fornitori. Si noti che i valori assegnati dal fornitore impostano il bit comune .
FunctionCode
Identifica la funzione da eseguire dal driver. I valori minori di 0x800 sono riservati a Microsoft. I valori di 0x800 e superiore possono essere usati dai fornitori. Si noti che i valori assegnati dal fornitore impostano il bit personalizzato .
TransferType
Indica come il sistema passerà i dati tra il chiamante di DeviceIoControl (o IoBuildDeviceIoControlRequest) e il driver che gestisce l'IRP.
Usare una delle costanti definite dal sistema seguenti:
METHOD_BUFFERED
Specifica il metodo di I/O memorizzato nel buffer , in genere usato per il trasferimento di piccole quantità di dati per richiesta. La maggior parte dei codici di controllo di I/O per i driver intermedi e di dispositivo usa questo valore TransferType .
Per informazioni su come il sistema specifica i buffer di dati per METHOD_BUFFERED codici di controllo di I/O, vedere Descrizioni del buffer per i codici di controllo di I/O.
Per altre informazioni sull'I/O memorizzato nel buffer, vedere Uso di I/O memorizzati nel buffer.
METHOD_IN_DIRECT o METHOD_OUT_DIRECT
Specifica il metodo di I/O diretto , in genere usato per la lettura o la scrittura di grandi quantità di dati, tramite DMA o PIO, che deve essere trasferito rapidamente.
Specificare METHOD_IN_DIRECT se il chiamante di DeviceIoControl o IoBuildDeviceIoControlRequest passerà i dati al driver.
Specificare METHOD_OUT_DIRECT se il chiamante di DeviceIoControl o IoBuildDeviceIoControlRequest riceverà i dati dal driver.
Per informazioni su come il sistema specifica i buffer di dati per METHOD_IN_DIRECT e METHOD_OUT_DIRECT codici di controllo di I/O, vedere Descrizioni del buffer per i codici di controllo di I/O.
Per altre informazioni sull'I/O diretto, vedere Uso di I/O diretto.
METHOD_NEITHER
Specifica né i/O memorizzati nel buffer né diretti. Il gestore di I/O non fornisce buffer di sistema o MDLs. L'IRP fornisce gli indirizzi virtuali in modalità utente dei buffer di input e output specificati per DeviceIoControl o IoBuildDeviceIoControlRequest, senza convalidarli o eseguirne il mapping.
Per informazioni su come il sistema specifica i buffer di dati per METHOD_NEITHER codici di controllo di I/O, vedere Descrizioni del buffer per i codici di controllo di I/O.
Questo metodo può essere usato solo se è possibile garantire che il driver sia in esecuzione nel contesto del thread che ha originato la richiesta di controllo di I/O. È garantito che solo un driver in modalità kernel di livello più alto soddisfi questa condizione, quindi METHOD_NEITHER viene usato raramente per i codici di controllo di I/O passati ai driver di dispositivo di basso livello.
Con questo metodo, il driver di livello più alto deve determinare se configurare l'accesso nel buffer o l'accesso diretto ai dati utente alla ricezione della richiesta, eventualmente deve bloccare il buffer utente e deve eseguirne il wrapping dell'accesso al buffer utente in un gestore di eccezioni strutturate (vedere Gestione delle eccezioni). In caso contrario, il chiamante in modalità utente di origine potrebbe modificare i dati memorizzati nel buffer prima che il driver possa usarlo oppure il chiamante potrebbe essere scambiato esattamente come il driver accede al buffer utente.
Per altre informazioni, vedere Uso né di I/O con buffering né diretto.
RequiredAccess
Indica il tipo di accesso che un chiamante deve richiedere all'apertura dell'oggetto file che rappresenta il dispositivo (vedere IRP_MJ_CREATE). Il gestore di I/O creerà i provider di integrazione e chiamerà il driver con un codice di controllo di I/O specifico solo se il chiamante ha richiesto i diritti di accesso specificati.
RequiredAccess viene specificato utilizzando le costanti definite dal sistema seguenti:
FILE_ANY_ACCESS
Il gestore di I/O invia l'IRP per qualsiasi chiamante con un handle all'oggetto file che rappresenta l'oggetto dispositivo di destinazione.
FILE_READ_DATA
Il gestore di I/O invia l'IRP solo per un chiamante con diritti di accesso in lettura, consentendo al driver di dispositivo sottostante di trasferire i dati dal dispositivo alla memoria di sistema.
FILE_WRITE_DATA
Il gestore di I/O invia l'IRP solo per un chiamante con diritti di accesso in scrittura, consentendo al driver di dispositivo sottostante di trasferire i dati dalla memoria di sistema al dispositivo.
FILE_READ_DATA e FILE_WRITE_DATA possono essere ORed insieme se il chiamante deve avere diritti di accesso in lettura e scrittura.
Alcuni codici di controllo I/O definiti dal sistema hanno un valore RequiredAccess di FILE_ANY_ACCESS, che consente al chiamante di inviare il codice IOCTL specifico indipendentemente dall'accesso concesso al dispositivo. Gli esempi includono i codici di controllo di I/O inviati ai driver di dispositivi esclusivi.
Altri codici di controllo di I/O definiti dal sistema richiedono al chiamante diritti di accesso in lettura, diritti di accesso in scrittura o entrambi. Ad esempio, la definizione seguente del codice di controllo di I/O pubblico IOCTL_DISK_SET_PARTITION_INFO mostra che questa richiesta di I/O può essere inviata a un driver solo se il chiamante ha diritti di accesso in lettura e scrittura:
#define IOCTL_DISK_SET_PARTITION_INFO\
CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
FILE_READ_DATA | FILE_WRITE_DATA)
Nota
Prima di specificare FILE_ANY_ACCESS per un nuovo codice IOCTL, è necessario essere assolutamente certi che consentire l'accesso senza restrizioni al dispositivo non crei un possibile percorso per gli utenti malintenzionati a compromettere il sistema.
I driver possono usare IoValidateDeviceIoControlAccess per eseguire un controllo di accesso più rigoroso rispetto a quello fornito dai bit RequiredAccess di un IOCTL.
Altre macro utili
Le macro seguenti sono utili per estrarre i campi DeviceType a 16 bit e TransferType a 2 bit da un codice IOCTL:
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3))
Queste macro sono definite in Wdm.h e Ntddk.h.