KasperskyOS Community Edition 1.3

Использование DMA (dma.h)

API определен в заголовочном файле sysroot-*-kos/include/coresrv/io/dma.h из состава KasperskyOS SDK.

API предназначен для организации обмена данными между устройствами и оперативной памятью в режиме прямого доступа к памяти (англ. Direct Memory Access, DMA), при котором процессор не используется.

Сведения о функциях API приведены в таблице ниже.

Использование API

Типовой сценарий использования API включает следующие шаги:

  1. Создание буфера DMA.

    Буфер DMA –это буфер, состоящий из одного или нескольких регионов физической памяти (блоков), используемых для DMA. Буфер DMA, состоящий из нескольких блоков, можно использовать, если устройство поддерживает режим "scatter/gather DMA". Буфер DMA, состоящий из одного блока, можно использовать, если устройство поддерживает режим "scatter/gather DMA" или "continuous DMA". Вероятность создать буфер DMA, состоящий из одного большого блока, ниже, чем вероятность создать буфер DMA, состоящий из нескольких небольших блоков. Это особенно актуально при высокой фрагментации физической памяти.

    Если устройство поддерживает только режим "continuous DMA", то даже при задействовании IOMMU нужно использовать буфер DMA, состоящий из одного блока.

    Чтобы выполнить этот шаг, нужно вызвать функцию KnIoDmaCreate() или KnIoDmaCreateContinuous(). Функция KnIoDmaCreateContinuous() создает буфер DMA, состоящий из одного блока. Функция KnIoDmaCreate() создает буфер DMA, состоящий из одного блока, если значение 2^order равно значению size/размер страницы памяти, или значение 2^order является ближайшим большим к значению size/размер страницы памяти в упорядоченном по возрастанию множестве {2^(order-1);size/размер страницы памяти;2^order}. Если значение size/размер страницы памяти больше значения 2^order, функция KnIoDmaCreate() может создать буфер DMA, состоящий из нескольких блоков.

    Дескриптор буфера DMA можно передать другому процессу через IPC.

  2. Отображение буфера DMA на память процессов.

    Один буфер DMA может быть отображен на несколько регионов виртуальной памяти одного или нескольких процессов, которые владеют дескриптором этого буфера DMA. В результате отображения процессы получают доступ к буферу DMA на чтение и/или запись.

    Чтобы зарезервировать регион виртуальной памяти и отобразить на него буфер DMA, нужно вызвать функцию KnIoDmaMap().

    Дескриптор, полученный при вызове функции KnIoDmaMap(), нельзя передать другому процессу через IPC.

  3. Открытие доступа к буферу DMA для устройства вызовом функции KnIoDmaBegin() или KnIoDmaBeginEx().

    Вызов функции KnIoDmaBegin() или KnIoDmaBeginEx() необходим, чтобы создать объект ядра, содержащий адреса и размеры блоков, из которых состоит буфер DMA. Эти сведения необходимы устройству, чтобы использовать буфер DMA. Устройство может работать как с физическими, так и с виртуальными адресами в зависимости от того, задействован ли IOMMU. Если IOMMU задействован, нужно использовать функцию KnIoDmaBegin() или KnIoDmaBeginEx(), и объект будет содержать виртуальные и физические адреса блоков. Если IOMMU не задействован, нужно использовать функцию KnIoDmaBegin(), и объект будет содержать только физические адреса блоков.

    При задействовании IOMMU устройство должно быть прикреплено к домену IOMMU.

    Дескриптор, полученный при вызове функции KnIoDmaBegin() или KnIoDmaBeginEx(), нельзя передать другому процессу через IPC.

  4. Получение сведений о буфере DMA.

    На этом шаге нужно получить адреса и размеры блоков из объекта ядра, созданного вызовом функции KnIoDmaBegin() или KnIoDmaBeginEx(). Полученные адреса и размеры в дальнейшем требуется передать устройству, используя, например, MMIO. После получения этих сведений устройство может записывать в буфер DMA и/или читать из него.

    Чтобы выполнить этот шаг, нужно вызвать одну из следующих функций:

    • KnIoDmaGetInfo();
    • KnIoDmaGetPhysInfo();
    • KnIoDmaContinuousGetDmaAddr();
    • KnIoDmaContinuousGetPhysAddr().

    Функции KnIoDmaGetInfo() и KnIoDmaGetPhysInfo() позволяют получить номер страницы памяти (frame) и порядок (order) для каждого блока. (Номер страницы памяти, умноженный на размер страницы памяти, дает адрес блока. Значение 2^order представляет собой размер блока в страницах памяти.) Через выходной параметр outInfo эти функции передают объект KosObject, который содержит структуру со сведениями о буфере DMA (об объектах KosObject см. "Использование объектов KosObject (objects.h)"). Тип структуры определен в заголовочном файле sysroot-*-kos/include/io/io_dma.h из состава KasperskyOS SDK. Функция KnIoDmaGetInfo() заполняет данными все поля структуры, а функция KnIoDmaGetPhysInfo() заполняет данными только поля count и descriptors, записывая в остальные поля нули. При использовании функции KnIoDmaGetInfo() массив descriptors содержит номера виртуальных страниц памяти, если IOMMU задействован, и номера физических страниц памяти, если IOMMU не задействован. При использовании функции KnIoDmaGetPhysInfo() массив descriptors содержит номера физических страниц памяти независимо от того, задействован IOMMU или нет.

    Функции KnIoDmaContinuousGetDmaAddr() и KnIoDmaContinuousGetPhysAddr() можно использовать, если буфер DMA состоит из одного блока. Эти функции позволяет получить адрес блока. (В качестве размера блока нужно принять размер буфера DMA, заданный при его создании.) Функция KnIoDmaContinuousGetDmaAddr() передает через выходной параметр addr виртуальный адрес, если IOMMU задействован, и физический адрес, если IOMMU не задействован. Функция KnIoDmaContinuousGetPhysAddr() передает через выходной параметр addr физический адрес независимо от того, задействован IOMMU или нет.

    На Raspberry Pi 4 B функция KnIoDmaGetPhysInfo() позволяет получить действительные номера физических страниц, а функция KnIoDmaGetInfo() позволяет получить номера физических страниц со смещением, обусловленным тем, что некоторые устройства используют при DMA трансляцию VPU (Visual Processing Unit). Аналогично функции KnIoDmaContinuousGetPhysAddr() и KnIoDmaContinuousGetDmaAddr() позволяют получить действительный и смещенный физический адрес соответственно.

