Condividi tramite


Estensioni del dispositivo

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

  • Gestire le informazioni sullo stato del dispositivo.

  • Fornire spazio di archiviazione per qualsiasi oggetto definito dal kernel o altre risorse di sistema, come i spin lock, utilizzati dal driver.

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

Poiché la maggior parte dei driver bus, funzione e filtro (driver di livello più basso e intermedio) viene eseguita in un contesto di thread arbitrario (quello del thread che si trova al momento attuale), un'estensione del dispositivo è il principale riferimento per 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 definiti dal kernel e/o DPC necessari in un'estensione del dispositivo.

Ogni driver con ISR deve fornire spazio di archiviazione per un puntatore a un set di oggetti di 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 del gestore I/O allocano memoria per l'oggetto dispositivo e l'estensione dal pool di memoria non paginata.

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 una serie rappresentativa di dati specificati dal driver per l'estensione dell'oggetto dispositivo del driver di livello più basso. Un driver di livello superiore non fornisce spazio di archiviazione per un puntatore a un oggetto interrupt restituito da IoConnectInterrupt e passato a KeSynchronizeExecution e IoDisconnectInterrupt. Tuttavia, un driver di livello superiore fornirà 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 di rotazione esecutivo e una coda di lavoro interbloccata.

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 al livello più basso deve fornire spazio di archiviazione per uno spinlock di interrupt se il suo ISR gestisce gli interrupt per due o più dispositivi su vettori diversi o se dispone di più ISR. Per altre informazioni sulla registrazione di un ISR, vedere Registrazione di un ISR.

In genere, i driver archiviano puntatori agli 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 in genere memorizza un puntatore all'oggetto dispositivo del driver di livello inferiore successivo nella sua 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 degli IRP.

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 avere i 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.

    L'unica eccezione 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 di livello 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 loro 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 i driver di livello inferiore da una piattaforma o versione Windows alla successiva, i driver di livello superiore devono riutilizzare i runtime di integrazione forniti o devono creare nuovi runtime di integrazione e devono usare IoCallDriver per comunicare le richieste ai driver di livello inferiore.