Using DMA (dma.h)
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:
- Creating a DMA buffer.
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()
orKnIoDmaCreateContinuous()
function. TheKnIoDmaCreateContinuous()
function creates a DMA buffer consisting of one block. TheKnIoDmaCreate()
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, theKnIoDmaCreate()
function can create a DMA buffer consisting of multiple blocks.The DMA buffer handle can be transferred to another process via IPC.
- Mapping the DMA buffer to the memory of processes.
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. - Opening access to the DMA buffer for a device via the
KnIoDmaBegin()
orKnIoDmaBeginEx()
function call.The
KnIoDmaBegin()
orKnIoDmaBeginEx()
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 theKnIoDmaBegin()
orKnIoDmaBeginEx()
function, and the object will contain virtual and physical addresses of blocks. If IOMMU is not enabled, you must use theKnIoDmaBegin()
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()
orKnIoDmaBeginEx()
function cannot be transferred to another process via IPC. - Information about the DMA buffer is received.
At this step, get the addresses and sizes of blocks from the kernel object that was created by calling the
KnIoDmaBegin()
orKnIoDmaBeginEx()
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()
andKnIoDmaGetPhysInfo()
functions get the memory page number (frame
) and theorder
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 parameteroutInfo
to pass theKosObject
that contains the structure with information about the DMA buffer (for details aboutKosObjects
, see Using KosObjects (objects.h)). The type of structure is defined in the header filesysroot-*-kos/include/io/io_dma.h
from the KasperskyOS SDK. TheKnIoDmaGetInfo()
function inserts data into all fields of the structure, while theKnIoDmaGetPhysInfo()
function inserts data only into thecount
anddescriptors
fields while writing zeros to all other fields. When using theKnIoDmaGetInfo()
function, thedescriptors
array contains virtual memory page numbers if IOMMU is enabled, and it contains physical memory page numbers if IOMMU is not enabled. When using theKnIoDmaGetPhysInfo()
function, thedescriptors
array contains physical memory page numbers regardless of whether or not IOMMU is enabled.The
KnIoDmaContinuousGetDmaAddr()
andKnIoDmaContinuousGetPhysAddr()
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.) TheKnIoDmaContinuousGetDmaAddr()
function uses the output parameteraddr
to pass the virtual address if IOMMU is enabled or the physical address if IOMMU is not enabled. TheKnIoDmaContinuousGetPhysAddr()
function uses the output parameteraddr
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 theKnIoDmaGetInfo()
function lets you get the offset physical page numbers because some devices use Visual Processing Unit (VPU) translation for DMA. Similarly, theKnIoDmaContinuousGetPhysAddr()
andKnIoDmaContinuousGetDmaAddr()
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:
- Free the virtual memory regions that were reserved during
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.
- Delete the kernel object that was created by the
KnIoDmaBegin()
orKnIoDmaBeginEx()
function call.To complete this step, you must close the handle that was received when the
KnIoDmaBegin()
orKnIoDmaBeginEx()
function was called. - Close or revoke each DMA buffer handle in all processes that own these handles.
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 |