Закрытие доступа к буферу DMA для устройства

Закрыть доступ к буферу DMA для устройства можно только при задействовании IOMMU. Если удалить объект ядра, созданный при вызове функции KnIoDmaBegin() или KnIoDmaBeginEx(), то доступ устройства к буферу DMA будет закрыт. Чтобы удалить этот объект, нужно закрыть его дескриптор.

Удаление буфера DMA

Чтобы удалить буфер DMA, нужно выполнить следующие шаги:

  1. Освободить регионы виртуальной памяти, зарезервированные при вызовах функции KnIoDmaMap().

    Чтобы выполнить этот шаг, нужно закрыть дескрипторы, которые были получены при вызовах функции KnIoDmaMap().

    Этот шаг нужно выполнить для всех процессов, на память которых отображен буфер DMA.

  2. Удалить объект ядра, созданный вызовом функции KnIoDmaBegin() или KnIoDmaBeginEx().

    Чтобы выполнить этот шаг, нужно закрыть дескриптор, который был получен при вызове функции KnIoDmaBegin() или KnIoDmaBeginEx().

  3. Закрыть или отозвать каждый дескриптор буфера DMA во всех процессах, которые владеют этими дескрипторами.

Сведения о функциях API

Функции dma.h

Функция

Сведения о функции

KnIoDmaCreate()

Назначение

Создает буфер DMA.

Параметры

  • [in] order – параметр, задающий минимальное число страниц памяти (2^order) в блоке.
  • [in] size – размер буфера DMA в байтах. Должен быть кратен размеру страницы памяти.
  • [in] flags – флаги, задающие параметры буфера DMA. Тип параметра и флаги определены в заголовочном файле sysroot-*-kos/include/io/io_dma.h из состава KasperskyOS SDK.
  • [out] outRid – указатель на дескриптор буфера DMA.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

Дополнительные сведения

В параметре flags можно указать следующие флаги:

  • DMA_DIR_TO_DEVICE – устройство имеет доступ к буферу DMA на чтение.
  • DMA_DIR_FROM_DEVICE – устройство имеет доступ к буферу DMA на запись.
  • DMA_DIR_BIDIR – устройство имеет доступ к буферу DMA на чтение и запись.
  • DMA_ZONE_DMA32 – для создания буфера DMA разрешено использовать только первые четыре гигабайта физической памяти.
  • DMA_ATTR_WRITE_BACK, DMA_ATTR_WRITE_THROUGH, DMA_ATTR_CACHE_DISABLE, DMA_ATTR_WRITE_COMBINE, DMA_RULE_CACHE_VOLATILE, DMA_RULE_CACHE_FIXED – управление кешированием.

KnIoDmaCreateContinuous()

Назначение

Создает буфер DMA, состоящий из одного блока.

Параметры

  • [in] size – размер буфера DMA в байтах. Должен быть кратен размеру страницы памяти.
  • [in] flags – флаги, задающие параметры буфера DMA. Тип параметра и флаги определены в заголовочном файле sysroot-*-kos/include/io/io_dma.h из состава KasperskyOS SDK.
  • [out] outRid – указатель на дескриптор буфера DMA.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

Дополнительные сведения

