Contents
- libkos library
- Managing handles (handle_api.h)
- Allocating and freeing memory (alloc.h)
- Using DMA (dma.h)
- Managing interrupt processing (irq.h)
- Initializing IPC transport for interprocess communication and managing IPC request processing (transport-kos.h, transport-kos-dispatch.h)
- Initializing IPC transport for querying the security module (transport-kos-security.h)
- Generating random numbers (random_api.h)
- Getting and changing time values (time_api.h)
- Using notifications (notice_api.h)
- Dynamically creating IPC channels (cm_api.h, ns_api.h)
- Using synchronization primitives (event.h, mutex.h, rwlock.h, semaphore.h, condvar.h)
- Managing I/O memory isolation (iommu_api.h)
- Using queues (queue.h)
- Using memory barriers (barriers.h)
- Executing system calls (syscalls.h)
- IPC interrupt (ipc_api.h)
libkos library
The libkos
library is the basic KasperskyOS library that provides the set of APIs that allow programs and other libraries (for example, libc
and kdf
) to use core endpoints. The APIs provided by the libkos
library enable solution developers to do the following:
- Manage processes, threads, and virtual memory.
- Control access to resources.
- Perform input/output operations.
- Create IPC channels.
- Manage power.
- Obtain statistical data on the system.
- Use other capabilities supported by core endpoints.
This section contains detailed descriptions for working with some libkos
library interfaces. Descriptions of other interfaces can be found in corresponding header files.
The header files that define the libkos
library API are located in the following directories:
sysroot-*-kos/include/coresrv/
sysroot-*-kos/include/kos/
Managing handles (handle_api.h)
The API is defined in the sysroot-*-kos/include/coresrv/handle/handle_api.h
header file from the KasperskyOS SDK.
The API is intended for performing operations with handles. Handles have the Handle
type, which is defined in the header file sysroot-*-kos/include/handle/handletype.h
from the KasperskyOS SDK.
Locality of handles
Each process receives handles from its own handle space irrespective of other processes. The handle spaces of different processes are absolutely identical in that they consist of the same set of values. Therefore, a handle is unique (has a unique value) only within the handle space of the single process that owns the particular handle. In other words, different processes may have identical handles that identify different resources, or may have different handles that identify the same resource.
Handle permissions mask
A handle permissions mask has a size of 32 bits and consists of a general part and a specialized part. The general part describes the general rights that are not specific to any particular resource (the flags of these rights are defined in the header file sysroot-*-kos/include/services/ocap.h
from the KasperskyOS SDK). For example, the general part contains the OCAP_HANDLE_TRANSFER
flag, which defines the permission to transfer the handle. The specialized part describes the rights that are specific to the particular user resource or system resource. The flags of the specialized part's permissions for system resources are defined in the ocap.h
header file. The structure of the specialized part for user resources is defined by the resource provider by using the OCAP_HANDLE_SPEC()
macro that is defined in the ocap.h
header file. The resource provider must export the public header files describing the flags of the specialized part.
When the handle of a system resource is created, the permissions mask is defined by the KasperskyOS kernel, which applies permissions masks from the ocap.h
header file. It applies permissions masks with names such as OCAP_*_FULL
(for example, OCAP_IOPORT_FULL
, OCAP_TASK_FULL
, OCAP_FILE_FULL
) and OCAP_IPC_*
(for example, OCAP_IPC_SERVER
, OCAP_IPC_LISTENER
, OCAP_IPC_CLIENT
).
When the handle of a user resource is created, the permissions mask is defined by the user.
When a handle is transferred, the permissions mask is defined by the user but the transferred access rights cannot be elevated above the access rights of the process.
Page topCreating handles
Creating handles of system resources
Handles of system resources are created when these resources are created. For example, handles are created when an interrupt or MMIO memory region is registered, and when a DMA buffer, thread, or process is created.
Creating handles of user resources
Handles of user resources are created by the providers of these resources by using the KnHandleCreateUserObject()
or KnHandleCreateUserObjectEx()
function.
The context of a user resource must be defined through the context
parameter. The user resource context consists of data that allows the resource provider to identify the resource and its state when access to the resource is requested by other processes. This normally consists of a data set with various types of data (structure). For example, the context of a file may include the name, path, and cursor position. The user resource context is used as the resource transfer context or is used together with multiple resource transfer contexts.
You must use the rights
parameter to define the handle permissions mask.
Creating IPC handles
An IPC handle is a handle that identifies an IPC channel. IPC handles are used to execute system calls. A client IPC handle is necessary for executing a Call()
system call. A server IPC handle is necessary for executing the Recv()
and Reply()
system calls. A listener handle is a server IPC handle that has extended rights allowing it to add IPC channels to the set of IPC channels identified by this handle. A callable handle is a client IPC handle that simultaneously identifies the IPC channel to a server and an endpoint of this server.
A server creates a callable handle and passes it to a client so that the client can use the server endpoint. The client initializes IPC transport by using the callable handle that it received. In addition, the client specifies the INVALID_RIID
value as the endpoint ID (RIID) in the proxy object initialization function. To create a callable handle, call the KnHandleCreateUserObjectEx()
function and specify the server IPC handle and the endpoint ID (RIID) in the ipcChannel
and riid
parameters, respectively. Use the context
parameter to specify the data to be associated with the callable handle. The server will be able to receive the pointer to this data when dereferencing the callable handle. (Even though the callable handle is an IPC handle, the kernel puts it into the base_.self
field of the constant part of an IPC request.)
To create the client IPC handle, server IPC handle, and listener IPC handle and associate them with each other, call the KnHandleConnect()
or KnHandleConnectEx()
function. These functions are used to statically create IPC channels. The KnHandleConnect()
function creates IPC handles from the handle space of the calling process. However, the client IPC handle can be transferred to another process. The KnHandleConnectEx()
function can create IPC handles from the handle space of the calling process or from the handle spaces of other processes, such as the client and server.
When calling the KnHandleConnect()
or KnHandleConnectEx()
function with the INVALID_HANDLE
value in the parameter that defines the listener handle, a new listener handle is created. However, the server IPC handle and listener IPC handle in the output parameters are the same handle. If a listener handle is specified when calling the KnHandleConnect()
or KnHandleConnectEx()
function, the created server IPC handle will provide the capability to receive IPC requests over all IPC channels associated with this listener handle. In this case, the server IPC handle and listener IPC handle in the output parameters are different handles. (The first IPC channel associated with the listener handle is created when calling the KnHandleConnect()
or KnHandleConnectEx()
function with the INVALID_HANDLE
value in the parameter that defines the listener handle. The second and subsequent IPC channels associated with the listener handle are created during the second and subsequent calls of the KnHandleConnect()
or KnHandleConnectEx()
function specifying the listener handle that was obtained during the first call.)
To call a listener handle that is not associated with a client IPC handle and server IPC handle, call the KnHandleCreateListener()
function. (The KnHandleConnect()
and KnHandleConnectEx()
functions create a listener handle associated with a client IPC handle and server IPC handle.) The KnHandleCreateListener()
function is convenient for creating a listener handle that will be subsequently bound to callable handles.
To create a client IPC handle for querying the Kaspersky Security Module through the security interface, call the KnHandleSecurityConnect()
function. This function is called by the libkos
library when initializing IPC transport for querying the security module.
Information about API functions
handle_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a handle. Parameters
Returned values If successful, the function returns |
|
Purpose Creates a handle. Parameters
Returned values If successful, the function returns |
|
Purpose Creates and connects the client, server, and listener IPC handles. Parameters
Returned values If successful, the function returns |
|
Purpose Creates and connects the client, server, and listener IPC handles. Parameters
Returned values If successful, the function returns |
|
Purpose Creates a client IPC handle for querying the Kaspersky Security Module through the security interface. Parameters
Returned values If successful, the function returns |
|
Purpose Creates a listener handle that is not associated with a client IPC handle and server IPC handle. Parameters
Returned values If successful, the function returns |
Transferring handles
Overview
Handles are transferred between processes so that resource consumers can gain access to required resources. Due to the specific locality of handles, a handle transfer initiates the creation of a handle from the handle space of the recipient process. This handle is registered as a descendant of the transferred handle and identifies the same resource.
One handle can be transferred multiple times to one or more processes. Each transfer initiates the creation of a new descendant of the transferred handle on the recipient process side. A process can transfer handles that it received from other processes or the KasperskyOS kernel. For this reason, a handle may have multiple generations of descendants. The generation hierarchy of handles for each resource is stored in the KasperskyOS kernel in the form of a handle inheritance tree.
A process can transfer handles for user resources and system resources if the access rights of these handles permit such a transfer (the OCAP_HANDLE_TRANSFER
flag is set in the permissions mask). A descendant may have less access rights than an ancestor. For example, a transferring process with read-and-write permissions for a file can transfer read-only permissions. The transferring process can also prohibit the recipient process from further transferring the handle. Access rights are defined in the transferred permissions mask for the handle.
Conditions for transferring handles
To enable processes to transfer handles to other processes, the following conditions must be met:
- An IPC channel is created between the processes.
- The solution security policy (
security.psl
) allows interaction between process classes. - Interface methods are implemented for transferring handles.
The API task.h enables a parent process to pass handles to a child process that is not yet running.
In an IDL description, signatures of interface methods for transferring handles have input (in
) and/or output (out
) parameters of the Handle
type or array
type with elements of the Handle
type. Up to 255 handles can be passed through the input parameters of one method. This same number of handles can be received through output parameters.
Example IDL description that defines the signatures of interface methods for transferring handles:
For each parameter of the Handle
type, the NK compiler generates a field of the nk_handle_desc_t
type (hereinafter also referred to as the transport container of the handle) in the *_req
IPC request structure and/or *_res
IPC response structure. This type is declared in the header file sysroot-*-kos/include/nk/types.h
from the KasperskyOS SDK and comprises a structure consisting of the following three fields: handle
field for the handle, rights
field for the handle permissions mask, and the badge
field for the resource transfer context.
Resource transfer context
The resource transfer context consists of data that allows the server to identify the resource and its state when access to the resource is requested via descendants of the transferred handle. This normally consists of a data set with various types of data (structure). For example, the transfer context of a file may include the name, path, and cursor position. The server receives a pointer to the resource transfer context when dereferencing a handle.
Regardless of whether or not the server is the resource provider, the server can associate each handle transfer with a separate resource transfer context. This resource transfer context is bound only to the handle descendants (handle inheritance subtree) that were generated as a result of a specific transfer of the handle. This lets you define the state of a resource in relation to a separate transfer of the handle of this resource. For example, for cases when one file may be accessed multiple times, the file transfer context lets you define which specific opening of this file corresponds to a received IPC request.
If the server is the resource provider, each transfer of the handle of this resource is associated with the user resource context by default. In other words, the user resource context is used as the resource transfer context for each handle transfer if the particular transfer is not associated with a separate resource transfer context.
A server that is the resource provider can use both the user resource context and the resource transfer context together. For example, the name, path and size of a file is stored in the user resource context while the cursor position can be stored in multiple resource transfer contexts because each client can work with different parts of the file. Technically, joint use of the user resource context and resource transfer contexts is possible because the resource transfer contexts store a pointer to the user resource context.
If the client uses multiple various-type resources of the server, the resource transfer contexts (or contexts of user resources if they are used as resource transfer contexts) must be specialized objects of the KosObject
type. This is necessary so that the server can verify that the client using a resource has sent the interface method the handle of the specific resource that corresponds to this method. This verification is required because the client could mistakenly send the interface method a resource handle that does not correspond to this method. For example, a client may have received a file handle and sent it to an interface method for working with volumes.
To associate a handle transfer with a resource transfer context, the server puts the handle of the resource transfer context object into the badge
field of the nk_handle_desc_t
structure. The resource transfer context object is the kernel object that stores the pointer to the resource transfer context. To create a resource transfer context object, call the KnHandleCreateBadge()
function. This function is bound to the notification mechanism because a server needs to know when a resource transfer context object will be closed and deleted. The server needs this information to free up or re-use memory that was allotted for storing the resource transfer context.
The resource transfer context object will be closed upon the closure or revocation of the handle descendants that comprise the handle inheritance subtree whose root node was generated by the transfer of this handle in association with this object. (A transferred handle may be closed intentionally or unintentionally, such as when a recipient client is unexpectedly terminated.) After receiving a notification regarding the closure of a resource transfer context object, the server closes the handle of this object. After this, the resource transfer context object will be deleted. After receiving a notification regarding the deletion of the resource transfer context object, the server frees up or re-uses the memory that was allotted for storing the resource transfer context.
One resource transfer context object can be associated with only one handle transfer.
Packaging data into the transport container of a handle
To package a handle, handle permissions mask, and resource transfer context object handle into a handle transport container, use the nk_handle_desc()
macro that is defined in the header file sysroot-*-kos/include/nk/types.h
from the KasperskyOS SDK. This macro receives a variable number of parameters.
If no parameter is passed to the macro, the NK_INVALID_HANDLE
value will be written to the handle
field of the nk_handle_desc_t
structure. If one parameter is passed to the macro, this parameter is interpreted as the handle. If two parameters are passed to the macro, the first parameter is interpreted as the handle and the second parameter is interpreted as the handle permissions mask. If three parameters are passed to the macro, the first parameter is interpreted as the handle, the second parameter is interpreted as the handle permissions mask, and the third parameter is interpreted as the resource transfer context object handle.
Extracting data from the transport container of a handle
To extract the handle, handle permissions mask, and pointer to the resource transfer context from the transport container of a handle, use the nk_get_handle()
, nk_get_rights()
and nk_get_badge_op()
(or nk_get_badge()
) functions, respectively, which are declared in the header file sysroot-*-kos/include/nk/types.h
from the KasperskyOS SDK. The nk_get_badge_op()
and nk_get_badge()
functions should be used only when dereferencing handles.
Handle transfer scenarios
The scenario for transferring handles from a client to the server includes the following steps:
- The client packages the handles and handle permissions masks into fields of the
*_req
IPC requests structure of thenk_handle_desc_t
type. - The client calls the interface method for transferring handles to the server. The
Call()
system call is executed when this method is called. - The server receives an IPC request by executing the
Recv()
system call. - The dispatcher on the server side calls the method corresponding to the IPC request. This method extracts the handles and handle permissions masks from fields of the
*_req
IPC request structure of thenk_handle_desc_t
type.
The scenario for transferring handles from the server to a client includes the following steps:
- The client calls the interface method for receiving handles from the server. The
Call()
system call is executed when this method is called. - The server receives an IPC request by executing the
Recv()
system call. - The dispatcher on the server side calls the method corresponding to the IPC request. This method packages the handles, handle permissions masks and resource transfer context object handles into fields of the
*_res
IPC response structure of thenk_handle_desc_t
type. - The server responds to the IPC request by executing the
Reply()
system call. - On the client side, the interface method returns control. After this, the client extracts the handles and handle permissions masks from fields of the
*_res
IPC response structure of thenk_handle_desc_t
type.
If the transferring process defines more access rights in the transferred handle permissions mask than the access rights defined for the transferred handle (which it owns), the transfer is not completed. In this case, the Call()
system call executed by the transferring or recipient client or the Reply()
system call executed by the transferring server ends with the rcSecurityDisallow
error.
Information about API functions
handle_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a resource transfer context object and configures a notification mechanism for monitoring the life cycle of this object. Parameters
Returned values If successful, the function returns Additional information The notification receiver is configured to receive notifications about events that match the |
Duplicating handles
Handle duplication is similar to a handle transfer, but duplication is performed within a process. A handle descendant is created in the same process and from the same handle space. The rights of the handle descendant may be less than or equal to the rights of the original handle. Handle duplication can be associated with a resource transfer context object. This lets you use the notification mechanism to track the closure or revocation of all handle descendants that form the handle inheritance subtree whose root node was generated by the duplication operation. It also provides the capability to revoke these descendants.
To duplicate a handle, call the KnHandleCopy()
function. To do so, the OCAP_HANDLE_COPY
flag must be set in the handle permissions mask.
Information about API functions is provided in the table below.
handle_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Duplicates a handle. As a result of duplication, the calling process receives the handle descendant. Parameters
Returned values If successful, the function returns |
Dereferencing handles
When dereferencing a handle, the client sends the handle to the server, and the server receives a pointer to the resource transfer context, the permissions mask of the sent handle, and the ancestor of the handle sent by the client and already owned by the server. Dereferencing occurs when a resource consumer that called methods for working with a resource (such as read/write or access closure) sends the resource provider the handle that was received from this resource provider when access to the resource was opened.
Dereferencing handles requires fulfillment of the same conditions and utilizes the same mechanisms and data types as when transferring handles. A handle dereferencing scenario includes the following steps:
- The client packages the handle into a field of the
*_req
IPC request structure of thenk_handle_desc_t
type. - The client calls the interface method for sending the handle to the server for the purpose of performing operations with the resource. The
Call()
system call is executed when this method is called. - The server receives the IPC request by executing the
Recv()
system call. - The dispatcher on the server side calls the method corresponding to the IPC request. This method verifies that the dereferencing operation was specifically executed instead of a handle transfer. Then the called method has the option to verify that the access rights of the dereferenced handle (that was sent by the client) permit the requested actions with the resource, and extracts the pointer to the resource transfer context from the field of the
*_req
request structure of thenk_handle_desc_t
type.
To perform verification, the server uses the nk_is_handle_dereferenced()
and nk_get_badge_op()
functions that are declared in the header file sysroot-*-kos/include/nk/types.h
from the KasperskyOS SDK.
types.h (fragment)
Generally, the server does not require the handle that was received from dereferencing because the server normally retains the handles that it owns, for example, within the contexts of user resources. However, the server can extract this handle from the handle transport container if necessary.
Page topRevoking handles
A process can revoke descendants of a handle that it owns. Handles are revoked according to the handle inheritance tree.
Revoked handles are not closed. However, you cannot query resources via revoked handles. Any function that receives the handle will end with the rcHandleRevoked
error if the function is called with a revoked handle.
To revoke handle descendants, call the KnHandleRevoke()
or KnHandleRevokeSubtree()
function. The KnHandleRevokeSubtree()
function uses the resource transfer context object that is created when transferring handles.
If each handle of a system resource in all processes that own these handles are closed (see "Closing handles") or revoked, this system resource will be deleted.
Information about API functions is provided in the table below.
handle_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Closes a handle and revokes its descendants. Parameters
Returned values If successful, the function returns |
|
Purpose Revokes the handles that make up the inheritance subtree of the specified handle. Parameters
Returned values If successful, the function returns |
Closing handles
A process can close the handles that it owns. Closing a handle terminates the association between an ID and a resource, thereby releasing the ID. Closing a handle does not invalidate its ancestors and descendants (in contrast to revoking a handle, which actually invalidates the descendants of the handle). In other words, the ancestors and descendants of a closed handle can still be used to provide access to the resource that they identify. Also, closing a handle does not disrupt the handle inheritance tree associated with the resource identified by the particular handle. The place of a closed handle is occupied by its ancestor. In other words, the ancestor of a closed handle becomes the direct ancestor of the descendants of the closed handle.
To close the handle, call the KnHandleClose()
function.
If each handle of a system resource in all processes that own these handles are revoked (see "Revoking handles") or closed, this system resource will be deleted.
Information about API functions is provided in the table below.
handle_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Closes a handle. Parameters
Returned values If successful, the function returns |
Getting a security ID (SID)
By getting the SID values for different handles, you can determine whether these handles identify different resources or the same resource.
To get an SID for a handle, call the KnHandleGetSidByHandle()
function. To do so, the OCAP_HANDLE_GET_SID
flag must be set in the handle permissions mask.
Information about API functions is provided in the table below.
handle_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Receives a security ID (SID) based on a handle. Parameters
Returned values If successful, the function returns |
OCap usage example
This example describes an OCap usage scenario in which the resource provider provides the following methods for accessing its resources:
OpenResource()
– opens access to the resource.UseResource()
– uses the resource.CloseResource()
– closes access to the resource.
The resource consumer uses these methods.
IDL description:
The scenario includes the following steps:
- The resource provider creates the user resource context and calls the
KnHandleCreateUserObject()
function to create the resource handle. The resource provider saves the resource handle in the user resource context. - The resource consumer calls the
OpenResource()
method to open access to the resource.- The resource provider creates the resource transfer context and calls the
KnHandleCreateBadge()
function to create a resource transfer context object and configure the notification receiver to receive notifications regarding the closure and deletion of the resource transfer context object. The resource provider saves the handle of the resource transfer context object and the pointer to the user resource context in the resource transfer context. - The resource provider uses the
nk_handle_desc()
macro to package the resource handle, permissions mask of the handle, and pointer to the resource transfer context object into the handle transport container. - The handle is transferred from the resource provider to the resource consumer, which means that the resource consumer receives a descendant of the handle owned by the resource provider.
- The
OpenResource()
method call completes successfully. The resource consumer extracts the handle and permissions mask of the handle from the handle transport container by using thenk_get_handle()
andnk_get_rights()
functions, respectively. The handle permissions mask is not required by the resource consumer to query the resource, but is transferred so that the resource consumer can find out its permissions for accessing the resource.
- The resource provider creates the resource transfer context and calls the
- The resource consumer calls the
UseResource()
method to utilize the resource.- The handle that was received from the resource provider at step 2 is used as a parameter of the
UseResource()
method. Before calling this method, the resource consumer uses thenk_handle_desc()
macro to package the handle into the handle transport container. - The handle is dereferenced, after which the resource provider receives the pointer to the resource transfer context.
- The resource provider uses the
nk_is_handle_dereferenced()
function to verify that the dereferencing operation was completed instead of a handle transfer. - The resource provider verifies that the access rights of the dereferenced handle (that was sent by the resource consumer) allows the requested operation with the resource, and extracts the pointer to the resource transfer context from the handle transport container. To do so, the resource provider uses the
nk_get_badge_op()
function, which extracts the pointer to the resource transfer context from the handle transport container if the received permissions mask has the corresponding flags set for the requested operation. - The resource provider uses the resource transfer context and the user resource context to perform the corresponding operation with the resource as requested by the resource consumer. Then the resource provider sends the results of this operation to the resource consumer.
- The
UseResource()
method call completes successfully. The resource consumer receives the results of the operation performed with the resource.
- The handle that was received from the resource provider at step 2 is used as a parameter of the
- The resource consumer calls the
CloseResource()
method to close access to the resource.- The handle that was received from the resource provider at step 2 is used as a parameter of the
CloseResource()
method. Before calling this method, the resource consumer uses thenk_handle_desc()
macro to package the handle into the handle transport container. After theCloseResource()
method is called, the resource consumer uses theKnHandleClose()
function to close the handle. - The handle is dereferenced, after which the resource provider receives the pointer to the resource transfer context.
- The resource provider uses the
nk_is_handle_dereferenced()
function to verify that the dereferencing operation was completed instead of a handle transfer. - The resource provider uses the
nk_get_badge()
function to extract the pointer to the resource transfer context from the handle transport container. - The resource provider uses the
KnHandleRevokeSubtree()
function to revoke the handle owned by the resource consumer. The resource handle owned by the resource provider and the handle of the resource transfer context object are used as parameters of this function. The resource provider obtains access to these handles through the pointer to the resource transfer context. (Technically, the handle owned by the resource consumer does not have to be revoked because the resource consumer already closed it. However, the revoke operation is performed in case the resource provider is not sure if the resource consumer actually closed the handle). - The
CloseResource()
method call completes successfully.
- The handle that was received from the resource provider at step 2 is used as a parameter of the
- The resource provider frees up the memory that was allocated for the resource transfer context and user resource context.
- The resource provider calls the
KnNoticeGetEvent()
function to receive a notification that the resource transfer context object was closed, and uses theKnHandleClose()
function to close the handle of the resource transfer context object. - The resource provider calls the
KnNoticeGetEvent()
function to receive a notification that the resource transfer context object was deleted, and frees up the memory that was allocated for the resource transfer context. - The resource provider uses the
KnHandleClose()
function to close the resource handle and free up the memory that was allocated for the user resource context.
- The resource provider calls the
Allocating and freeing memory (alloc.h)
The API is defined in the header file sysroot-*-kos/include/kos/alloc.h
from the KasperskyOS SDK.
The API is intended for allocating and freeing memory. Allocated memory is a committed virtual memory region that can be accessed for read-and-write operations.
Information about API functions is provided in the table below.
alloc.h functions
Function |
Information about the function |
---|---|
|
Purpose Allocates memory. Parameters
Returned values If successful, the function returns the pointer to the allocated memory, otherwise it returns |
|
Purpose Allocates memory. Parameters
Returned values If successful, the function returns the pointer to the allocated memory, otherwise it returns |
|
Purpose Allocates memory and initializes it with zeros. Parameters
Returned values If successful, the function returns the pointer to the allocated memory, otherwise it returns |
|
Purpose Deallocates memory. Parameters
Returned values N/A |
|
Purpose Gets the actual size of allocated memory. The actual size of allocated memory exceeds the requested size because it includes the size of service data and also may be increased due to alignment when the Parameters
Returned values Actual size of allocated memory (in bytes). |
|
Purpose Gets the size of memory that was requested when it is allocated. The actual size of allocated memory exceeds the requested size because it includes the size of service data and also may be increased due to alignment when the Parameters
Returned values Size (in bytes) of memory that was requested when it is allocated. |
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()
function call.The
KnIoDmaBegin()
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, an object contains virtual addresses of blocks. Otherwise, an object contains physical addresses of blocks.A handle received when calling the
KnIoDmaBegin()
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()
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 (if IOMMU is enabled, a device on the PCIe bus must be attached to the IOMMU domain).To complete this step, you need to call the
KnIoDmaGetInfo()
orKnIoDmaContinuousGetDmaAddr()
function. TheKnIoDmaGetInfo()
function gets 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.) TheKnIoDmaContinuousGetDmaAddr()
function can be used if the DMA buffer consists of one block. This function gets the block address. (The accepted block size should be the DMA buffer size that was defined when this buffer was created.)
Closing access to the DMA buffer for a device
If you delete the kernel object that was created when the KnIoDmaBegin()
function was called and IOMMU is enabled, the device will be denied access to the DMA buffer. To delete this object, call the KnHandleClose()
function and specify the handle that was received when the KnIoDmaBegin()
function was called. (The KnHandleClose()
function is declared in the header file sysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.)
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, use the
KnHandleClose()
function and specify the handles that were received fromKnIoDmaMap()
function calls. (KnHandleClose()
function is declared in the header filesysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.)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()
function call.To complete this step, call the
KnHandleClose()
function and specify the handle that was received when theKnIoDmaBegin()
function was called. - Close or revoke each DMA buffer handle in all processes that own these handles.
To complete this step, use the
KnHandleClose()
and/orKnHandleRevoke()
functions that are declared in the header filesysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.
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 |
|
Purpose Gets the block 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 |
Managing interrupt processing (irq.h)
The API is defined in the header file sysroot-*-kos/include/coresrv/io/irq.h
from the KasperskyOS SDK.
The API manages the handling of hardware interrupts. A hardware interrupt is a signal sent from a device to direct the processor to immediately pause execution of the current program and instead handle an event related to this device. For example, pressing a key on the keyboard invokes a hardware interrupt that ensures the required response to this pressed key (for example, input of a character).
A hardware interrupt occurs when the device queries the interrupt controller. This query can be transmitted through a hardware interrupt line between the device and the interrupt controller or through MMIO memory. In the second case, the device writes to MMIO memory by calling the Message Signaled Interrupt (MSI).
At present, no functions for managing the handling of MSI interrupts have been implemented.
Each hardware interrupt line corresponds to one interrupt with a unique number.
Information about API functions is provided in the table below.
Using the API
To attach an interrupt to its handler, complete the following steps:
- Registering an interrupt by calling the
KnRegisterIrq()
function.One interrupt can be registered multiple times in one or more processes.
The handle of an interrupt can be transferred to another process via IPC.
- Attaching a thread to an interrupt by calling the
KnIoAttachIrq()
function.This step is performed by the thread in whose context the interrupt will be handled.
When using the handle received from the
KnRegisterIrq()
function call, you can attach only one thread to an interrupt. To attach multiple threads in one or more processes to an interrupt, use different handles for this interrupt received from separateKnRegisterIrq()
function calls. In this case, theKnIoAttachIrq()
function must be called with the same flags in theflags
parameter.A handle received when calling the
KnIoAttachIrq()
function cannot be transferred to another process via IPC.
To deny (mask) an interrupt, call the KnIoDisableIrq()
function. To allow (unmask) an interrupt, call the KnIoEnableIrq()
function. Even though these functions receive an interrupt handle that is used to attach only one thread to the interrupt, their action is applied to all threads that are attached to this interrupt. These functions must be called outside of the threads attached to the interrupt. After an interrupt is registered and a thread is attached to it, this interrupt does not require unmasking.
To initiate detachment of a thread from an interrupt, call the KnIoDetachIrq()
function outside of the thread that is attached to the interrupt. Detachment is performed by the thread attached to the interrupt by calling the KnThreadDetachIrq()
function declared in the header file sysroot-*-kos/include/coresrv/thread/thread_api.h
from the KasperskyOS SDK.
Handling an interrupt
After attaching to an interrupt, a thread calls the Call()
function declared in the header file sysroot-*-kos/include/coresrv/syscalls.h
from the KasperskyOS SDK. The thread is locked as a result of this call. When an interrupt occurs or the KnIoDetachIrq()
function is called, the KasperskyOS kernel sends an IPC message to the process that contains this thread. This IPC message contains a request to handle the interrupt or a request to detach the thread from the interrupt. When a process receives an IPC message, the Call()
function in the thread attached to the interrupt returns control and provides the contents of the IPC message to the thread. The thread extracts the request from the IPC message and either processes the interrupt or detaches from the interrupt. If the interrupt is processed, information about its failure or success upon completion is added to the response IPC message that is sent to the kernel by the next Call()
function call in the loop.
When processing an interrupt, use the IoGetIrqRequest()
and IoSetIrqAnswer()
functions that are declared in the header file sysroot-*-kos/include/io/io_irq.h
from the KasperskyOS SDK. These functions let you extract data from IPC messages and add data to IPC messages for data exchange between the kernel and the thread attached to the interrupt.
The standard interrupt processing loop includes the following steps:
- Adding information about the failure or success of interrupt processing to an IPC message by calling the
IoSetIrqAnswer()
function. - Sending the IPC message to the kernel and receiving an IPC message from the kernel.
To complete this step, call the
Call()
functions. In thehandle
parameter, you must specify the handle that was received when theKnIoAttachIrq()
function was called. You must use themsgOut
parameter to define the IPC message that will be sent to the kernel, and use themsgIn
parameter to define the IPC message that will be received from the kernel. - Extracting a request from the IPC message received from the kernel by calling the
IoGetIrqRequest()
function. - Processing the interrupt or detaching from the interrupt depending on the request.
If the request requires detachment from the interrupt, exit the interrupt processing loop and call the
KnThreadDetachIrq()
function.
Deregistering an interrupt
To deregister an interrupt, complete the following steps:
- Detach the thread from the interrupt.
To complete this step, call the
KnThreadDetachIrq()
function. - Close the handle that was received when the
KnIoAttachIrq()
function was called.To complete this step, call the
KnHandleClose()
function. (TheKnHandleClose()
function is declared in the header filesysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.) - Close or revoke each interrupt handle in all processes that own these handles.
To complete this step, use the
KnHandleClose()
and/orKnHandleRevoke()
functions that are declared in the header filesysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.
One interrupt can be registered multiple times, but completion of these steps cancels only one registration. The other registrations will remain active. Each registration of one interrupt must be canceled separately.
Information about API functions
irq.h functions
Function |
Information about the function |
---|---|
|
Purpose Registers an interrupt. Parameters
Returned values If successful, the function returns |
|
Purpose Attaches the calling thread to an interrupt. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Sends a request to a thread. When this request is fulfilled, the thread must detach from the interrupt. Parameters
Returned values If successful, the function returns |
|
Purpose Allows (unmasks) an interrupt. Parameters
Returned values If successful, the function returns |
|
Purpose Denies (masks) an interrupt. Parameters
Returned values If successful, the function returns |
Initializing IPC transport for interprocess communication and managing IPC request processing (transport-kos.h, transport-kos-dispatch.h)
APIs are defined in the header files transport-kos.h
and transport-kos-dispatch.h
from the KasperskyOS SDK that are located at the path sysroot-*-kos/include/coresrv/nk
.
API capabilities:
- Initialize IPC transport on the client side and on the server side.
IPC transport is an add-on that works on top of system calls for sending and receiving IPC messages and works separately with the constant part and arena of IPC messages. Transport code works on top of this add-on.
- Start the loop for processing IPC requests on the server side.
- Copy data to the IPC message arena.
Information about API functions is provided in the tables below.
This section contains API usage examples. In these examples, programs acting as servers have the following formal specification:
FsDriver.edl
Operations.cdl
FileIface.idl
Initializing IPC transport for interprocess communication
To initialize IPC transport for interaction with other processes, call the NkKosTransport_Init()
or NkKosTransportSync_Init()
function declared in the header file transport-kos.h
.
Example use of the NkKosTransport_Init()
function on the client side:
If a client needs to use several endpoints, the same number of proxy objects must be initialized. When initializing each proxy object, you need to specify the IPC transport that is associated through the client IPC handle with the relevant server. When initializing multiple proxy objects pertaining to the endpoints of one server, you can specify the same IPC transport that is associated with this server.
Example use of the NkKosTransport_Init()
function on the server side:
If a server processes IPC requests received through multiple IPC channels, the following special considerations should be taken into account:
- If a listener handle is associated with all IPC channels, IPC interaction with all clients can use the same IPC transport associated with this listener handle.
- If IPC channels are associated with different listener handles, IPC interaction with each group of clients corresponding to the same listener handle must use a separate IPC transport associated with this listener handle. In this case, IPC requests can be processed in parallel threads if you are using a thread-safe implementation of endpoint methods.
The NkKosTransportSync_Init()
function initializes IPC transport with support for interrupting the Call()
and Recv()
locking system calls. (For example, an interrupt of these calls may be required for correct termination of the process that is executing them.) To interrupt the Call()
and Recv()
system calls, use the API ipc_api.h.
The NkKosSetTransportTimeouts()
function declared in the header file transport-kos.h
defines the maximum lockout duration for Call()
and Recv()
system calls used for IPC transport.
Starting the IPC request processing loop
The IPC request processing loop on a server includes the following steps:
- Receive an IPC request.
- Process the IPC request.
- Send an IPC response.
Each step of this loop can be completed separately by sequentially calling the nk_transport_recv()
, dispatcher, and nk_transport_reply()
functions. (The nk_transport_recv()
and nk_transport_reply()
functions are declared in the header file sysroot-*-kos/include/nk/transport.h
from the KasperskyOS SDK.) You can also call the NkKosTransport_Dispatch()
or NkKosDoDispatch()
function in which this loop is completed in its entirety. (The NkKosTransport_Dispatch()
and NkKosDoDispatch()
functions are declared in the header files transport-kos.h
and transport-kos-dispatch.h
, respectively.) It is more convenient to use the NkKosDoDispatch()
function because it requires fewer preparatory operations (for example, you do not need to initialize IPC transport).
You can initialize the structure passed to the NkKosDoDispatch()
function through the info
parameter by using the macros defined in the header file transport-kos-dispatch.h
.
The NkKosTransport_Dispatch()
and NkKosDoDispatch()
functions can be called from parallel threads if you are using a thread-safe implementation of endpoint methods.
Example use of the NkKosDoDispatch()
function:
Example use of the NkKosTransport_Dispatch()
function:
Copying data to the IPC message arena
To copy a string to the IPC message arena, call the NkKosCopyStringToArena()
function declared in the header file transport-kos.h
. This function reserves a segment of the arena and copies a string to this segment.
Example use of the NkKosCopyStringToArena()
function:
Information about API functions
transport-kos.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes IPC transport. Parameters
Returned values N/A |
|
Purpose Initializes IPC transport with support for interrupting the Parameters
Returned values N/A |
|
Purpose Defines the maximum lockout duration for Parameters
Returned values N/A |
|
Purpose Starts the IPC request processing loop. Parameters
Returned values If unsuccessful, it returns an error code. |
|
Purpose Reserves a segment of the arena and copies a string to this segment. Parameters
Returned values If successful, the function returns |
transport-kos-dispatch.h functions
Function |
Information about the function |
---|---|
|
Purpose Starts the IPC request processing loop. Parameters
Returned values N/A |
Initializing IPC transport for querying the security module (transport-kos-security.h)
The API is defined in the header file sysroot-*-kos/include/coresrv/nk/transport-kos-security.h
from the KasperskyOS SDK.
The API initializes IPC transport for querying the Kaspersky Security Module via the security interface. Transport code works on top of IPC transport.
Information about API functions is provided in the table below.
This section contains an API usage example. In this example, the program that queries the security module has the following formal specification:
Verifier.edl
Approve.idl
Fragment of the policy description in the example:
security.psl
Using the API
To initialize IPC transport for querying the security module, call the NkKosSecurityTransport_Init()
function.
Example use of the NkKosSecurityTransport_Init()
function:
If a process needs to use several security interfaces, the same number of proxy objects must be initialized by specifying the same IPC transport and the unique IDs of the security interfaces.
Information about API functions
transport-kos-security.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes IPC transport for querying the Kaspersky Security Module through the security interface. Parameters
Returned values If successful, the function returns |
Generating random numbers (random_api.h)
The API is defined in the header file sysroot-*-kos/include/kos/random/random_api.h
from the KasperskyOS SDK.
The API generates random numbers and includes functions that can be used to ensure high entropy (high level of unpredictability) of the seed value of the random number generator. The start number of the random number generator (seed) determines the sequence of the generated random numbers. In other words, if the same seed value is set, the generator creates identical sequences of random numbers. (The entropy of these numbers is fully determined by the entropy of the seed value, which means that these numbers are not entirely random, but pseudorandom.)
The random number generator of one process does not depend on the random number generators of other processes.
Information about API functions is provided in the table below.
Using the API
To generate a sequence of random byte values, call the KosRandomGenerate()
or KosRandomGenerateEx()
function.
Example use of the KosRandomGenerate()
function:
The KosRandomGenerateEx()
function gets the quality level of the generated random values through the output parameter quality
. The quality level can be high or low. High-quality random values are random values that are generated while fulfilling all of the following conditions:
- When the seed value is changed, at least one entropy source is registered and data is successfully received from all registered entropy sources.
To register the entropy source, call the
KosRandomRegisterSrc()
function. This function uses thecallback
parameter to receive the pointer to a callback function of the following type:typedef Retcode (*KosRandomSeedMethod)(void *context, rtl_size_t size, void *output);Using the
context
parameters, this callback function receives data with the specifiedsize
of bytes from the entropy source and writes this data to theoutput
buffer. If the function returnsrcOk
, it is assumed that data was successfully received from the entropy source. An entropy source can be a digitalized signal of a sensor or a hardware-based random number generator, for example.To deregister an entropy source, call the
KosRandomUnregisterSrc()
function. - The random number generator is initialized if the quality level was low before changing the seed value while fulfilling condition 1.
If the quality level is low, it cannot be changed to high without initializing the random number generator.
To initialize a random number generator, call the
KosRandomInitSeed()
function. The entropy of data passed through theseed
parameter must be guaranteed by the calling process. - The counter of random byte values that were generated after changing the seed value while fulfilling condition 1 does not exceed the system-defined limit.
- The counter of time that has elapsed since changing the seed value while fulfilling condition 1 does not exceed the system-defined limit.
If at least one of these conditions is not fulfilled, the generated random values are deemed low-quality values.
When a process is started, the seed value is automatically defined by the system. Then the seed value is modified when doing the following:
- Generating a sequence of random values.
Each successful call of the
KosRandomGenerateEx()
function with thesize
parameter greater than zero and each successful call of theKosRandomGenerate()
function results in a change of the seed value of the random number generator, but not each seed change results in the receipt of data from registered entropy sources. The registered entropy sources are used only when condition 3 or 4 is not fulfilled. If at least one entropy source is registered, the time counter for the change in the seed value is reset. If data from at least one entropy source is successfully received, the counter of generated random byte values is also reset.The quality level may change from high to low.
- Initializing a random number generator.
Each successful call of the
KosRandomInitSeed()
function changes the seed value by using the data that is passed through theseed
parameter and received from registered entropy sources. If at least one registered entropy source is available, the counters for generated byte values and the time of a change in the seed value are reset. Otherwise, only the counter of generated random byte values is reset.The quality level may change from high to low, and vice versa.
- Registering an entropy source.
Each successful call of the
KosRandomRegisterSrc()
function changes the seed value by using the data only from the registered entropy source. The counter of the generated random byte values is also reset.The quality level may not change.
A possible scenario for generating high-quality random values includes the following steps:
- Register at least one source of entropy by calling the
KosRandomRegisterSrc()
function. - Generate a sequence of random values by calling the
KosRandomGenerateEx()
function. - Check the quality level of the random values.
If the quality level is low, initialize the random number generator by calling the
KosRandomInitSeed()
function, and proceed to step 2.If the quality level is high, proceed to step 4.
- Use random values.
To get the quality level without generating random values, call the KosRandomGenerateEx()
function with the values 0
and RTL_NULL
in the size
and output
parameters, respectively.
Information about API functions
random_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes the random number generator. Parameters
Returned values If successful, the function returns |
|
Purpose Generates a sequence of random byte values. Parameters
Returned values If successful, the function returns |
|
Purpose Generates a sequence of random byte values. Parameters
Returned values If successful, the function returns |
|
Purpose Registers an entropy source. Parameters
Returned values If successful, the function returns |
|
Purpose Deregisters the source of entropy. Parameters
Returned values If successful, the function returns |
Getting and changing time values (time_api.h)
The API is defined in the header file sysroot-*-kos/include/coresrv/time/time_api.h
from the KasperskyOS SDK.
Main capabilities of the API:
- Get and modify the system time
- Get the monotonic time that has elapsed since the moment the KasperskyOS kernel was started
- Get the resolution of the sources of system time and monotonic time
Information about API functions is provided in the table below.
time_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Gets the resolution of the system time source. Parameters
Returned values If successful, the function returns |
|
Purpose Sets the system time. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the system time. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the resolution of the source of monotonic time that has elapsed since the KasperskyOS kernel was started. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the monotonic time that has elapsed since the moment the KasperskyOS kernel was started. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the system time. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the monotonic time that has elapsed since the moment the KasperskyOS kernel was started. Parameters N/A Returned values Monotonic time (in milliseconds) that has elapsed since the KasperskyOS kernel was started. |
|
Purpose Starts gradual adjustment of the system time. Parameters
Returned values If successful, the function returns Additional information If a new adjustment is started before a previously running adjustment is finished, the previously running adjustment is interrupted. |
Using notifications (notice_api.h)
The API is defined in the sysroot-*-kos/include/coresrv/handle/notice_api.h
header file from the KasperskyOS SDK.
The API can track events that occur to (both system and user) resources, and inform other processes and threads about events involving user resources.
Information about API functions is provided in the table below.
Using the API
The notification mechanism uses an event mask. An event mask is a value whose bits are interpreted as events that should be tracked or that have already occurred. An event mask has a size of 32 bits and consists of a general part and a specialized part. The common part describes events that are not specific to any resources. The specialized part describes events that are specific to certain resources. Specialized part flags for system resources and common part flags are defined in the sysroot-*-kos/include/handle/event_descr.h
header file from KasperskyOS SDK. (For example, the common part flag EVENT_OBJECT_DESTROYED
signifies resource termination, and the specialized part flag EVENT_TASK_COMPLETED
signifies process termination.) Specialized part flags for a user resource are defined by the resource provider with the help of the OBJECT_EVENT_SPEC()
and OBJECT_EVENT_USER()
macros, which are defined in the sysroot-*-kos/include/handle/event_descr.h
header file from the KasperskyOS SDK. The resource provider must export the public header files describing the flags of the specialized part.
The standard scenario for receiving notifications about events occurring to resources consists of the following steps:
- Creating a notification receiver (KasperskyOS kernel object that collects notifications) by calling the
KnNoticeCreate()
function. - Adding "resource—event mask" entries to the notification receiver to configure it to get notifications about events that occur to relevant resources.
To add a "resource—event mask" entry to the notification receiver, you need to call the
KnNoticeSubscribeToObject()
function. (TheOCAP_HANDLE_GET_EVENT
flag should be set in the handle permissions mask of the resource stated in theobject
parameter.) Several "resource—event mask" entries can be added for one resource, and the entry identifiers do not need to be unique. Tracked events for each "resource—event mask" entry should be defined with an event mask that may match one or several events."Resource—event mask" entries added to the notification receiver can be fully or partially removed to prevent the receiver from getting notifications that match these entries. To remove all "resource—event mask" entries from the receiver, you need to call the
KnNoticeDropAndWake()
function. To remove from the receiver "resource—event mask" entries that refer to the same resource, you need to call theKnNoticeUnsubscribeFromObject()
function. To remove from the receiver a "resource—event mask" entry with a specific identifier, you need to call theKnNoticeUnsubscribeFromEvent()
function."Resource—event mask" entries can be added to, or removed from, the notification receiver throughout its life cycle.
- Extracting notifications from the receiver with the
KnNoticeGetEvent()
function.You can set the time-out for notifications to appear in the receiver when calling the
KnNoticeGetEvent()
function. Threads that are locked while waiting for notifications to appear in the receiver will resume when notifications appear, even if these notifications match "resource—event mask" entries added after wait start.Threads that are locked while waiting for notifications to appear in the receiver will resume if all "resource—event mask" entries are removed from the receiver by calling the
KnNoticeDropAndWake()
function. If you add at least one "resource—event mask" entry to the notification receiver after calling theKnNoticeDropAndWake()
function, threads that get notifications from that receiver will be locked again when calling theKnNoticeGetEvent()
function for the specified time-out duration as long as there are no notifications. If all "resource—event mask" entries are removed from the notification receiver with theKnNoticeUnsubscribeFromObject()
and/orKnNoticeUnsubscribeFromEvent()
functions, threads waiting for notifications to appear in the receiver will not resume until the time-out elapses. - Removing a notification receiver by calling the
KnNoticeRelease()
function.Threads that are locked while waiting for notifications to appear in the receiver will resume when the receiver is removed by calling the
KnNoticeRelease()
function.
To notify other processes and/or threads about events that occurred to the user resource, you need to call the KnNoticeSetObjectEvent()
function. Calling the function results in notifications appearing in receivers configured to get events defined with the evMask
parameter that occur to the user resource defined with the object
parameter. You cannot set flags of the general part of an event mask in the evMask
parameter, because only the kernel can signal about events that match the general part of an event mask. If the process calling the KnNoticeSetObjectEvent()
function created the user resource handle stated in the object
parameter, you can set flags defined by the OBJECT_EVENT_SPEC()
and OBJECT_EVENT_USER()
macros in the evMask
parameter. If the process calling the KnNoticeSetObjectEvent()
function received the user resource handle stated in the object
parameter from another process, you can set only those flags defined by the OBJECT_EVENT_USER()
macro in the evMask
parameter, while the permissions mask of the resulting handle must have a OCAP_HANDLE_SET_EVENT
flag set.
Information about API functions
notice_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a notification receiver. Parameters
Returned values If successful, the function returns |
|
Purpose Adds a "resource–event mask" entry to the notification receiver so that it can receive notifications about events that occur with the defined resource and match the defined event mask. Parameters
Returned values If successful, the function returns |
|
Purpose Extracts notifications from the receiver. Parameters
Returned values If successful, the function returns If the time-out for notifications to appear in the receiver has elapsed, returns If the time-out for notifications appear in the receiver is interrupted by a call to the |
|
Purpose Removes from the notification receiver "resource—event mask" entries that match the specified resource to prevent the receiver from getting notifications about events that match these entries. Parameters
Returned values If successful, the function returns Additional information Notifications that correspond to the removed "resource—event mask" entries will be removed from the receiver. |
|
Purpose Removes from the notification receiver "resource—event mask" entries with the specified identifier to prevent the receiver from getting notifications about events that match these entries. Parameters
Returned values If successful, the function returns Additional information Notifications that correspond to the removed "resource—event mask" entries will be removed from the receiver. |
|
Purpose Removes all "resource—event mask" entries from the specified notification receiver and resumes all threads that are waiting for notifications to appear in the specified receiver. Parameters
Returned values If successful, the function returns |
|
Purpose Removes the specified notification receiver and resumes all threads that are waiting for notifications to appear in the specified receiver. Parameters
Returned values If successful, the function returns |
|
Purpose Signals that events matching the specified event mask occurred to the specified user resource. Parameters
Returned values If successful, the function returns |
Dynamically creating IPC channels (cm_api.h, ns_api.h)
APIs are defined in the header files from the KasperskyOS SDK:
sysroot-*-kos/include/coresrv/cm/cm_api.h
sysroot-*-kos/include/coresrv/ns/ns_api.h
The API dynamically creates IPC channels.
Information about API functions is provided in the tables below.
Using the API
To ensure that servers can notify clients about the endpoints that they provide, the solution should include a name server, which is provided by the NameServer
system program (executable file sysroot-*-kos/bin/ns
from the KasperskyOS SDK). IPC channels from clients and servers to a name server can be statically created (these IPC channels must be named kl.core.NameServer
). If this is not done, attempts will be made to dynamically create these IPC channels whenever clients and servers call the NsCreate()
function. A name server does not have to be included in a solution if the clients initially already have information about the names of servers and the endpoints provided by these servers.
The names of endpoints and interfaces should be defined according to the formal specifications of solution components. (For information about the qualified name of an endpoint, see "Binding methods of security models to security events") Instead of the qualified name of an endpoint, you can use any conditional name of this endpoint. The names of clients and servers are defined in the init description. You can also get a process name by calling the KnTaskGetName()
function from the API task_api.h.
Dynamic creation of an IPC channel on the server side includes the following steps:
- Connect to the name server by calling the
NsCreate()
function. - Publish the provided endpoints on the name server by using the
NsPublishService()
function.To unpublish an endpoint, call the
NsUnPublishService()
function. - Receive a client request to create an IPC channel by calling the
KnCmListen()
function.The
KnCmListen()
function gets the first request in the queue without deleting this request but instead putting it at the end of the queue. If there is only one request in the queue, multiple consecutive calls of theKnCmListen()
function will provide the same result. A request is deleted from the queue when theKnCmAccept()
orKnCmDrop()
function is called. - You can accept a client request to create an IPC channel by calling the
KnCmAccept()
function.To decline a client request, call the
KnCmDrop()
function.A listener handle is created when the
KnCmAccept()
function is called with theINVALID_HANDLE
value in thelistener
parameter. If a listener handle is specified, the created server IPC handle will provide the capability to receive IPC requests over all IPC channels associated with this listener handle. (The first IPC channel associated with the listener handle is created when theKnCmAccept()
function is called with theINVALID_HANDLE
value in thelistener
parameter. The second and subsequent IPC channels associated with the listener handle are created during the second and subsequent calls of theKnCmAccept()
function specifying the handle that was obtained during the first call.) In thelistener
parameter of theKnCmAccept()
function, you can specify the listener handle received using theKnHandleConnect()
,KnHandleConnectEx()
andKnHandleCreateListener()
functions from the API handle_api.h, and theServiceLocatorRegister()
function declared in the header filesysroot-*-kos/include/coresrv/sl/sl_api.h
from the KasperskyOS SDK.
Dynamic creation of an IPC channel on the client side includes the following steps:
- Connect to the name server by calling the
NsCreate()
function. - Find the server providing the required endpoint by using the
NsEnumServices()
function.To get a full list of endpoints with a defined interface, call the function several times while incrementing the index until you receive the
rcResourceNotFound
error. - Fulfill the request to create an IPC channel with the necessary server by calling the
KnCmConnect()
function.
You can connect multiple clients and servers to the name server. Each client and server can create multiple connections to the name server. A server can unpublish an endpoint that was published by another server.
Deleting dynamically created IPC channels
A dynamically created IPC channel will be deleted when its client IPC handle and server IPC handle are closed.
Information about API functions
ns_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a connection to a name server. Parameters
Returned values If successful, the function returns |
|
Purpose Publishes an endpoint on a name server. Parameters
Returned values If successful, the function returns |
|
Purpose Unpublishes an endpoint on a name server. Parameters
Returned values If successful, the function returns |
|
Purpose Enumerates the endpoints published on a name server. Parameters
Returned values If successful, the function returns |
cm_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Requests to create an IPC channel with a server for use of the defined endpoint. Parameters
Returned values If successful, the function returns |
|
Purpose Receives a client request to create an IPC channel for use of an endpoint. Parameters
Returned values If successful, the function returns |
|
Purpose Rejects a client request to create an IPC channel for use of the defined endpoint. Parameters
Returned values If successful, the function returns |
|
Purpose Accepts a client request to create an IPC channel for use of the defined endpoint. Parameters
Returned values If successful, the function returns |
Using synchronization primitives (event.h, mutex.h, rwlock.h, semaphore.h, condvar.h)
The libkos
library provides APIs that enable use of the following synchronization primitives:
- Events (
event.h
) - Mutexes (
mutex.h
) - Read-write locks (
rwlock.h
) - Semaphores (
semaphore.h
) - Conditional variables (
condvar.h
)
The header files are located in the KasperskyOS SDK at sysroot-*-kos/include/kos
.
The APIs are intended for synchronizing threads that belong to the same process.
Events
An event is a synchronization primitive that is used to notify one or more threads about the fulfillment of a condition required by these threads. The notified thread waits for the event to switch from a non-signaling state to a signaling state, and the notifying thread changes the state of this event.
The standard API usage scenario for working with events includes the following steps:
- An event is initialized via the
KosEventInit()
function call. - The event is used by threads:
- The notified threads wait for the event to switch from non-signaling state to signaling state via the
KosEventWait()
orKosEventWaitTimeout()
function call. - The notifying threads change the state of the event via the
KosEventSet()
andKosEventReset()
function calls.
- The notified threads wait for the event to switch from non-signaling state to signaling state via the
Information about the API event functions is provided in the table below.
event.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes an event. The event is in a non-signaling state after it is initialized. Parameters
Returned values N/A |
|
Purpose Sets the event state to signaling. Parameters
Returned values N/A |
|
Purpose Sets the event state to non-signaling. Parameters
Returned values N/A |
|
Purpose Waits for the event to change its state from non-signaling to signaling. Parameters
Returned values N/A |
|
Purpose Waits on the event to change its state from non-signaling to signaling for a period that does not exceed the specified time. Parameters
Returned values If successful, the function returns Returns |
Mutexes
A mutex is a synchronization primitive that ensures mutually exclusive execution of critical sections (areas of code where resources shared between threads are queried). One thread captures the mutex and executes a critical section. Meanwhile, other threads wait for the mutex to be freed and attempt to capture this mutex to execute other critical sections. A mutex can be freed only by the specific thread that captured it. You can use a recursive mutex, which can be captured by the same thread multiple times.
The standard API usage scenario for working with mutexes includes the following steps:
- A mutex is initialized via the
KosMutexInit()
orKosMutexInitEx()
function call. - The mutex is used by threads:
- The mutex is captured via the
KosMutexTryLock()
,KosMutexLock()
orKosMutexLockTimeout()
function call. - The mutex is freed via the
KosMutexUnlock()
function call.
- The mutex is captured via the
Information about the API mutex functions is provided in the table below.
mutex.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes a non-recursive mutex. Parameters
Returned values N/A |
|
Purpose Initializes a mutex. Parameters
Returned values N/A |
|
Purpose Acquires the mutex. If the mutex is already acquired, returns control rather than waits for the mutex to be released. Parameters
Returned values If successful, the function returns If the mutex is already acquired, returns |
|
Purpose Acquires the mutex. If the mutex is already acquired, waits indefinitely for it to be released. Parameters
Returned values N/A |
|
Purpose Releases the mutex. Parameters
Returned values N/A |
|
Purpose Acquires the mutex. If the mutex is already acquired, waits for it to be released for a period that does not exceed the specified time. Parameters
Returned values If successful, the function returns Returns |
Read-write locks
A read-write lock is a synchronization primitive used to allow access to resources shared between threads: write access for one thread or read access for multiple threads at the same time.
The standard API usage scenario for working with read-write locks includes the following steps:
- A read-write lock is initialized by the
KosRWLockInit()
function call. - The read-write lock is used by threads:
- The read-write lock is captured for write operations (via the
KosRWLockWrite()
orKosRWLockTryWrite()
function call) or for read operations (via theKosRWLockRead()
orKosRWLockTryRead()
function call). - The read-write lock is freed via the
KosRWLockUnlock()
function call.
- The read-write lock is captured for write operations (via the
Information about the API read-write lock functions is provided in the table below.
rwlock.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes a read-write lock. Parameters
Returned values N/A |
|
Purpose Acquires a read-write lock for reading. If the read-write lock is already acquired for writing, or if there are threads waiting on the lock to be acquired for writing, waits indefinitely for the lock to be released. Parameters
Returned values N/A |
|
Purpose Acquires the read-write lock for reading. If the read-write lock is already acquired for writing, or if there are threads waiting on the lock to be acquired for writing, returns control, rather than waits for the lock to be released. Parameters
Returned values If successful, the function returns |
|
Purpose Acquires the read-write lock for writing. If the read-write lock is already acquired for writing or reading, waits indefinitely for the lock to be released. Parameters
Returned values N/A |
|
Purpose Acquires the read-write lock for writing. If the read-write lock is already acquired for writing or reading, returns control, rather than waits for the lock to be released. Parameters
Returned values If successful, the function returns |
|
Purpose Releases the read-write lock. Parameters
Returned values N/A Additional information If the read-write lock is acquired for reading, it remains acquired for reading until released by every reading thread. |
Semaphores
A semaphore is a synchronization primitive that is based on a counter whose value can be atomically modified. The value of the counter normally reflects the number of available resources shared between threads. To execute a critical section, the thread waits until the counter value becomes greater than zero. If the counter value is greater than zero, it is decremented by one and the thread executes the critical section. After the critical section is executed, the thread signals the semaphore and the counter value is increased.
The standard API usage scenario for working with semaphores includes the following steps:
- A semaphore is initialized via the
KosSemaphoreInit()
function call. - The semaphore is used by threads:
- They wait for the semaphore via the
KosSemaphoreWait()
,KosSemaphoreWaitTimeout()
orKosSemaphoreTryWait()
function call. - The semaphore is signaled via the
KosSemaphoreSignal()
orKosSemaphoreSignalN()
function call.
- They wait for the semaphore via the
- Deallocating semaphore resources by calling the
KosSemaphoreDeinit()
function.
Information about the API semaphore functions is provided in the table below.
semaphore.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes a semaphore. Parameters
Returned values If successful, the function returns If the value of the |
|
Purpose Deallocates semaphore resources. Parameters
Returned values If successful, the function returns If there are threads waiting on the semaphore, returns |
|
Purpose Signals the semaphore and increases the counter by one. Parameters
Returned values If successful, the function returns |
|
Purpose Signals the semaphore and increases the counter by the specified number. Parameters
Returned values If successful, the function returns |
|
Purpose Waits on the semaphore for a period that does not exceed the specified time. Parameters
Returned values If successful, the function returns Returns |
|
Purpose Waits on the semaphore indefinitely. Parameters
Returned values If successful, the function returns |
|
Purpose Waits on the semaphore. If the semaphore counter has a zero value, returns control, rather than waits for the semaphore counter to increase. Parameters
Returned values If successful, the function returns If the semaphore counter has a zero value, returns |
Conditional variables
A conditional variable is a synchronization primitive that is used to notify one or more threads about the fulfillment of a condition required by these threads. A conditional variable is used together with a mutex. The notifying and notified threads capture a mutex to execute critical sections. During execution of a critical section, the notified thread verifies that its required condition was fulfilled (for example, the data has been prepared by the notifying thread). If the condition is fulfilled, the notified thread executes the critical section and frees the mutex. If the condition is not fulfilled, the notified thread is locked at the conditional variable and waits for the condition to be fulfilled. When this happens, the mutex is automatically freed. During execution of a critical section, the notifying thread verifies fulfillment of the condition required by the notified thread. If the condition is fulfilled, the notifying thread signals this fulfillment through the conditional variable and frees the mutex. The notified thread that was locked and waiting for the fulfillment of its required condition resumes execution of the critical section while automatically capturing the mutex. After the critical section is executed, the notified thread frees the mutex.
The standard API usage scenario for working with conditional variables includes the following steps:
- The conditional variable and mutex are initialized.
To initialize a conditional variable, you need to call the
KosCondvarInit()
function. - The conditional variable and mutex are used by threads.
Use of a conditional variable and mutex by notified threads includes the following steps:
- The mutex is captured.
- Condition fulfillment is verified.
- The
KosCondvarWait()
orKosCondvarWaitTimeout()
function is called to wait for condition fulfillment.After the
KosCondvarWait()
orKosCondvarWaitTimeout()
function is returned, you normally need to re-verify that the condition is fulfilled because another notified thread also received the signal and may have voided this condition again. (For example, another thread could have extracted the data prepared by the notifying thread). To do so, you need to use the following construct:while(<condition>) <call of KosCondvarWait() or KosCondvarWaitTimeout()> - The mutex is freed.
Use of a conditional variable and mutex by notifying threads includes the following steps:
- The mutex is captured.
- Condition fulfillment is verified.
- Fulfillment of the condition is signaled via the
KosCondvarSignal()
orKosCondvarBroadcast()
function call. - The mutex is freed.
Information about the API conditional variable functions is provided in the table below.
condvar.h functions
Function |
Information about the function |
---|---|
|
Purpose Initializes a conditional variable. Parameters
Returned values N/A |
|
Purpose Waits for condition fulfillment for a period that does not exceed the specified time. Parameters
Returned values Returns Returns |
|
Purpose Waits indefinitely for condition fulfillment. Parameters
Returned values If successful, the function returns |
|
Purpose Signals condition fulfillment to one of the threads waiting for it. Parameters
Returned values N/A |
|
Purpose Signals condition fulfillment to all threads waiting for it. Parameters
Returned values N/A |
Managing I/O memory isolation (iommu_api.h)
The API is defined in the sysroot-*-kos/include/coresrv/iommu/iommu_api.h
header file from the KasperskyOS SDK.
The API is intended for managing the isolation of physical memory regions used by devices on a PCIe bus for DMA. (Isolation is provided by the IOMMU.)
Information about API functions is provided in the table below.
Using the API
A device on the PCIe bus cannot use DMA unless the device is attached to the IOMMU domain. After a device is attached to the IOMMU domain, the device can access all DMA buffers that are associated with this IOMMU domain. A device can be attached to only one IOMMU domain at a time, but multiple devices can be attached to the same IOMMU domain. A DMA buffer can be associated with multiple IOMMU domains at the same time. Each process is associated with a separate IOMMU domain.
The API attaches devices on the PCIe bus to an IOMMU domain associated with the calling process, and performs the inverse operation. A device is normally attached to an IOMMU domain when its driver is initialized. A device is usually detached from an IOMMU domain when errors are encountered during driver initialization or driver finalization.
A DMA buffer is associated with an IOMMU domain when calling the KnIoDmaBegin()
function that is included in the API dma.h.
Information about API functions
iommu_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Attaches a device on a PCIe bus to the IOMMU domain associated with the calling process. Parameters
Returned values If successful, the function returns Additional information If IOMMU is not enabled, |
|
Purpose Detaches a device on a PCIe bus from the IOMMU domain associated with the calling process. Parameters
Returned values If successful, the function returns Additional information If IOMMU is not enabled, |
Using queues (queue.h)
The API is defined in the header file sysroot-*-kos/include/kos/queue.h
from the KasperskyOS SDK.
The API sets up data exchange between threads owned by one process via a queuing mechanism that does not lock threads. In other words, you can add or extract elements of a queue without locking other threads that add or extract elements of this queue.
Information about API functions is provided in the table below.
Using the API
The standard scenario for API usage includes the following steps:
- Create a queue abstraction.
A queue abstraction consists of a structure containing queue metadata and a queue buffer intended for storing elements of the queue. A queue buffer is logically divided into equal segments, each of which is intended for an individual element of the queue. The number of segments in a queue buffer matches the maximum number of elements in the queue. The alignment of segment addresses corresponds to the data types of elements in the queue.
To complete this step, call the
KosQueueCreate()
function. This function can allocate memory for the queue buffer or use already allocated memory. The size of the already allocated memory must be sufficient to accommodate the maximum number of elements in the queue. Also take into account that the size of a segment in the queue buffer is rounded to the next largest multiple of the alignment value defined through theobjAlign
parameter. The initial address of the already allocated memory must also be aligned to correspond to the data types of queue elements. If the memory address alignment specified in thebuffer
parameter is less than the value defined through theobjAlign
parameter, the function returnsRTL_NULL
. - Exchange data between threads by adding and extracting elements of the queue.
To add one element to the end of the queue, you must reserve a segment in the queue buffer by calling the
KosQueueAlloc()
function, copy this element to the reserved segment, and call theKosQueuePush()
function.To add a sequence of elements to the end of the queue, you must reserve the necessary number of segments in the queue buffer via
KosQueueAlloc()
function calls, copy the elements of this sequence to the reserved segments, and call theKosQueuePushArray()
function. The order of elements in a sequence is not changed after this sequence is added to the queue. In other words, elements are added to the queue in the same order in which the pointers to reserved segments in the queue buffer are put into the array that is passed through theobjs
parameter of theKosQueuePushArray()
function.To extract the first element of the queue, you must call the
KosQueuePop()
function. This function returns the pointer to the reserved segment in the queue buffer that contains the first element of the queue. After using an extracted element (for example, after checking or saving the value of an element), you must free the queue buffer segment occupied by this element. To do so, call theKosQueueFree()
function.To clear the queue and free all registered segments in the queue buffer, you must call the
KosQueueFlush()
function. - Delete the queue abstraction.
To complete this step, call the
KosQueueDestroy()
function. This function deletes the queue buffer if only the memory for this buffer was allocated by theKosQueueCreate()
function. Otherwise, you must separately delete the queue buffer.
Information about API functions
queue.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a queue abstraction. Parameters
Returned values If successful, the function returns the queue abstraction ID, otherwise it returns |
|
Purpose Deletes a queue abstraction. Parameters
Returned values N/A |
|
Purpose Reserves a segment in the queue buffer. Parameters
Returned values If successful, the function returns the pointer to the reserved segment in the queue buffer, otherwise it returns |
|
Purpose Resets the reservation of the defined segment in the queue buffer. Parameters
Returned values N/A |
|
Purpose Adds an element to the end of the queue. Parameters
Returned values N/A |
|
Purpose Adds a sequence of elements to the end of the queue. Parameters
Returned values N/A |
|
Purpose Extracts the first element of the queue. Parameters
Returned values If successful, this function returns the pointer to the reserved segment in the queue buffer containing the first element of the queue. Otherwise it returns |
|
Purpose Clears the queue and resets the reservation of all registered segments in the queue buffer. Parameters
Returned values N/A |
Using memory barriers (barriers.h)
This API is defined in the header file sysroot-*-kos/include/coresrv/io/barriers.h
from the KasperskyOS SDK.
The API sets barriers for reading from memory and/or writing to memory. A memory barrier is an instruction for a compiler or processor that guarantees that memory access operations specified in source code before setting a barrier will be executed before the memory access operations specified in source code after setting a barrier. Use of memory barriers is required if the specific order of memory write and memory read operations is important. Otherwise, the optimization mechanisms of a compiler and/or processor could cause these operations to be executed in a different order than the order specified in the source code.
Information about API functions is provided in the table below.
barriers.h functions
Function |
Information about the function |
---|---|
|
Purpose Sets a barrier for reading from memory. Parameters N/A Returned values N/A |
|
Purpose Sets a barrier for writing to memory. Parameters N/A Returned values N/A |
|
Purpose Sets a barrier for writing to memory and reading from memory. Parameters N/A Returned values N/A |
Executing system calls (syscalls.h)
This API is defined in the header file sysroot-*-kos/include/coresrv/syscalls.h
from the KasperskyOS SDK.
The API allows execution of the Call()
, Recv()
, and Reply()
system calls for sending and receiving IPC messages.
Information about API functions is provided in the table below.
Using the API
Pointers to buffers containing the constant part and arena of IPC messages are passed to API functions by using an IPC message header whose type is defined in the header file sysroot-*-kos/include/ipc/if_rend.h
from the KasperskyOS SDK. Prior to API function calls, the headers of IPC messages must be bound to buffers containing the constant part and arena of IPC messages. To do so, use the PackInMsg()
and PackOutMsg()
functions that are declared in the header file sysroot-*-kos/include/services/rtl/nk_msg.h
from the KasperskyOS SDK.
The Call()
, CallEx()
, Recv()
, and RecvEx()
functions lock execution of the calling thread while waiting for the system calls to complete. The CallEx()
and RecvEx()
functions let you define the timeout for completion of a system call. When this timeout is reached, an uncompleted system call is interrupted and the thread that is waiting for its completion resumes execution. A system call is also interrupted if an error occurs during its execution (such as an error due to termination of a server process). If a thread waiting on the completion of a system call is terminated externally, this system call is also interrupted. A system call executed by the CallEx()
or RecvEx()
function can be interrupted (for example, for correct termination of a process) by using the API ipc_api.h.
If a system call was interrupted using the API ipc_api.h, the CallEx()
and RecvEx()
functions return the error code rcIpcInterrupt
. If IPC message transmission is prohibited by security mechanisms (such as the Kaspersky Security Module or a capability-based security mechanism implemented by the KasperskyOS kernel), the Call()
, CallEx()
, and Reply()
functions return the error code rcSecurityDisallow
.
Information about API functions
syscalls.h functions
Function |
Information about the function |
---|---|
|
Purpose Executes the Parameters
Returned values If successful, the function returns |
|
Purpose Executes the Parameters
Returned values If successful, the function returns |
|
Purpose Executes the Parameters
Returned values If successful, the function returns |
|
Purpose Executes the Parameters
Returned values If successful, the function returns |
|
Purpose Executes the Parameters
Returned values If successful, the function returns |
IPC interrupt (ipc_api.h)
This API is defined in the header file sysroot-*-kos/include/coresrv/ipc/ipc_api.h
from the KasperskyOS SDK.
The API interrupts the Call()
and Recv()
system calls if one or more process threads are locked while waiting for these system calls to complete. For example, you may need to interrupt these system calls to correctly terminate a process so that threads waiting for the completion of these system calls can resume execution.
Information about API functions is provided in the table below.
Using the API
The API interrupts system calls in process threads that were locked after the CallEx()
or RecvEx()
function was called from the API syscalls.h if these functions were called while specifying the IPC synchronization object handle in the syncHandle
parameter. To create an IPC synchronization object, call the KnIpcCreateSyncObject()
function. (The handle of an IPC synchronization object cannot be transferred to another process because the necessary flag for this operation is not set in the permissions mask of this handle.)
The KnIpcSetInterrupt()
function switches an IPC synchronization object to a state that allows interruption of the system calls in those process threads that have been locked after a CallEx()
or RecvEx()
function call specifying the handle of this IPC synchronization object in the syncHandle
parameter. A system call can be interrupted only during certain stages of its execution. A system call that is executed by the CallEx()
function can be interrupted only when the server has not yet received a Recv()
or RecvEx()
function call for the IPC channel whose client IPC handle was specified during the CallEx()
function call. A system call executed by the RecvEx()
function can be interrupted only while waiting for an IPC request from a client.
The KnIpcClearInterrupt()
function cancels the action of the KnIpcSetInterrupt()
function.
To delete an IPC synchronization object, close its handle by calling the KnHandleClose()
function that is declared in the header file sysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.
Information about API functions
ipc_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates an IPC synchronization object. Parameters
Returned values If successful, the function returns |
|
Purpose Switches the defined IPC synchronization object to a state in which the Parameters
Returned values If successful, the function returns |
|
Purpose Switches the defined IPC synchronization object to a state in which the Parameters
Returned values If successful, the function returns |