Compartir a través de


Protección de solicitudes digitales que usan E/S extendidas

Las solicitudes digitales seguras (SD) que leen o escriben más que un par de bytes de datos deben usar un comando de E/S extendido (denominado CMD53 en la especificación SD). El comando de E/S extendida indica al controlador del bus que transmita datos a través de las líneas DAT de la tarjeta SD. Las características de una transferencia de datos dependen de las funcionalidades del controlador SD. Por ejemplo, algunos controladores solo permiten E/S programables (PIO); otros permiten el acceso directo a la memoria (DMA). Para obtener la máxima compatibilidad entre diferentes tipos de controlador SD, los controladores de dispositivo deben cargar el paquete de solicitud con un puntero a un MDL que describa el búfer de datos. El controlador de dispositivo debe construir su propia MDL, a menos que un controlador de una capa superior construya el MDL y lo pase al controlador del dispositivo.

En el ejemplo de código siguiente se muestra cómo un controlador podría realizar una solicitud de E/S extendida mediante un búfer de datos descrito por una MDL. Este ejemplo de código es similar en formato al ejemplo de código de E/S directo descrito en Secure Digital Requests That Use Direct I/O (Solicitudes digitales seguras que usan E/S directa), por lo que podría resultar útil estudiar el ejemplo de código de E/S directo antes de estudiar el ejemplo de código de E/S extendido.

La diferencia principal entre los dos ejemplos es que el ejemplo de código de E/S extendido muestra cómo usar MDL con una solicitud SD. También hay pequeñas diferencias en la forma en que se definen descriptores y paquetes de solicitud para E/S directa y extendida.

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

En este ejemplo de código se incluyen los pasos siguientes:

  1. Inicialización del descriptor

    El primer paso para enviar una solicitud device-command es definir un descriptor de comandos SD, SDCMD_DESCRIPTOR. El descriptor del ejemplo de código define una operación de escritura de E/S extendida con los siguientes elementos:

    Elemento Descripción

    SD_COMMAND_CODE

    La operación definida por el descriptor realiza una escritura de E/S extendida, por lo que el valor del código de comando se SDCMD_IO_RW_DIRECT.

    SD_COMMAND_CLASS

    Las operaciones de escritura de E/S extendidas pertenecen al conjunto de comandos estándar (códigos de comando 0 a 63), por lo que el valor asignado a este miembro del descriptor se SDCC_STANDARD.

    SD_TRANSFER_DIRECTION

    Las operaciones de escritura requieren una transferencia del host al dispositivo, por lo que el valor asignado a este miembro del descriptor es SDTD_WRITE.

    SD_TRANSFER_TYPE

    El descriptor de una operación de escritura de E/S extendida debe incluir un tipo de transferencia. En el ejemplo de código se especifica una escritura de bloque único, SDTT_SINGLE_BLOCK, que indica que el host escribe un bloque de datos en el dispositivo. El controlador estableció el tamaño de un bloque por un comando anterior SET_BLOCKLEN (no se muestra en este ejemplo de código). Para obtener una explicación del comando SET_BLOCKLEN y el tipo de transferencia de SDTT_SINGLE_BLOCK, consulte La especificación de tarjeta MultiMedia , publicada por el comité técnico de la Asociación de Tarjetas MultiMedia (MMCA).

    SD_RESPONSE_TYPE

    El descriptor especifica un tipo de respuesta de SDRT_1, que especifica una respuesta R1 estándar al comando y contiene datos de estado. Para obtener una explicación de la respuesta R1, consulte la especificación De asociación de tarjetas MultiMedia .

  2. Configuración de MDL

    Llame a IoAllocateMdl para asignar una MDL y pasar un puntero a un búfer asignado desde un grupo no paginado. A continuación, la rutina MmBuildMdlForNonPagedPool toma la MDL recién asignada que especifica un búfer de memoria virtual en un grupo no paginado y lo actualiza para describir las páginas físicas subyacentes. Los autores de llamadas de MmBuildMdlForNonPagedPool deben ejecutarse en IRQL <= DISPATCH_LEVEL.

  3. Para inicializar el paquete de solicitud , complete los pasos siguientes:

    • Defina la función Request:

      Después de crear un descriptor SD, el ejemplo de código inicializa el paquete de solicitud, SDBUS_REQUEST_PACKET. El miembro RequestFunction del paquete de solicitud especifica si la solicitud contiene un comando de dispositivo (valor de SDRF_DEVICE_COMMAND) o una operación de propiedad (valor de SDRF_GET_PROPERTY o SDRF_SET_PROPERTY). El ejemplo de código envía un comando de dispositivo, por lo que establece el miembro RequestFunction en SDRF_DEVICE_COMMAND.

    • Cargue el descriptor de comandos. A continuación, el ejemplo de código almacena el descriptor recién inicializado en el miembro Parameters.DeviceCommand.CmdDesc del paquete de solicitud.

    • Inicialice el argumento de lectura y escritura:

      El paquete de solicitud contiene una estructura de SD_RW_DIRECT_ARGUMENT con la ubicación en la que escribe el controlador de autobús. Esta estructura también almacena el número de la función cuyo espacio de E/S lee el controlador de bus. El ejemplo de código recupera el número de función de la extensión de dispositivo, lo que implica que el controlador recuperó previamente esta información de la tarjeta (probablemente cuando se inició el dispositivo con una solicitud SDRF_GET_PROPERTY y la almacenó en la extensión del dispositivo.

  4. Enviar la solicitud

    Después de inicializar el descriptor y el paquete de solicitud, en el ejemplo se usa la rutina de solicitud sincrónica SdBusSubmitRequest para enviar la solicitud. Pasa el paquete de solicitud y la información de contexto de interfaz que el sistema proporcionó al controlador cuando abrió la interfaz SD. Dado que se trata de una solicitud sincrónica, el controlador debe ejecutarse en IRQL menor que DISPATCH_LEVEL.

  5. Resultados del comando

    Dado que el ejemplo de código usa un comando de E/S directo, no hay ningún búfer de datos distinto del campo ResponseData del paquete de solicitud SD.

En el ejemplo de código se asigna un búfer de transferencia de datos del grupo no paginado. Un controlador puede usar PagedPool para un búfer de transferencia de datos, siempre que bloquee las páginas. Sin embargo, los controladores siempre deben asignar búferes de transferencia de datos del grupo no paginado al realizar solicitudes SDRF_GET_PROPERTY y SDRF_SET_PROPERTY. Los controladores también deben asignar paquetes de solicitud SD del grupo no paginado porque la rutina de finalización del IRP que acompaña a la solicitud SD podría ejecutarse en una llamada a procedimiento diferido (DPC).

Para todo tipo de solicitudes, hay ventajas de rendimiento para asignar búferes del grupo no paginado cuando los búferes son pequeños y el controlador los contiene brevemente.