Compartir a través de


División de solicitudes de transferencia de DMA

Es posible que cualquier controlador tenga que dividir una solicitud de transferencia y llevar a cabo más de una operación de transferencia DMA para satisfacer un IRP determinado, dependiendo de lo siguiente:

  • Número de registros de mapa devueltos por IoGetDmaAdapter

  • Bytes de datos que se van a transferir, incluidos en el miembro Length de la ubicación de pila de E/S del controlador para irP.

  • Número de límites de página, en memoria física del sistema, para el búfer en el que o desde el que el controlador va a transferir datos

  • Restricciones específicas del dispositivo en las operaciones DMA del controlador. Por ejemplo, el controlador de disco "AT" del sistema debe dividir las solicitudes de transferencia para más de 256 sectores debido a las limitaciones del controlador de disco.

Un controlador puede determinar el número de registros de mapa necesarios para transferir todos los datos especificados por un IRP de la siguiente manera:

  1. Llama a MmGetMdlVirtualAddress, pasando un puntero al MDL en Irp-MdlAddress>, para obtener la dirección virtual inicial del búfer. Tenga en cuenta que un controlador no debe intentar acceder a la memoria mediante esta dirección virtual. El valor devuelto por MmGetMdlVirtualAddress es un índice en MDL, no necesariamente una dirección válida.

  2. Pase el índice devuelto y el valor de Length en la ubicación de pila de E/S del controlador del IRP a la macro ADDRESS_AND_SIZE_TO_SPAN_PAGES .

Si el valor devuelto por ADDRESS_AND_SIZE_TO_SPAN_PAGES es mayor que el valor NumberOfMapRegisters devuelto por IoGetDmaAdapter, el controlador no puede transferir todos los datos solicitados para este IRP en una sola operación DMA. En su lugar, debe hacer lo siguiente:

  1. Divida el búfer en partes de tamaño para adaptarse al número de registros de mapa disponibles (y cualquier restricción DMA específica del dispositivo).

  2. Realice tantas operaciones DMA como sea necesario para satisfacer la solicitud de transferencia.

Por ejemplo, supongamos que ADDRESS_AND_SIZE_TO_SPAN_PAGES indica que se necesitan doce registros de asignación para satisfacer una solicitud de transferencia, pero el valor NumberOfMapRegisters devuelto por IoGetDmaAdapter es solo cinco. (Suponga que no hay restricciones DMA específicas del dispositivo). En este caso, el controlador debe realizar tres operaciones de transferencia de DMA, llamando a MapTransfer tres veces para transferir todos los datos solicitados por el IRP.

Los controladores de dispositivos DMA del sistema usan varias técnicas para dividir una transferencia DMA cuando no hay suficientes registros de mapa para satisfacer un IRP con una sola operación de E/S. Una técnica que se debe usar es la siguiente:

  1. Llame a IoAllocateMdl para asignar una MDL que describa una parte del búfer de usuario.

  2. Llame a MmProbeAndLockPages para bloquear esa parte del búfer de usuario.

  3. Transfiera los datos de esa parte del búfer.

  4. Llame a MmUnlockPages y realice una de las siguientes acciones:

    • Si el MDL que el controlador asignado en el paso 1 es lo suficientemente grande para la siguiente parte de la transferencia, llame a MmPrepareMdlForReuse y repita los pasos del 2 al 4.
    • De lo contrario, llame a IoFreeMdl y repita los pasos del 1 al 4.
  5. Llame a MmUnlockPages e IoFreeMdl cuando se hayan transferido todos los datos.

Si un controlador de nivel superior no puede bloquear todo el búfer de usuario con MmProbeAndLockPages en una máquina con memoria limitada, puede hacer lo siguiente:

  1. Llame a IoBuildSynchronousFsdRequest para asignar un IRP de transferencia parcial y bloquear una parte del búfer de usuario. El área bloqueada suele ser un múltiplo de PAGE_SIZE o tiene un tamaño adecuado para adaptarse a la capacidad de transferencia del dispositivo subyacente.

  2. Llame a IoCallDriver para el IRP de transferencia parcial y llame a KeWaitForSingleObject para esperar a un objeto de evento que el controlador configuró para asociarse con su IRP de transferencia parcial, si los controladores inferiores devuelven STATUS_PENDING.

  3. Cuando recupere el control, repita los pasos 1 y 2 hasta que se transfieran todos los datos y, a continuación, complete el IRP original.

Cuando un controlador de clase de almacenamiento divide las solicitudes de transferencia grandes para los controladores de puerto o miniport SCSI subyacentes, asigna un IRP adicional para cada parte de la solicitud de transferencia. Registra una rutina de IoCompletion para cada IRP asignado por el controlador, para realizar un seguimiento del estado de la solicitud de transferencia completa y liberar los IRP asignados por el controlador. A continuación, envía estos IRP al controlador de puerto mediante IoCallDriver.

Otros controladores de clase/puerto solo pueden usar esta técnica si el controlador de clase puede determinar cuántos registros de mapa están disponibles para el controlador de puerto. El controlador de puerto debe almacenar esta información de configuración en el Registro para el controlador de clase emparejado o los controladores emparejados deben definir una interfaz privada, mediante solicitudes de control de E/S de dispositivo internas, para pasar información de configuración sobre el número de registros de mapa disponibles desde el controlador de puerto al controlador de clase.

Un controlador monolítico (es decir, un controlador que no forma parte de un par de clases o puertos) para un dispositivo DMA debe dividir las solicitudes de transferencia grandes para sí mismo. Estos controladores suelen dividir una solicitud grande en partes y llevar a cabo una secuencia de operaciones DMA para satisfacer el IRP.

Si una solicitud de transferencia es demasiado grande para que el controlador de dispositivo subyacente lo controle, un controlador de nivel superior puede llamar a MmGetMdlVirtualAddress e IoBuildPartialMdl, configure una secuencia de IRP de transferencia parcial para controladores de dispositivo subyacentes.