Condividi tramite


Accesso ai buffer di dati nei driver WDF (KMDF o UMDF)

Quando un driver di Windows Driver Frameworks (WDF) riceve una richiesta di lettura, scrittura o controllo di I/O del dispositivo, l'oggetto della richiesta contiene un buffer di input, un buffer di output o entrambi.

I buffer di input contengono informazioni necessarie al driver. Per le richieste di scrittura, queste informazioni sono in genere dati che un driver di funzione deve inviare a un dispositivo. Per le richieste di controllo di I/O del dispositivo, un buffer di input potrebbe contenere informazioni che indicano il tipo di operazione che il driver deve eseguire.

I buffer di output ricevono informazioni dal driver. Per le richieste di lettura, queste informazioni sono in genere dati che un driver di funzione riceve da un dispositivo. Per le richieste di controllo di I/O del dispositivo, un buffer di output potrebbe ricevere lo stato o altre informazioni specificate dal codice di controllo di I/O della richiesta.

La tecnica usata dal driver per accedere ai buffer di dati di una richiesta dipende dal metodo del driver per accedere ai buffer di dati per un dispositivo. Esistono tre metodi di accesso:

  • di I/O memorizzati nel buffer. Il gestore I/O crea buffer intermedi che condivide con il driver.
  • I/O diretto. Gestione I/O blocca lo spazio del buffer nella memoria fisica e quindi fornisce al driver l'accesso diretto allo spazio buffer.
  • Né bufferizzato né I/O diretto. Gestione I/O fornisce al driver gli indirizzi virtuali dello spazio buffer della richiesta. Gestione I/O non convalida lo spazio buffer della richiesta, quindi il driver deve verificare che lo spazio del buffer sia accessibile e bloccare lo spazio del buffer nella memoria fisica.

Un driver Kernel-Mode Driver Framework (KMDF) può usare uno dei tre metodi di accesso. Un driver User-Mode Driver Framework (UMDF) può usare l'I/O memorizzato nel buffer o diretto per le richieste di lettura, scrittura e IOCTL e può convertire le richieste che specificano il metodo METHOD_NEITHER.

Specificare il Metodo di Accesso al Buffer

Driver KMDF

Per le richieste di lettura e scrittura, tutti i driver in uno stack di driver devono usare lo stesso metodo per accedere ai buffer di un dispositivo, ad eccezione del driver di livello più alto, che può usare il metodo "nessuno dei due", indipendentemente dal metodo usato dai driver inferiori.

A partire dalla versione 1.13, un driver KMDF specifica il metodo di accesso per tutte le richieste di lettura e scrittura di un dispositivo chiamando WdfDeviceInitSetIoTypeEx per ogni dispositivo. Ad esempio, se un driver specifica il metodo di I/O memorizzato nel buffer per uno dei relativi dispositivi, il gestore di I/O usa il metodo di I/O memorizzato nel buffer durante il recapito di richieste di lettura e scrittura al driver per tale dispositivo.

Per le richieste di controllo I/O del dispositivo, il codice di controllo I/O (IOCTL) contiene bit che specificano il metodo di accesso al buffer. Di conseguenza, un driver KMDF non deve eseguire alcuna azione per selezionare un metodo di buffering per IOCTLs. Per altre informazioni sui codici IOCTL, vedere Definizione di codici di controllo I/O. A differenza delle richieste di lettura e scrittura, tutti gli IOCTLs di un dispositivo non devono specificare lo stesso metodo di accesso.

driver UMDF

Un driver UMDF specifica preferenze per il metodo di accesso usato dal framework per le richieste di lettura e scrittura, nonché per le richieste di controllo di I/O del dispositivo. I valori forniti da un driver UMDF sono solo preferenze e non sono garantiti che vengano usati dal framework. Per altre informazioni, vedere Gestione dei metodi di accesso al buffer nei driver UMDF.

Un driver UMDF specifica il metodo di accesso per tutte le richieste di lettura, scrittura e IOCTL di un dispositivo chiamando WdfDeviceInitSetIoTypeEx per ogni dispositivo. Ad esempio, se un driver specifica il metodo di I/O memorizzato nel buffer per uno dei relativi dispositivi, il framework usa il metodo di I/O memorizzato nel buffer durante il recapito di richieste di lettura, scrittura e IOCTL al driver per tale dispositivo.

Si noti la differenza nella tecnica di accesso al buffer per IOCTLs tra KMDF e UMDF. I driver KMDF non specificano il metodo di accesso al buffer per IOCTLs, mentre i driver UMDF specificano il metodo di accesso al buffer per IOCTLs.

