Partilhar via


Proteger solicitações digitais que usam E/S estendida

As solicitações SD (Secure Digital) que leem ou gravam mais do que apenas alguns bytes de dados devem usar um comando de E/S estendido (conhecido como CMD53 na especificação do SD). O comando de E/S estendido instrui o motorista do barramento a transmitir dados pelas linhas DAT do SD cartão. As características de uma transferência de dados dependem dos recursos do controlador SD. Por exemplo, alguns controladores só permitem E/S programável (PIO); outros permitem acesso direto à memória (DMA). Para obter a compatibilidade máxima entre diferentes tipos de controlador SD, os drivers de dispositivo devem carregar o pacote de solicitação com um ponteiro para um MDL que descreve o buffer de dados. O driver do dispositivo deve construir seu próprio MDL, a menos que um driver em uma camada mais alta construa o MDL e o passe para o driver do dispositivo.

O exemplo de código a seguir mostra como um driver pode executar uma solicitação de E/S estendida usando um buffer de dados descrito por um MDL. Este exemplo de código é semelhante em formato ao exemplo de código de E/S direto descrito em Solicitações Digitais Seguras que Usam E/S Direta, portanto, pode ser útil estudar o exemplo de código de E/S direto antes de estudar o exemplo de código de E/S estendido.

A principal diferença entre os dois exemplos é que o exemplo de código de E/S estendido ilustra como usar MDLs com uma solicitação SD. Também há pequenas diferenças na forma como descritores e pacotes de solicitação são definidos para E/S direta e estendida.

    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);

Este exemplo de código inclui as seguintes etapas:

  1. Inicializar o Descritor

    A primeira etapa no envio de uma solicitação device-command é definir um descritor de comando SD, SDCMD_DESCRIPTOR. O descritor no exemplo de código define uma operação de gravação de E/S estendida com os seguintes elementos:

    Elemento Descrição

    SD_COMMAND_CODE

    A operação definida pelo descritor executa uma gravação de E/S estendida, portanto, o valor do código de comando é SDCMD_IO_RW_DIRECT.

    SD_COMMAND_CLASS

    As operações de gravação de E/S estendidas pertencem ao conjunto de comandos padrão (códigos de comando 0 a 63), portanto, o valor atribuído a esse membro do descritor é SDCC_STANDARD.

    SD_TRANSFER_DIRECTION

    As operações de gravação exigem uma transferência do host para o dispositivo, portanto, o valor atribuído a esse membro do descritor é SDTD_WRITE.

    SD_TRANSFER_TYPE

    O descritor de uma operação de gravação de E/S estendida deve incluir um tipo de transferência. O exemplo de código especifica uma gravação de bloco único, SDTT_SINGLE_BLOCK, que indica que o host grava um bloco de dados no dispositivo. O driver estabeleceu o tamanho de um bloco por um comando SET_BLOCKLEN anterior (não ilustrado neste exemplo de código). Para obter uma explicação do comando SET_BLOCKLEN e do tipo de transferência SDTT_SINGLE_BLOCK, consulte A especificação do Cartão MultiMedia , publicada pelo comitê técnico da MMCA (Associação multiMedia Card).

    SD_RESPONSE_TYPE

    O descritor especifica um tipo de resposta de SDRT_1, que especifica uma resposta R1 padrão ao comando e contém status dados. Para obter uma explicação da resposta R1, consulte a especificação Associação de Cartão MultiMedia .

  2. Configurar o MDL

    Chame IoAllocateMdl para alocar um MDL e passar um ponteiro para um buffer alocado do pool não paginado. Em seguida, a rotina MmBuildMdlForNonPagedPool usa o MDL recém-alocado que especifica um buffer de memória virtual no pool não paginado e o atualiza para descrever as páginas físicas subjacentes. Os chamadores de MmBuildMdlForNonPagedPool devem estar em execução em IRQL <= DISPATCH_LEVEL.

  3. Inicialize o Pacote de Solicitação concluindo as seguintes etapas:

    • Defina a Função de Solicitação:

      Depois de criar um descritor SD, o exemplo de código inicializa o pacote de solicitação , SDBUS_REQUEST_PACKET. O membro RequestFunction do pacote de solicitação especifica se a solicitação contém um comando de dispositivo (valor de SDRF_DEVICE_COMMAND) ou uma operação de propriedade (valor de SDRF_GET_PROPERTY ou SDRF_SET_PROPERTY). O exemplo de código está enviando um comando de dispositivo, portanto, ele define o membro RequestFunction como SDRF_DEVICE_COMMAND.

    • Carregue o Descritor de Comando. Em seguida, o exemplo de código armazena o descritor recém-inicializado no membro Parameters.DeviceCommand.CmdDesc do pacote de solicitação.

    • Inicialize o argumento de leitura/gravação:

      O pacote de solicitação contém uma estrutura SD_RW_DIRECT_ARGUMENT com o local no qual o motorista do ônibus grava. Essa estrutura também armazena o número da função cujo espaço de E/S o motorista do barramento lê. O exemplo de código recupera o número da função da extensão do dispositivo, o que implica que o driver recuperou anteriormente essas informações do cartão (provavelmente quando iniciou o dispositivo com uma solicitação de SDRF_GET_PROPERTY e as armazenou na extensão do dispositivo.

  4. Enviar a solicitação

    Depois de inicializar o descritor e o pacote de solicitação, o exemplo usa a rotina de solicitação síncrona, SdBusSubmitRequest para enviar a solicitação. Ele passa o pacote de solicitação e as informações de contexto da interface que o sistema forneceu ao driver quando abriu a interface SD. Como essa é uma solicitação síncrona, o driver deve estar em execução no IRQL com menos de DISPATCH_LEVEL.

  5. Resultados do comando

    Como o exemplo de código usa um comando de E/S direto, nenhum buffer de dados diferente do campo ResponseData no pacote de solicitação SD.

O exemplo de código aloca um buffer de transferência de dados do pool não paginado. Um driver pode usar PagedPool para um buffer de transferência de dados, desde que bloqueie as páginas. No entanto, os drivers devem sempre alocar buffers de transferência de dados de pool não paginado ao fazer solicitações de SDRF_GET_PROPERTY e SDRF_SET_PROPERTY. Os drivers também devem alocar pacotes de solicitação SD de pool não paginado porque a rotina de conclusão do IRP que acompanha a solicitação SD pode ser executada em uma DPC (chamada de procedimento adiado).

Para todos os tipos de solicitações, há benefícios de desempenho para alocar buffers de pool não paginado quando os buffers são pequenos e o driver os mantém brevemente.