Защита цифровых запросов, использующих расширенные операции ввода-вывода
Запросы Secure Digital (SD), которые считывают или записывают больше, чем несколько байтов данных, должны использовать расширенную команду ввода-вывода (которая в спецификации SD называется CMD53). Расширенная команда ввода-вывода указывает водителю шины передавать данные через линии DAT SD карта. Характеристики передачи данных зависят от возможностей контроллера SD. Например, некоторые контроллеры разрешают только программируемый ввод-вывод (PIO); другие разрешают прямой доступ к памяти (DMA). Для обеспечения максимальной совместимости с различными типами контроллеров SD драйверы устройств должны загружать пакет запроса с указателем на MDL, описывающий буфер данных. Драйвер устройства должен создать собственный MDL, если только драйвер на более высоком уровне не создает MDL и не передает его драйверу устройства.
В следующем примере кода показано, как драйвер может выполнять расширенный запрос ввода-вывода с помощью буфера данных, описанного в MDL. Этот пример кода по формату аналогичен примеру кода прямого ввода-вывода, описанному в разделе Безопасные цифровые запросы, использующие прямые операции ввода-вывода, поэтому может быть полезно изучить пример кода прямого ввода-вывода перед изучением расширенного примера кода ввода-вывода.
Принципиальное различие между этими двумя примерами заключается в том, что в расширенном примере кода ввода-вывода показано, как использовать mdls с запросом SD. Кроме того, существуют небольшие различия в определении дескрипторов и пакетов запросов для прямого и расширенного ввода-вывода.
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);
Этот пример кода включает следующие шаги:
Инициализация дескриптора
Первым шагом при отправке запроса device-command является определение дескриптора команды SD , SDCMD_DESCRIPTOR. Дескриптор в примере кода определяет расширенную операцию записи ввода-вывода со следующими элементами:
Элемент Описание Операция, определяемая дескриптором, выполняет расширенную запись ввода-вывода, поэтому значение командного кода SDCMD_IO_RW_DIRECT.
Расширенные операции записи ввода-вывода относятся к стандартному набору команд (коды команд от 0 до 63), поэтому этому члену дескриптора присваивается значение SDCC_STANDARD.
Операции записи требуют передачи с узла на устройство, поэтому значение, присвоенное этому члену дескриптора, равно SDTD_WRITE.
Дескриптор для расширенной операции записи ввода-вывода должен включать тип передачи. В примере кода указывается один блок записи SDTT_SINGLE_BLOCK, который указывает, что узел записывает на устройство один блок данных. Драйвер установил размер блока с помощью предыдущей команды SET_BLOCKLEN (не показано в этом примере кода). Описание команды SET_BLOCKLEN и типа передачи SDTT_SINGLE_BLOCK см. в разделе Спецификация MultiMedia Card , опубликованная техническим комитетом Ассоциации карт MultiMedia (MMCA).
Дескриптор задает тип ответа SDRT_1, который задает стандартный ответ R1 на команду и содержит данные о состоянии. Описание ответа R1 см. в спецификации Ассоциации карт MultiMedia .
Настройка MDL
Вызовите IoAllocateMdl , чтобы выделить MDL и передать указатель на буфер, выделенный из нестраничного пула. Затем подпрограмма MmBuildMdlForNonPagedPool принимает только что выделенный MDL, указывающий буфер виртуальной памяти в нестраничном пуле, и обновляет его для описания базовых физических страниц. Вызывающие устройства MmBuildMdlForNonPagedPool должны выполняться в irQL <= DISPATCH_LEVEL.
Инициализируйте пакет запроса , выполнив следующие действия.
Определите функцию запроса:
После создания дескриптора SD в примере кода инициализируется пакет запроса , SDBUS_REQUEST_PACKET. Элемент RequestFunction пакета запроса указывает, содержит ли запрос команду устройства (значение SDRF_DEVICE_COMMAND) или операцию свойства (значение SDRF_GET_PROPERTY или SDRF_SET_PROPERTY). В примере кода отправляется команда устройства, поэтому члену RequestFunction присваивается значение SDRF_DEVICE_COMMAND.
Загрузите дескриптор команды. Далее в примере кода новый инициализированный дескриптор сохраняется в элементе Parameters.DeviceCommand.CmdDesc пакета запроса.
Инициализируйте аргумент чтения и записи:
Пакет запроса содержит структуру SD_RW_DIRECT_ARGUMENT с расположением, в которое записывает драйвер автобуса. В этой структуре также хранится число функции, пространство ввода-вывода которой считывает водитель автобуса. В примере кода извлекается номер функции из расширения устройства. Это означает, что драйвер ранее извлек эти сведения из карта (вероятно, когда он запустил устройство с запросом SDRF_GET_PROPERTY и сохранил их в расширении устройства.
Отправка запроса
После инициализации дескриптора и пакета запроса в примере используется синхронная подпрограмма запроса SdBusSubmitRequest для отправки запроса. Он передает пакет запроса и сведения о контексте интерфейса, которые система предоставила драйверу при открытии интерфейса SD. Так как это синхронный запрос, драйвер должен работать в IRQL менее DISPATCH_LEVEL.
Результаты выполнения команды
Так как в примере кода используется команда прямого ввода-вывода, в пакете запроса SD нет буфера данных, кроме поля ResponseData .
В примере кода выделяется буфер передачи данных из нестраничного пула. Драйвер может использовать PagedPool для буфера передачи данных при условии, что он блокирует страницы. Однако драйверы всегда должны выделять буферы передачи данных из нестраничного пула при выполнении запросов SDRF_GET_PROPERTY и SDRF_SET_PROPERTY. Драйверы также должны выделять пакеты запросов SD из нестраничного пула, так как подпрограмма завершения IRP, сопровождающая запрос SD, может выполняться в отложенном вызове процедуры (DPC).
Для всех типов запросов есть преимущества производительности при выделении буферов из нестраничного пула, если буферы небольшие и драйвер удерживает их на короткое время.