The API is defined in the header file sysroot-*-kos/include/coresrv/io/dma.h
from the KasperskyOS SDK.
The API is designed to set up data exchange between devices and RAM in direct memory access (DMA) mode in which the processor is not used.
Information about API functions is provided in the table below.
Using the API
The standard scenario for API usage includes the following steps:
DMA buffer consists of one or more physical memory regions (blocks) that are used for DMA. A DMA buffer consisting of multiple blocks can be used if the device supports "scatter/gather DMA" mode. A DMA buffer consisting of one block can be used only if the device supports "scatter/gather DMA" or "continuous DMA" mode. The likelihood of creating a DMA buffer consisting of one large block is lower than the likelihood of creating a DMA buffer consisting of multiple small blocks. This is especially relevant when physical memory is highly fragmented.
If the device supports only "continuous DMA" mode, you must use a DMA buffer consisting of one block even if IOMMU is enabled.
To complete this step, call the KnIoDmaCreate()
or KnIoDmaCreateContinuous()
function. The KnIoDmaCreateContinuous()
function creates a DMA buffer consisting of one block. The KnIoDmaCreate()
function creates a DMA buffer consisting of one block if the 2^order value is equal to the memory page size value, or if the 2^order value is the next largest value of the memory page size in the ascending ordered set {2^(order-1);memory page size;2^order}. If the value of the memory page size is greater than the 2^order value, the KnIoDmaCreate()
function can create a DMA buffer consisting of multiple blocks.
The DMA buffer handle can be transferred to another process via IPC.
One DMA buffer can be mapped to multiple virtual memory regions of one or more processes that own the handle of this DMA buffer. Mapping allows processes to receive read-and/or-write access to the DMA buffer.
To reserve a virtual memory region and map the DMA buffer to it, call the KnIoDmaMap()
function.
A handle received when calling the KnIoDmaMap()
function cannot be transferred to another process via IPC.
KnIoDmaBegin()
or KnIoDmaBeginEx()
function call.The KnIoDmaBegin()
or KnIoDmaBeginEx()
function must be called to create a kernel object containing the addresses and sizes of blocks comprising the DMA buffer. A device needs this information to use the DMA buffer. A device can work with physical addresses and/or virtual addresses depending on whether IOMMU is enabled. If IOMMU is enabled, you must use the KnIoDmaBegin()
or KnIoDmaBeginEx()
function, and the object will contain virtual and physical addresses of blocks. If IOMMU is not enabled, you must use the KnIoDmaBegin()
function, and the object will contain physical addresses of blocks only.
When IOMMU is enabled, the device must be attached to an IOMMU domain.
A handle received when calling the KnIoDmaBegin()
or KnIoDmaBeginEx()
function cannot be transferred to another process via IPC.
At this step, get the addresses and sizes of blocks from the kernel object that was created by calling the KnIoDmaBegin()
or KnIoDmaBeginEx()
function. The received addresses and sizes will need to be passed to the device by using MMIO, for example. After receiving this information, the device can write to the DMA buffer and/or read from it.
To complete this step, call one of the following functions:
KnIoDmaGetInfo()
KnIoDmaGetPhysInfo()
KnIoDmaContinuousGetDmaAddr()
KnIoDmaContinuousGetPhysAddr()
The KnIoDmaGetInfo()
and KnIoDmaGetPhysInfo()
functions get the memory page number (frame
) and the order
for each block. (The memory page number multiplied by the memory page size results in the block address. The 2^order value is the block size in memory pages.) These functions use the output parameter outInfo
to pass the KosObject
that contains the structure with information about the DMA buffer (for details about KosObjects
, see Using KosObjects (objects.h)). The type of structure is defined in the header file sysroot-*-kos/include/io/io_dma.h
from the KasperskyOS SDK. The KnIoDmaGetInfo()
function inserts data into all fields of the structure, while the KnIoDmaGetPhysInfo()
function inserts data only into the count
and descriptors
fields while writing zeros to all other fields. When using the KnIoDmaGetInfo()
function, the descriptors
array contains virtual memory page numbers if IOMMU is enabled, and it contains physical memory page numbers if IOMMU is not enabled. When using the KnIoDmaGetPhysInfo()
function, the descriptors
array contains physical memory page numbers regardless of whether or not IOMMU is enabled.
The KnIoDmaContinuousGetDmaAddr()
and KnIoDmaContinuousGetPhysAddr()
functions can be used if the DMA buffer consists of one block. These functions let you get the block address. (The accepted block size should be the DMA buffer size that was defined when it was created.) The KnIoDmaContinuousGetDmaAddr()
function uses the output parameter addr
to pass the virtual address if IOMMU is enabled or the physical address if IOMMU is not enabled. The KnIoDmaContinuousGetPhysAddr()
function uses the output parameter addr
to pass the physical address, regardless of whether or not IOMMU is enabled.
On Raspberry Pi 4 B, the KnIoDmaGetPhysInfo()
function lets you get the actual physical page numbers, while the KnIoDmaGetInfo()
function lets you get the offset physical page numbers because some devices use Visual Processing Unit (VPU) translation for DMA. Similarly, the KnIoDmaContinuousGetPhysAddr()
and KnIoDmaContinuousGetDmaAddr()
functions let you get the actual and offset physical address, respectively.
Closing access to the DMA buffer for a device
Access to the DMA buffer can be closed only if IOMMU is enabled. If you delete the kernel object that was created when the KnIoDmaBegin()
or KnIoDmaBeginEx()
function was called, device access to the DMA buffer will be closed. To delete this object, you must close its handle.
Deleting a DMA buffer
To delete a DMA buffer, complete the following steps:
KnIoDmaMap()
function calls.To complete this step, you must close the handles that were received from KnIoDmaMap()
function calls.
This step must be completed for all processes whose memory is mapped to the DMA buffer.
KnIoDmaBegin()
or KnIoDmaBeginEx()
function call.To complete this step, you must close the handle that was received when the KnIoDmaBegin()
or KnIoDmaBeginEx()
function was called.
Information about API functions
dma.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a DMA buffer. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Creates a DMA buffer consisting of one block. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Reserves a virtual memory region and maps the DMA buffer to it. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Modifies the DMA buffer cache settings. Parameters
Returned values If successful, the function returns Additional information This function can be used if the following conditions are fulfilled:
In the
|
|
Purpose Gets information about a DMA buffer. This information includes the addresses and sizes of blocks. Parameters
Returned values If successful, the function returns Additional information To delete an object that was received via the |
|
Purpose Gets the physical addresses and sizes of DMA buffer blocks. Parameters
Returned values If successful, the function returns Additional information To delete an object that was received via the |
|
Purpose Gets the block address for a DMA buffer consisting of one block. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the block physical address for a DMA buffer consisting of one block. Parameters
Returned values If successful, the function returns |
|
Purpose Opens access to a DMA buffer for a device. Parameters
Returned values If successful, the function returns |
|
Purpose Opens access to a DMA buffer for a device. Parameters
Returned values If successful, the function returns |