Condividi tramite


Proteggere le richieste digitali che usano l'I/O esteso

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 (denominato CMD53 nella specifica SD). Il comando I/O esteso indica al driver del bus di trasmettere i dati sulle linee DAT della scheda SD. Le caratteristiche di un trasferimento dati dipendono dalle funzionalità del controller SD. Ad esempio, alcuni controller consentono solo I/O programmabili (PIO); altri consentono l'accesso diretto alla memoria (DMA). Per 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 costrutti l'MDL e lo passi al driver del dispositivo.

Nell'esempio di codice seguente viene illustrato 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 al codice I/O diretto descritto in Richieste digitali sicure che usano I/O diretto, pertanto potrebbe essere utile studiare l'esempio di codice I/O diretto prima di studiare l'esempio di codice I/O esteso.

La differenza di principio tra i due esempi è che l'esempio di codice I/O esteso illustra come usare gli MDLs con una richiesta SD. Esistono anche differenze minime nel modo in cui i descrittori e i pacchetti di richiesta sono definiti per i pacchetti di I/O diretti e estesi.

    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:

  1. Inizializzare il descrittore

    Il primo passaggio nell'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

    SD_COMMAND_CODE

    L'operazione definita dal descrittore esegue una scrittura di I/O estesa, quindi il valore del codice di comando è SDCMD_IO_RW_DIRECT.

    SD_COMMAND_CLASS

    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.

    SD_TRANSFER_DIRECTION

    Le operazioni di scrittura richiedono un trasferimento dall'host al dispositivo, quindi il valore assegnato a questo membro del descrittore è SDTD_WRITE.

    SD_TRANSFER_TYPE

    Il descrittore per un'operazione di scrittura di I/O estesa deve includere un tipo di trasferimento. Nell'esempio di codice viene specificato 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 precedente SET_BLOCKLEN (non illustrato in questo esempio di codice). Per una spiegazione del comando SET_BLOCKLEN e del tipo di trasferimento SDTT_SINGLE_BLOCK, vedere La specifica multimedia card pubblicata dal comitato tecnico MMCA (MultiMedia Card Association).

    SD_RESPONSE_TYPE

    Il descrittore specifica un tipo di risposta di SDRT_1, che specifica una risposta R1 standard al comando e contiene dati di stato. Per una spiegazione della risposta R1, vedere la specifica MultiMedia Card Association .

  2. Configurare L'MDL

    Chiamare IoAllocateMdl per allocare un MDL e passare un puntatore a un buffer allocato da un pool non a pagina. Successivamente, la routine MmBuildMdlForNonPagedPool accetta l'MDL appena allocato che specifica un buffer di memoria virtuale nel pool non a pagina e lo aggiorna per descrivere le pagine fisiche sottostanti. I chiamanti di MmBuildMdlForNonPagedPool devono essere in esecuzione in IRQL <= DISPATCH_LEVEL.

  3. Inizializzare il pacchetto richiesta completando i passaggi seguenti:

    • Definire la funzione request:

      Dopo aver creato un descrittore SD, l'esempio di codice inizializza il pacchetto di richiesta, SDBUS_REQUEST_PACKET. Il membro RequestFunction 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 del dispositivo, quindi imposta il membro RequestFunction su SDRF_DEVICE_COMMAND.

    • Caricare il descrittore del comando. L'esempio di codice archivia quindi il descrittore appena inizializzato nel membro Parameters.DeviceCommand.CmdDesc 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 archivia anche il numero della funzione da cui viene letto lo spazio I/O dal driver del bus. 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.

  4. Inviare 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 quando ha aperto l'interfaccia SD. Poiché si tratta di una richiesta sincrona, il driver deve essere in esecuzione in IRQL minore di DISPATCH_LEVEL.

  5. 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.

L'esempio di codice alloca un buffer di trasferimento dati da un pool non a pagina. Un driver può usare PagedPool per un buffer di trasferimento dati, a condizione che blocchi le pagine. Tuttavia, i driver devono sempre allocare i buffer di trasferimento dati dal pool non a pagina quando si eseguono SDRF_GET_PROPERTY e SDRF_SET_PROPERTY richieste. I driver devono allocare anche pacchetti di richiesta SD dal pool non a pagina perché la routine di completamento dell'IRP che accompagna la richiesta SD potrebbe essere eseguita in una chiamata di procedura posticipata (DPC).

Per tutti i tipi di richieste, esistono vantaggi per le prestazioni per l'allocazione dei buffer da un pool non a pagina quando i buffer sono piccoli e il driver li contiene brevemente.