Routine StartIo nei driver di Lowest-Level
La chiamata del gestore I/O alla routine di invio di un driver è la prima fase per soddisfare una richiesta di I/O del dispositivo. La routine StartIo è la seconda fase. Ogni driver di dispositivo con una routine StartIo è probabile che chiami IoStartPacket dalle routine DispatchRead e DispatchWrite e in genere per un subset dei codici di controllo I/O supportati nella routine DispatchDeviceControl . La routine IoStartPacket aggiunge l'IRP alla coda del dispositivo fornita dal dispositivo o, se la coda è vuota, chiama immediatamente la routine StartIo del driver per elaborare l'IRP.
Si supponga che quando viene chiamata la routine StartIo di un driver, il dispositivo di destinazione non è occupato. Questo perché il gestore I/O chiama StartIo in due circostanze; una delle routine di invio del driver ha appena chiamato IoStartPacket e la coda del dispositivo è vuota o la routine DpcForIsr del driver sta completando un'altra richiesta e ha appena chiamato IoStartNextPacket per dequeuere l'IRP successivo.
Prima di chiamare la routine StartIo in un driver di dispositivo di livello più alto, la routine di invio del driver deve essere stata sottoposto a probe e bloccato il buffer utente, se necessario, per configurare gli indirizzi del buffer mappati validi nella routine StartIo . Se un driver di dispositivo di livello superiore configura gli oggetti del dispositivo per i/O diretti (o per i driver di I/O diretti o buffer), il driver non può rinviare il blocco di un buffer utente alla routine StartIo ; ogni routine StartIo viene chiamata in un contesto di thread arbitrario in IRQL = DISPATCH_LEVEL.
Nota
Qualsiasi memoria buffer a cui accedere tramite la routine StartIo di un driver deve essere bloccata o allocata da memoria residente, spazio di sistema e deve essere accessibile in un contesto di thread arbitrario.
In generale, qualsiasi routine StartIo del driver di dispositivo di livello inferiore è responsabile della chiamata a IoGetCurrentIrpStackLocation con l'IRP di input e quindi all'esecuzione di qualsiasi elaborazione specifica della richiesta per avviare l'operazione di I/O nel dispositivo. L'elaborazione specifica della richiesta può includere quanto segue:
Configurazione o aggiornamento di informazioni sullo stato sulla richiesta corrente gestita dal driver. Le informazioni sullo stato potrebbero essere archiviate nell'estensione del dispositivo di destinazione dell'oggetto dispositivo di destinazione o altrove nel pool non a pagina allocato dal driver.
Ad esempio, se un driver di dispositivo gestisce un booleano interruptExpected per l'operazione di trasferimento corrente, la routine StartIo potrebbe impostare questa variabile su TRUE. Se il driver gestisce un contatore di timeout per l'operazione corrente, la routine StartIo potrebbe configurare questo valore oppure la routine StartIo potrebbe accodarsi alla routine CustomTimerDpc del driver.
Se la routine StartIo condivide l'accesso alle informazioni sullo stato o alle risorse hardware con altre routine driver, le informazioni sullo stato o la risorsa devono essere protette da un blocco di rotazione. Vedere Blocchi di spin.)
Se la routine StartIo condivide l'accesso alle informazioni sullo stato o alle risorse con la routine InterruptService del driver, StartIo deve usare KeSynchronizeExecution per chiamare una routine SynchCritSection che accede allo stato o alle informazioni sulla risorsa. Vedere Uso di sezioni critiche.
Assegnazione di un numero di sequenza all'IRP nel caso in cui il driver registri un errore di I/O del dispositivo durante l'elaborazione dell'IRP.
Per altre informazioni, vedere Errori di registrazione .
Se necessario, tradurre i parametri nella posizione dello stack I/O del driver in valori specifici del dispositivo.
Ad esempio, un driver del disco potrebbe dover calcolare il settore iniziale o l'offset di byte all'indirizzo del disco fisico per un'operazione di trasferimento e se la lunghezza richiesta del trasferimento supera un determinato limite di settore o supera la capacità di trasferimento del dispositivo fisico.
Se il driver controlla un dispositivo multimediale rimovibile, verificando le modifiche dei supporti prima di programmare il dispositivo per I/O e notificando il file system overlying se il supporto è cambiato.
Per altre informazioni, vedere Supporto di supporti rimovibili.
Se il dispositivo usa DMA, verificare se la lunghezza richiesta (numero di byte da trasferire, trovata nella posizione dello stack I/O del driver dell'IRP) deve essere suddivisa in operazioni di trasferimento parziale, come illustrato in Tecniche di input/output, presupponendo che un driver di livello superiore strettamente abbinato non presplififi i trasferimenti di grandi dimensioni per il driver di dispositivo.
La routine StartIo di tale driver di dispositivo può anche essere responsabile della chiamata di KeFlushIoBuffers e, se il driver usa DMA basato su pacchetti, per chiamare AllocateAdapterChannel con la routine AdapterControl del driver.
Per altri dettagli, vedere Oggetti adapter e DMA eGestione della coherency della cache.
Se il dispositivo usa PIO, mapping dell'indirizzo virtuale di base del buffer, descritto nell'IRP in Irp-MdlAddress>, a un indirizzo dello spazio di sistema con MmGetSystemAddressForMdlSafe.
Per le richieste di lettura, la routine StartIo del driver di dispositivo può essere responsabile della chiamata a KeFlushIoBuffers prima dell'avvio delle operazioni PIO. Per altre informazioni, vedere Gestione della coherency della cache .
Se un driver non WDM usa un oggetto controller, chiamando IoAllocateController per registrare la routine ControllerControl .
Se il driver gestisce i provider di integrazione annullabili, verifica se l'IRP di input è già stato annullato.
Se un'IRP di input può essere annullata prima del completamento dell'elaborazione, la routine StartIo deve chiamare IoSetCancelRoutine con IRP e il punto di ingresso della routine Annulla del driver. La routine StartIo deve acquisire il blocco di spin annulla per la chiamata a IoSetCancelRoutine. In alternativa, un driver può usare IoSetStartIoAttributes per impostare l'attributo NonCancelable per la routine StartIo su TRUE. Ciò impedisce al sistema di tentare di annullare un'IRP passata a StartIo tramite una chiamata a IoStartPacket.
Come regola generale, un driver che usa l'I/O con buffer ha una routine StartIo più semplice di quella che usa l'I/O diretta. I driver che usano l'I/O memorizzato nel buffer trasferiscono piccole quantità di dati per ogni richiesta di trasferimento, mentre quelli che usano i/O diretti (sia DMA che PIO) trasferiscono grandi quantità di dati a o da buffer bloccati che possono estendersi sui limiti di pagina fisici nella memoria di sistema.
I driver di livello superiore hanno in genere configurato i driver di dispositivo fisici in modo che corrispondano a quelli dei rispettivi driver di dispositivo. Tuttavia, un driver di livello più alto, in particolare un driver di file system, può configurare oggetti dispositivo per né i/O diretti né con buffer.
I driver che configurano gli oggetti del dispositivo per I/O memorizzati nel buffer possono basarsi sul gestore di I/O per passare buffer validi in tutti gli indirizzi IP inviati al driver. I driver di livello inferiore che configurano gli oggetti dispositivo per I/O diretti possono basarsi sul driver di livello più alto della catena per passare buffer validi in tutti i provider di sicurezza inviati tramite qualsiasi driver intermedio al driver di dispositivo inferiore sottostante.
Uso di I/O memorizzati nel buffer nelle routine StartIo
Se la routine DispatchRead, DispatchWrite o DispatchDeviceControl di un driver determina che una richiesta è valida e chiama IoStartPacket, il gestore I/O chiama la routine StartIo del driver per elaborare immediatamente l'IRP se la coda del dispositivo è vuota. Se la coda non è vuota, IoStartPacket accoda l'IRP . Alla fine, una chiamata a IoStartNextPacket dalla routine DpcForIsr o CustomDpc causa la dequeue routine di I/O e chiama la routine StartIo del driver.
La routine StartIo chiama IoGetCurrentIrpStackLocation e determina quale operazione deve essere eseguita per soddisfare la richiesta. Pre-elabora l'IRP in qualsiasi modo necessario prima di programmare il dispositivo fisico per eseguire la richiesta di I/O.
Se l'accesso al dispositivo fisico (o all'estensione del dispositivo) deve essere sincronizzato con una routine InterruptService , la routine StartIo deve chiamare una routine SynchCritSection per eseguire la programmazione del dispositivo necessaria. Per altre informazioni, vedere Uso di sezioni critiche.
Un driver di dispositivo fisico che usa i dati di I/O memorizzati nel buffer memorizzato nel buffer dello spazio di sistema, allocato dal gestore di I/O, che il driver trova in ogni IRP-AssociatedIrp.SystemBuffer>.
Uso di I/O diretto nelle routine StartIo
Se la routine DispatchRead, DispatchWrite o DispatchDeviceControl di un driver determina che una richiesta è valida e chiama IoStartPacket, il gestore I/O chiama la routine StartIo del driver per elaborare immediatamente l'IRP se la coda del dispositivo è vuota. Se la coda non è vuota, IoStartPacket accoda l'IRP . Alla fine, una chiamata a IoStartNextPacket dalla routine DpcForIsr o CustomDpc causa la dequeue routine di I/O e chiama la routine StartIo del driver.
La routine StartIo chiama IoGetCurrentIrpStackLocation e determina quale operazione deve essere eseguita per soddisfare la richiesta. Pre-elabora l'IRP in qualsiasi modo necessario, ad esempio suddividendo una richiesta di trasferimento DMA di grandi dimensioni in intervalli di trasferimento parziale e salvando lo stato relativo alla lunghezza di una richiesta di trasferimento in ingresso che deve essere divisa. Programma quindi il dispositivo fisico per eseguire la richiesta di I/O.
Se l'accesso al dispositivo fisico (o all'estensione del dispositivo) deve essere sincronizzato con l'ISR del driver, la routine StartIo deve usare una routine SynchCritSection fornita dal driver per eseguire la programmazione necessaria. Per altre informazioni, vedere Uso di sezioni critiche.
Qualsiasi driver che usa l'I/O diretto legge i dati in o scrive dati da un buffer bloccato, descritto da un elenco MDL (Memory Descriptor), che il driver trova nell'IRP-MdlAddress>. Tale driver usa comunemente l'I/O memorizzato nel buffer per le richieste di controllo del dispositivo. Per altre informazioni, vedere Gestione delle richieste di controllo I/O nelle routine StartIo.
Il tipo MDL è un tipo opaco che i driver non accedono direttamente. I driver che usano invece buffer di spazio utente mappati con PIO chiamando MmGetSystemAddressForMdlSafe con Irp-MdlAddress> come parametro. I driver che usano DMA passano anche Irp-MdlAddress> per supportare le routine durante le operazioni di trasferimento per avere gli indirizzi del buffer riapplicati agli intervalli logici per i dispositivi.
A meno che un driver di livello superiore sia strettamente associato suddivide le richieste di trasferimento DMA di grandi dimensioni per il driver di dispositivo sottostante, una routine StartIo del driver di dispositivo di livello più basso deve suddividere ogni richiesta di trasferimento più grande del relativo dispositivo può gestire in un'unica operazione di trasferimento. I driver che usano DMA di sistema sono necessari per suddividere le richieste di trasferimento troppo grandi per il controller DMA di sistema o per i dispositivi da gestire in una singola operazione di trasferimento.
Se il dispositivo è un dispositivo DMA subordinato, il driver deve sincronizzare i trasferimenti tramite un controller DMA di sistema con un oggetto adapter allocato dal driver, che rappresenta il canale DMA e una routine AdapterControl fornita dal driver. Il driver di un dispositivo DMA master del bus deve usare anche un oggetto adapter allocato dal driver per sincronizzarne i trasferimenti e deve fornire una routine AdapterControl se usa il supporto DMA basato sul pacchetto del sistema o una routine AdapterListControl se usa il supporto di dispersione/raccolta del sistema.
A seconda della progettazione del driver, potrebbe sincronizzare le operazioni di trasferimento e controllo del dispositivo in un dispositivo fisico con un oggetto controller e fornire una routine ControllerControl .
Per altre informazioni, vedere Oggetti adapter e oggetti DMA e Controller .
Gestione delle richieste di controllo I/O nelle routine StartIo
In generale, solo un subset di richieste di controllo I/O del dispositivo viene passato dalla routine DispatchDeviceControl o DispatchInternalDeviceControl di un driver per un'ulteriore elaborazione dalla routine StartIo del driver. La routine StartIo del driver deve gestire solo le richieste di controllo del dispositivo valide che richiedono modifiche dello stato del dispositivo o restituire informazioni volatili sullo stato del dispositivo corrente.
Ogni nuovo driver deve supportare lo stesso set di codici di controllo I/O pubblici di tutti gli altri driver per lo stesso tipo di dispositivo. Il sistema definisce codici di controllo I/O pubblici e specifici del tipo di dispositivo per le richieste di IRP_MJ_DEVICE_CONTROL come richieste memorizzate nel buffer.
Di conseguenza, i driver di dispositivo fisici effettuano trasferimenti di dati verso o da un buffer dello spazio di sistema che ogni driver trova nell'IRP-AssociatedIrp.SystemBuffer> per le richieste di controllo del dispositivo. Anche i driver che configurano gli oggetti dispositivo per l'I/O diretto usano i/O con buffer per soddisfare le richieste di controllo del dispositivo con codici di controllo I/O pubblici.
La definizione di ogni codice di controllo I/O determina se i dati trasferiti per tale richiesta vengono memorizzati nel buffer. Tutti i codici di controllo I/O definiti privatamente per le richieste di IRP_MJ_INTERNAL_DEVICE_CONTROL specifiche del driver tra i driver associati possono definire un codice con buffer di metodi, metodo diretto o metodo nessuno dei due. Come regola generale, qualsiasi codice di controllo I/O definito privatamente deve essere definito con il metodo né se un driver di livello superiore strettamente abbinato deve allocare un buffer per tale richiesta.
Programmazione del dispositivo per operazioni di I/O
In genere, la routine StartIo in un driver di dispositivo di livello più basso deve sincronizzare l'accesso a qualsiasi memoria o dispositivo lo registra con l'ISR del driver usando KeSynchronizeExecution per chiamare una routine SynchCritSection fornita dal driver. La routine StartIo del driver usa la routine SynchCritSection per programmare effettivamente il dispositivo fisico per I/O in DIRQL. Per altre informazioni, vedere Uso di sezioni critiche.
Prima di chiamare KeSynchronizeExecution, la routine StartIo deve eseguire qualsiasi pre-elaborazione necessaria per la richiesta. Il pre-elaborazione può includere il calcolo di un intervallo di trasferimento parziale iniziale e il salvataggio di informazioni sullo stato sulla richiesta originale per altre routine del driver.
Se un driver di dispositivo usa DMA, la routine StartIo chiama in genere AllocateAdapterChannel con una routine AdapterControl fornita dal driver. In queste circostanze, la routine StartIo rinvia la responsabilità della programmazione del dispositivo fisico alla routine AdapterControl . A sua volta, può chiamare KeSynchronizeExecution per avere un programma di routine SynchCritSection fornito dal driver per il dispositivo per un trasferimento DMA.