Proteggere le richieste digitali che usano le I/O estese
Le richieste Secure Digital (SD) che leggono o scrivono più di un paio di byte di dati devono usare un comando di I/O esteso (detto CMD53 nella specifica SD). Il comando di I/O esteso indica al driver del bus di trasmettere i dati sulle linee DAT della scheda SD. Le caratteristiche di un trasferimento dei dati dipendono dalle funzionalità del controller SD. Ad esempio, alcuni controller consentono solo operazioni di I/O programmabili (PIO); altri consentono l'accesso diretto alla memoria (DMA). Per garantire la massima compatibilità tra diversi tipi di controller SD, i driver di dispositivo devono caricare il pacchetto di richiesta con un puntatore a un MDL che descrive il buffer dei dati. Il driver di dispositivo deve costruire il proprio MDL, a meno che un driver in un livello superiore costruisca il file MDL e lo passi al driver di dispositivo.
L'esempio di codice seguente illustra come un driver potrebbe eseguire una richiesta di I/O estesa usando un buffer di dati descritto da un MDL. Questo esempio di codice è simile in formato all'esempio di codice I/O diretto descritto in richieste digitali sicure che usano l'I/O diretto, pertanto potrebbe essere utile studiare l'esempio di codice di I/O diretto prima di studiare l'esempio di codice di I/O esteso.
La differenza principale tra i due esempi è che l'esempio di codice di I/O esteso illustra come usare mdls con una richiesta SD. Esistono anche lievi differenze nel modo in cui i descrittori e i pacchetti di richiesta sono definiti per le I/O dirette e estese.
const SDCMD_DESCRIPTOR WriteIoExtendedDesc =
{SDCMD_IO_RW_EXTENDED, SDCC_STANDARD,
SDTD_WRITE, SDTT_SINGLE_BLOCK, SDRT_1};
// first, get an MDL to map the data. Call IoAllocateMdl to
// allocate an MDL and pass in a pointer to a buffer
// allocated from the non-paged pool.
mdl = IoAllocateMdl(Data, Length, FALSE, FALSE, NULL);
if (mdl == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool (mdl);
// next, allocate a request packet for the arguments of the command
sdrp = ExAllocatePool(NonPagedPool, sizeof(SDBUS_REQUEST_PACKET));
if (!sdrp) {
IoFreeMdl(mdl);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(sdrp, sizeof(SDBUS_REQUEST_PACKET));
sdrp->RequestFunction = SDRF_DEVICE_COMMAND;
sdrp->Parameters.DeviceCommand.CmdDesc =
WriteIoExtendedDesc;
// then, set up the argument and command descriptor
sdIoArgument.u.AsULONG = 0;
sdIoArgument.u.bits.Address = Offset;
// retrieve function number, the driver previously initialized
// this value with the SdBus GetProperty call
sdIoArgument.u.bits.Function = pDevExt->FunctionNumber;
sdIoArgument.u.bits.WriteToDevice = 1;
sdrp->Parameters.DeviceCommand.Argument =
sdIoArgument.u.AsULONG;
sdrp->Parameters.DeviceCommand.Mdl = mdl;
sdrp->Parameters.DeviceCommand.Length = Length;
// finally, submit the request
status = SdBusSubmitRequest(pDevExt->BusInterface.Context,sdrp);
IoFreeMdl(mdl);
ExFreePool(sdrp);
Questo esempio di codice include i passaggi seguenti:
Inizializzare il descrittore
Il primo passaggio per l'invio di una richiesta di comando del dispositivo consiste nel definire un descrittore di comando SD, SDCMD_DESCRIPTOR. Il descrittore nell'esempio di codice definisce un'operazione di scrittura di I/O estesa con gli elementi seguenti:
Elemento Descrizione L'operazione definita dal descrittore esegue una scrittura di I/O estesa, quindi il valore del codice del comando è SDCMD_IO_RW_DIRECT.
Le operazioni di scrittura di I/O estese appartengono al set di comandi standard (codici di comando da 0 a 63), quindi il valore assegnato a questo membro del descrittore è SDCC_STANDARD.
Le operazioni di scrittura richiedono un trasferimento dall'host al dispositivo, quindi il valore assegnato a questo membro del descrittore è SDTD_WRITE.
Il descrittore per un'operazione di scrittura di I/O estesa deve includere un tipo di trasferimento. L'esempio di codice specifica un singolo blocco di scrittura, SDTT_SINGLE_BLOCK, che indica che l'host scrive un blocco di dati nel dispositivo. Il driver ha stabilito le dimensioni di un blocco da un comando SET_BLOCKLEN precedente (non illustrato in questo esempio di codice). Per una spiegazione del comando SET_BLOCKLEN e del tipo di trasferimento SDTT_SINGLE_BLOCK, vedere specifica della scheda MultiMedia pubblicata dal comitato tecnico MMCA (MultiMedia Card Association).
Il descrittore specifica un tipo di risposta di SDRT_1, che specifica una risposta R1 standard al comando e contiene i dati sullo stato. Per una spiegazione della risposta R1, vedere la specifica dell'Associazione MultiMedia Card .
Configurare il MDL
Chiamare IoAllocateMdl per allocare un MDL e passare un puntatore a un buffer allocato nel pool di memoria non impaginato. Successivamente, la routine MmBuildMdlForNonPagedPool accetta il file MDL appena allocato che specifica un buffer di memoria virtuale nel pool non di paging e lo aggiorna per descrivere le pagine fisiche sottostanti. I chiamanti di MmBuildMdlForNonPagedPool devono essere in esecuzione in IRQL <= DISPATCH_LEVEL.
Inizializzare il pacchetto di richiesta completando i passaggi seguenti:
Definire la funzione richiesta:
Dopo aver creato un descrittore SD, l'esempio di codice inizializza il pacchetto di richiesta SDBUS_REQUEST_PACKET. Il RequestFunction membro del pacchetto di richiesta specifica se la richiesta contiene un comando del dispositivo (valore di SDRF_DEVICE_COMMAND) o un'operazione di proprietà (valore di SDRF_GET_PROPERTY o SDRF_SET_PROPERTY). L'esempio di codice invia un comando a un dispositivo, quindi imposta il membro RequestFunction su SDRF_DEVICE_COMMAND.
Caricare il descrittore di comando. L'esempio di codice archivia quindi il descrittore appena inizializzato nel Parameters.DeviceCommand.CmdDesc membro del pacchetto di richiesta.
inizializzare l'argomento di lettura/scrittura:
Il pacchetto di richiesta contiene una struttura SD_RW_DIRECT_ARGUMENT con la posizione in cui scrive il driver del bus. Questa struttura memorizza anche il numero della funzione da cui il driver del bus legge lo spazio di I/O. L'esempio di codice recupera il numero di funzione dall'estensione del dispositivo, che implica che il driver ha recuperato in precedenza queste informazioni dalla scheda (probabilmente quando ha avviato il dispositivo con una richiesta di SDRF_GET_PROPERTY e l'ha archiviata nell'estensione del dispositivo.
Invia la richiesta
Dopo aver inizializzato il descrittore e il pacchetto di richiesta, nell'esempio viene usata la routine di richiesta sincrona SdBusSubmitRequest per inviare la richiesta. Passa il pacchetto di richiesta e le informazioni sul contesto dell'interfaccia fornite dal sistema al driver all'apertura dell'interfaccia SD. Poiché si tratta di una richiesta sincrona, il driver deve essere in esecuzione in IRQL minore di DISPATCH_LEVEL.
risultati del comando
Poiché l'esempio di codice usa un comando di I/O diretto, nessun buffer di dati diverso dal campo ResponseData nel pacchetto di richiesta SD.
Nell'esempio di codice viene allocato un buffer di trasferimento dati da un pool non paginato. Un driver può usare PagedPool per un buffer di trasferimento dati, purché blocchi le pagine. Tuttavia, i driver devono sempre allocare buffer di trasferimento dati dal pool non paginato quando si eseguono richieste SDRF_GET_PROPERTY e SDRF_SET_PROPERTY. I driver devono allocare anche pacchetti di richiesta SD da un pool non di paginazione perché la routine di completamento dell'IRP che accompagna la richiesta SD potrebbe essere eseguita in una chiamata di procedura differita (DPC).
Per tutti i tipi di richieste, l'allocazione di buffer dal pool non di paging offre vantaggi in termini di prestazioni quando i buffer sono di piccole dimensioni e il driver li trattiene brevemente.