Estensioni del dispositivo

Per la maggior parte dei driver intermedi e di livello più basso, l'estensione del dispositivo è la struttura dei dati più importante associata a un oggetto dispositivo. La struttura interna è definita dal driver e viene in genere usata per:

  • Mantenere le informazioni sullo stato del dispositivo.

  • Fornire spazio di archiviazione per qualsiasi oggetto definito dal kernel o altre risorse di sistema, ad esempio blocchi di selezione, usati dal driver.

  • Conservare tutti i dati che il driver deve avere residente e nello spazio di sistema per eseguire le operazioni di I/O.

Poiché la maggior parte dei driver di bus, funzione e filtro (driver di livello più basso e intermedio) viene eseguita in un contesto di thread arbitrario (quello di qualsiasi thread sia aggiornato), un'estensione del dispositivo è la posizione principale di ogni driver per mantenere lo stato del dispositivo e tutti gli altri dati specifici del dispositivo necessari per il driver. Ad esempio, qualsiasi driver che implementa una routine CustomTimerDpc o CustomDpc fornisce in genere spazio di archiviazione per gli oggetti timer e/o DPC definiti dal kernel necessari in un'estensione del dispositivo.

Ogni driver che dispone di un ISR deve fornire spazio di archiviazione per un puntatore a un set di oggetti interrupt definiti dal kernel e la maggior parte dei driver di dispositivo archivia questo puntatore in un'estensione del dispositivo. Ogni driver determina le dimensioni dell'estensione del dispositivo quando crea un oggetto dispositivo e ogni driver definisce il contenuto e la struttura delle proprie estensioni del dispositivo.

Le routine IoCreateDevice e IoCreateDeviceSecure di I/O manager allocano memoria per l'oggetto dispositivo e l'estensione dal pool di memoria non di paging.

Ogni routine del driver standard che riceve un IRP riceve anche un puntatore a un oggetto dispositivo che rappresenta il dispositivo di destinazione per l'operazione di I/O richiesta. Queste routine driver possono accedere all'estensione del dispositivo corrispondente tramite questo puntatore. In genere, un puntatore DeviceObject è anche un parametro di input per l'ISR di un driver di livello più basso.

La figura seguente mostra un set rappresentativo di dati definiti dal driver per l'estensione del dispositivo di un oggetto dispositivo del driver di livello più basso. Un driver di livello superiore non fornisce spazio di archiviazione per un puntatore a oggetti interrupt restituito da IoConnectInterrupt e passato a KeSynchronizeExecution e IoDisconnectInterrupt. Tuttavia, un driver di livello superiore fornisce spazio di archiviazione per gli oggetti timer e DPC illustrati nella figura seguente se il driver ha una routine CustomTimerDpc . Un driver di livello superiore può anche fornire spazio di archiviazione per un blocco spin esecutivo e una coda di lavoro interlocked.

diagramma che illustra un'estensione del dispositivo di esempio per un driver di livello più basso.

Oltre a fornire spazio di archiviazione per un puntatore a un oggetto interrupt, un driver di dispositivo di livello più basso deve fornire spazio di archiviazione per un blocco di spin di interruzione se il relativo ISR gestisce gli interrupt per due o più dispositivi su vettori diversi o se ha più isr. Per altre informazioni sulla registrazione di un ISR, vedere Registrazione di un ISR.

In genere, i driver archiviano puntatori ai relativi oggetti dispositivo nelle estensioni del dispositivo, come illustrato nella figura. Un driver potrebbe anche mantenere una copia dell'elenco di risorse per il dispositivo nell'estensione.

Un driver di livello superiore archivia in genere un puntatore all'oggetto dispositivo del driver inferiore successivo nell'estensione del dispositivo. Un driver di livello superiore deve passare un puntatore all'oggetto dispositivo del driver inferiore successivo a IoCallDriver, dopo aver configurato la posizione dello stack I/O del driver inferiore successivo in un IRP, come illustrato in Gestione dei runtime di integrazione.

Si noti anche che qualsiasi driver di livello superiore che alloca i runtime di integrazione per i driver di livello inferiore deve specificare il numero di posizioni dello stack che devono essere presenti nei nuovi runtime di integrazione. In particolare, se un driver di livello superiore chiama IoMakeAssociatedIrp, IoAllocateIrp o IoInitializeIrp, deve accedere all'oggetto dispositivo di destinazione del driver di livello inferiore successivo per leggere il relativo valore StackSize , per fornire stackSize corretto come argomento a queste routine di supporto.

Anche se un driver di livello superiore può leggere i dati dall'oggetto dispositivo del driver di livello inferiore successivo tramite il puntatore restituito da IoAttachDeviceToDeviceStack, tale driver deve seguire queste linee guida di implementazione:

  • Non tentare mai di scrivere dati nell'oggetto dispositivo del driver inferiore.

    Le uniche eccezioni a questa linea guida sono i file system, che impostano e cancellano DO_VERIFY_VOLUME nei flag degli oggetti dispositivo dei driver di supporti rimovibili di livello inferiore.

  • Non tentare mai di accedere all'estensione del dispositivo del driver inferiore per i motivi seguenti:

    • Non esiste un modo sicuro per sincronizzare l'accesso a una singola estensione del dispositivo tra due driver.

    • Una coppia di driver che implementano uno schema di comunicazione backdoor di questo tipo non può essere aggiornata singolarmente, non può avere un driver intermedio inserito tra di essi senza modificare l'origine driver esistente e non può essere ricompilato e spostato facilmente da una piattaforma Windows alla successiva.

Per mantenere l'interoperabilità con driver di livello inferiore da una piattaforma o una versione di Windows al successivo, i driver di livello superiore devono riutilizzare i runtime di integrazione forniti o devono creare nuovi provider di integrazione e devono usare IoCallDriver per comunicare le richieste ai driver di livello inferiore.