Se un driver WDF descrive il buffer di una richiesta di I/O usando una tecnica non corretta per il metodo di I/O usato da una destinazione di I/O, il framework corregge la descrizione del buffer. Ad esempio, se un driver utilizza un MDL per descrivere un buffer che viene passato a WdfIoTargetSendReadSynchronously, e se la destinazione di I/O utilizza I/O memorizzato nel buffer (che richiede che i buffer vengano specificati usando indirizzi virtuali anziché MDL), il framework converte la descrizione del buffer da un MDL a un indirizzo virtuale e una lunghezza. Tuttavia, è più efficiente se il driver specifica i buffer nel formato corretto.

Per informazioni sugli oggetti di memoria del framework, gli elenchi lookaside, gli elenchi MDL e i buffer locali, vedere Using Memory Buffers.

Per informazioni sull'eliminazione dei buffer di memoria, vedere ciclo di vita del buffer di memoria.

l'accesso ai buffer di dati per le operazioni di I/O memorizzate nel buffer

Se il driver usa l'I/O memorizzato nel buffer, il comportamento cambia a seconda del tipo di richiesta di dati e se usa KMDF o UMDF.

driver KMDF

Quando un driver KMDF usa operazioni di I/O memorizzate nel buffer, il gestore di I/O crea un buffer intermedio a cui il driver può accedere per ogni tipo di richiesta. Di seguito è illustrato ciò che accade:

  • Scrivere richieste. Il gestore I/O trasferisce i dati di input dal buffer di input dell'app chiamante prima di chiamare lo stack di driver. Il driver KMDF legge quindi le informazioni di input dal buffer intermedio e lo scrive nel dispositivo.
  • Leggere le richieste. Il driver KMDF legge le informazioni dal dispositivo e lo archivia nel buffer intermedio. Quindi, il gestore di I/O copia i dati di output dal buffer intermedio nel buffer di output dell'app.
  • Richieste di controllo di I/O del dispositivo. Il driver KMDF legge o scrive i dati per tale richiesta da o verso il buffer intermedio.

driver UMDF

Quando un driver UMDF usa l'I/O memorizzato nel buffer, il processo host del driver crea uno o due buffer intermedi, a seconda del tipo di richiesta. Di seguito è illustrato ciò che accade:

  • Scrivere richieste. Il framework crea un buffer, trasferisce le informazioni di input dal buffer di input dell'app chiamante e quindi chiama lo stack di driver. Il driver UMDF legge le informazioni di input dal buffer intermedio e lo scrive nel dispositivo.
  • Leggi le richieste. Un driver UMDF legge informazioni da un dispositivo e lo archivia in un buffer creato dal framework. Il processo host del driver copia i dati di output dal buffer intermedio nel buffer di output dell'app.
  • Richieste di controllo di I/O del dispositivo. Il framework crea due buffer corrispondenti ai buffer di input e output dell'IOCTL a cui il driver può accedere. Il framework copia le informazioni di input dall'IOCTL nel nuovo buffer intermedio e lo rende disponibile per il driver. Il framework non copia il contenuto del buffer di output, quindi il driver non dovrebbe tentare di leggerlo (altrimenti finirà per leggere dati spazzatura). Tutti i dati scritti dal driver nel buffer di output vengono copiati nuovamente nel buffer IOCTL originale e vengono restituiti all'app al completamento della richiesta di I/O. Si noti che tutti i dati scritti dal driver nel buffer di input vengono eliminati e non restituiti all'app chiamante.

Per recuperare un handle in un oggetto memoria framework che rappresenta il buffer, i driver KMDF e UMDF chiamano WdfRequestRetrieveInputMemory o WdfRequestRetrieveOutputMemory, a seconda che si tratti di una richiesta di lettura o scrittura. Il driver può quindi recuperare un puntatore al buffer chiamando WdfMemoryGetBuffer. Per leggere e scrivere il buffer, il driver chiama WdfMemoryCopyFromBuffer o WdfMemoryCopyToBuffer.

Per recuperare l'indirizzo virtuale e la lunghezza del buffer, il driver chiama WdfRequestRetrieveInputBuffer o WdfRequestRetrieveOutputBuffer.

Per allocare e compilare un elenco di descrittori di memoria (MDL) per il buffer, un driver KMDF chiama WdfRequestRetrieveInputWdmMdl o WdfRequestRetrieveOutputWdmMdl.

Accesso ai buffer di dati per I/O diretto

driver KMDF

Se il driver usa l'I/O diretto, il gestore di I/O verifica l'accessibilità dello spazio buffer specificato dall'origine della richiesta di I/O (in genere un'applicazione in modalità utente), blocca lo spazio del buffer nella memoria fisica e quindi fornisce al driver l'accesso diretto allo spazio del buffer.

driver UMDF

Se il driver ha specificato una preferenza per l'I/O diretto e tutti i requisiti UMDF per i/O diretti sono stati soddisfatti (vedere Gestione dei metodi di accesso al buffer nei driver UMDF), il framework esegue il mapping del buffer di memoria ricevuto dal gestore di I/O direttamente nello spazio indirizzi del processo host del driver e fornisce quindi al driver l'accesso diretto allo spazio del buffer.