В параметре flags можно указать следующие флаги:

  • DMA_DIR_TO_DEVICE – устройство имеет доступ к буферу DMA на чтение.
  • DMA_DIR_FROM_DEVICE – устройство имеет доступ к буферу DMA на запись.
  • DMA_DIR_BIDIR – устройство имеет доступ к буферу DMA на чтение и запись.
  • DMA_ZONE_DMA32 – для создания буфера DMA разрешено использовать только первые четыре гигабайта физической памяти.
  • DMA_ATTR_WRITE_BACK, DMA_ATTR_WRITE_THROUGH, DMA_ATTR_CACHE_DISABLE, DMA_ATTR_WRITE_COMBINE, DMA_RULE_CACHE_VOLATILE, DMA_RULE_CACHE_FIXED – управление кешированием.

KnIoDmaMap()

Назначение

Резервирует регион виртуальной памяти и отображает на него буфер DMA.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [in] offset – смещение в буфере DMA, с которого нужно начать отображение, в байтах. Должно быть кратно размеру страницы памяти.
  • [in] length – размер части буфера DMA, которую нужно отобразить, в байтах. Должен быть кратен размеру страницы памяти. Также должно выполняться условие: length<=размер буфера DMA-offset.
  • [in,optional] hint – странично выровненный желаемый базовый адрес региона виртуальной памяти или 0, чтобы этот адрес был выбран автоматически.
  • [in] vmflags – флаги, задающие права доступа к региону виртуальной памяти. Флаги определены в заголовочном файле sysroot-*-kos/include/vmm/flags.h из состава KasperskyOS SDK.
  • [out] addr – указатель на базовый адрес региона виртуальной памяти.
  • [out] handle – указатель на дескриптор, который используется для освобождения региона виртуальной памяти.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

Дополнительные сведения

В параметре vmflags можно указать следующие флаги:

  • VMM_FLAG_READ – доступ на чтение.
  • VMM_FLAG_WRITE – доступ на запись.

KnIoDmaModify()

Назначение

Изменяет параметры кеширования буфера DMA.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [in] newAttr – флаги, задающие параметры кеширования буфера DMA. Флаги определены в заголовочном файле sysroot-*-kos/include/io/io_dma.h из состава KasperskyOS SDK.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

Дополнительные сведения

Функцию можно использовать, если выполняются следующие условия:

  1. Буфер DMA был создан с указанием флага DMA_RULE_CACHE_VOLATILE.
  2. Буфер DMA не отображен на виртуальную память.
  3. Предыдущий вызов функции (если он был) был выполнен с указанием флага DMA_RULE_CACHE_VOLATILE.

В параметре newAttr можно указать следующие флаги:

  • DMA_ATTR_WRITE_BACK, DMA_ATTR_WRITE_THROUGH, DMA_ATTR_CACHE_DISABLE, DMA_ATTR_WRITE_COMBINE, DMA_RULE_CACHE_VOLATILE – управление кешированием.

KnIoDmaGetInfo()

Назначение

Позволяет получить сведения о буфере DMA.

Сведения включают адреса и размеры блоков.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [out] outInfo – указатель на адрес объекта, содержащий структуру со сведениями о буфере DMA. Тип структуры определен в заголовочном файле sysroot-*-kos/include/io/io_dma.h из состава KasperskyOS SDK.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

Дополнительные сведения

Чтобы удалить объект, полученный через параметр outInfo, нужно использовать функцию KosPutObject() из API objects.h.

KnIoDmaGetPhysInfo()

Назначение

Позволяет получить физические адреса и размеры блоков буфера DMA.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [out] outInfo – указатель на адрес объекта, содержащего структуру со сведениями о буфере DMA. Тип структуры определен в заголовочном файле sysroot-*-kos/include/io/io_dma.h из состава KasperskyOS SDK.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

Дополнительные сведения

Чтобы удалить объект, полученный через параметр outInfo, нужно использовать функцию KosPutObject() из API objects.h.

KnIoDmaContinuousGetDmaAddr()

Назначение

Позволяет получить адрес блока для буфера DMA, состоящего из одного блока.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [out] addr – указатель на адрес блока. Тип адреса определен в заголовочном файле sysroot-*-kos/include/hal/mtypes.h из состава KasperskyOS SDK.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

KnIoDmaContinuousGetPhysAddr()

Назначение

Позволяет получить физический адрес блока для буфера DMA, состоящего из одного блока.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [out] addr – указатель на физический адрес блока. Тип адреса определен в заголовочном файле sysroot-*-kos/include/hal/mtypes.h из состава KasperskyOS SDK.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

KnIoDmaBegin()

Назначение

Открывает доступ к буферу DMA для устройства.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [out] handle – указатель на дескриптор объекта ядра, содержащего адреса и размеры блоков, которые необходимы устройству, чтобы использовать буфер DMA.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.

KnIoDmaBeginEx()

Назначение

Открывает доступ к буферу DMA для устройства.

Параметры

  • [in] rid – дескриптор буфера DMA.
  • [in] domain – дескриптор домена IOMMU.
  • [out] handle – указатель на дескриптор объекта ядра, содержащего адреса и размеры блоков, которые необходимы устройству, чтобы использовать буфер DMA.

Возвращаемые значения

В случае успеха возвращает rcOk, иначе возвращает код ошибки.