Per recuperare un handle per un oggetto di memoria del framework che rappresenta lo spazio del buffer, il driver chiama WdfRequestRetrieveInputMemory o WdfRequestRetrieveOutputMemory. Il driver può quindi recuperare un puntatore al buffer chiamando WdfMemoryGetBuffer. Per leggere e scrivere il buffer, il driver chiama WdfMemoryCopyFromBuffer o WdfMemoryCopyToBuffer.

Per recuperare l'indirizzo virtuale e la lunghezza dello spazio del buffer, il driver chiama WdfRequestRetrieveInputBuffer o WdfRequestRetrieveOutputBuffer.

Se i driver di un dispositivo usano i/O diretti, il gestore di I/O descrive i buffer tramite MDLs. Per recuperare un puntatore al file MDL di un buffer, un driver KMDF chiama WdfRequestRetrieveInputWdmMdl o WdfRequestRetrieveOutputWdmdl. Un driver UMDF non può accedere agli MDL.

Accesso ai buffer di dati per I/O né bufferizzato né diretto

driver KMDF

Se il driver usa il metodo di accesso al buffer conosciuto come , metodo di I/O né memorizzato nel buffer né diretto (o, il metodo "né l'uno né l'altro", per brevità), il gestore I/O fornisce al driver gli indirizzi virtuali specificati dall'origine della richiesta di I/O per lo spazio buffer della richiesta. Gestione I/O non convalida lo spazio buffer della richiesta di I/O, pertanto il driver deve verificare che lo spazio del buffer sia accessibile e bloccare lo spazio del buffer nella memoria fisica.

È possibile accedere agli indirizzi virtuali forniti dal gestore di I/O solo nel contesto del processo dell'origine della richiesta di I/O. Solo il driver di livello più alto nello stack di driver è garantito che venga eseguito nel contesto del processo dell'origine.

Per ottenere l'accesso allo spazio buffer di una richiesta di I/O, il driver di livello più alto deve fornire una funzione di callback EvtIoInCallerContext. Il framework chiama questa funzione di callback ogni volta che riceve una richiesta di I/O per il driver.

Se il metodo di accesso al buffer di una richiesta non è "nessuno dei due", un driver KMDF deve eseguire le operazioni seguenti per ogni buffer:

  1. Chiamare WdfRequestRetrieveUnsafeUserInputBuffer o WdfRequestRetrieveUnsafeUserOutputBuffer per ottenere l'indirizzo virtuale del buffer.

  2. Chiamare WdfRequestProbeAndLockUserBufferForRead o WdfRequestProbeAndLockUserBufferForWrite per eseguire il probe e bloccare il buffer e ottenere un handle per un oggetto di memoria del framework relativo al buffer.

  3. Salvare gli handle dell'oggetto memoria nello spazio di contesto della richiesta.

  4. Chiamare WdfDeviceEnqueueRequest, restituendo così la richiesta al framework.

Il framework aggiunge successivamente la richiesta a una delle code di I/O del driver. Se il driver ha fornito gestori di richieste, il framework chiamerà infine il gestore della richiesta appropriato.

Il gestore della richiesta può recuperare gli handle di memoria della richiesta dallo spazio di contesto della richiesta. Il driver può passare gli handler a WdfMemoryGetBuffer per ottenere l'indirizzo del buffer.

In alcuni casi, un driver di livello più alto deve usare i passaggi precedenti per accedere a un buffer in modalità utente, anche se il driver non usa il metodo di accesso "nessuno dei due". Si supponga, ad esempio, che il driver usi l'I/O memorizzato nel buffer. Un codice di controllo di I/O che usa il metodo di accesso memorizzato nel buffer potrebbe passare una struttura contenente un puntatore incorporato a un buffer in modalità utente. In tal caso, il driver deve fornire una EvtIoInCallerContext funzione di callback che estrae i puntatori dalla struttura e quindi usa i passaggi precedenti da 2 a 4.

driver UMDF

UMDF non supporta né i buffer di tipo I/O memorizzato né quelli di tipo I/O diretto, quindi un driver UMDF non deve mai gestire direttamente questo tipo di buffer.

Tuttavia, se il framework riceve tali buffer per la lettura o la scrittura dal gestore di I/O, li rende disponibili per un driver UMDF come I/O memorizzato nel buffer o I/O diretto, a seconda del metodo di accesso selezionato dal driver. Se il framework riceve un IOCTL che specifica il metodo di buffer "nessuno dei due", può facoltativamente convertire il metodo di accesso al buffer della richiesta IOCTL in I/O con buffer o I/O diretto, in base alla presenza di una direttiva INF. Per altre informazioni, vedere Gestione dei metodi di accesso al buffer nei driver UMDF.