Contents
- libkos library
- Overview of the libkos library
- Memory
- Memory allocation
- Threads
- KosThreadCallback()
- KosThreadCallbackRegister()
- KosThreadCallbackUnregister()
- KosThreadCreate()
- KosThreadCurrentId()
- KosThreadExit()
- KosThreadGetStack()
- KosThreadOnce()
- KosThreadResume()
- KosThreadSleep()
- KosThreadSuspend()
- KosThreadTerminate()
- KosThreadTlsGet()
- KosThreadTlsSet()
- KosThreadWait()
- KosThreadYield()
- Handles
- Notifications
- Processes
- Dynamically created channels
- Synchronization primitives
- KosCondvarBroadcast()
- KosCondvarDeinit()
- KosCondvarInit()
- KosCondvarSignal()
- KosCondvarWait()
- KosCondvarWaitTimeout()
- KosEventDeinit()
- KosEventInit()
- KosEventReset()
- KosEventSet()
- KosEventWait()
- KosEventWaitTimeout()
- KosMutexDeinit()
- KosMutexInit()
- KosMutexInitEx()
- KosMutexLock()
- KosMutexLockTimeout()
- KosMutexTryLock()
- KosMutexUnlock()
- KosRWLockDeinit()
- KosRWLockInit()
- KosRWLockRead()
- KosRWLockTryRead()
- KosRWLockTryWrite()
- KosRWLockUnlock()
- KosRWLockWrite()
- KosSemaphoreDeinit()
- KosSemaphoreInit()
- KosSemaphoreSignal()
- KosSemaphoreTryWait()
- KosSemaphoreWait()
- KosSemaphoreWaitTimeout()
- DMA buffers
- IOMMU
- I/O ports
- IoReadIoPort8(), IoReadIoPort16(), IoReadIoPort32()
- IoReadIoPortBuffer8(), IoReadIoPortBuffer16(), IoReadIoPortBuffer32()
- IoWriteIoPort8(), IoWriteIoPort16(), IoWriteIoPort32()
- IoWriteIoPortBuffer8(), IoWriteIoPortBuffer16(), IoWriteIoPortBuffer32()
- KnIoPermitPort()
- KnRegisterPort8(), KnRegisterPort16(), KnRegisterPort32()
- KnRegisterPorts()
- Memory-mapped I/O (MMIO)
- Interrupts
- Deallocating resources
- Time
- Queues
- Memory barriers
- Receiving information about CPU time and memory usage
Overview of the libkos library
The KasperskyOS kernel has a number of endpoints for managing handles, threads, memory, processes, IPC channels, I/O resources, and others. The libkos
library is used for accessing endpoints.
libkos library
The libkos
library consists of two parts:
- The first part provides the C interface for accessing KasperskyOS core endpoints. It is available through the header files in the
coresrv
directory. - The second part of the
libkos
library provides abstractions of synchronization primitives, objects, and queues. It also contains wrapper functions for simpler memory allocation and thread management. Header files of the second part oflibkos
are in thekos
directory.
The libkos
library significantly simplifies the use of core endpoints. The libkos
library functions ensure correct packaging of an IPC message and execution of system calls. Other libraries (including libc
) interact with the kernel through the libkos
library.
To use a KasperskyOS core endpoint, you need to include the libkos
library header file corresponding to this endpoint. For example, to access methods of the IO Manager, you need to include the io_api.h
file:
Files used by the libkos library
An intrinsic implementation of the libkos
library can use the following files exported by the kernel:
- Files in the IDL language (IDL descriptions). They contain descriptions of the interfaces of endpoints. They are used by IPC transport for correct packaging of messages.
- Header files of the kernel. These files are included in the
libkos
library.
Example
The I/O Manager is provided for the user in the following files:
coresrv/io/io_api.h
is a header file of thelibkos
library.services/io/IO.idl
is the IDL description of the I/O manager.io/io_dma.h
andio/io_irq.h
are header files of the kernel.
Memory states
Each page of virtual memory can be free, reserved, or committed.
The transition from a free state to a reserved state is called allocation. Pre-reserving memory (without committing physical pages) enables an application to mark its address space in advance. The transition from a reserved state back to a free state is referred to as freeing memory.
The assignment of physical memory for a previously reserved page of virtual memory is referred to as committing memory, and the inverse transition from the committed state to the reserved state is called returning memory.
Transitions between memory page states
Page topKnVmAllocate()
This function is declared in the coresrv/vmm/vmm_api.h
file.
void *KnVmAllocate(void *addr, rtl_size_t size, int flags);
Reserves a range of physical pages defined by the addr
and size
parameters. If the VMM_FLAG_COMMIT flag is indicated, the function reserves and commits pages for one call.
Parameters:
addr
is the page-aligned base physical address; ifaddr
is set equal to 0, the system chooses a free area of physical memory.size
is the size of the memory area in bytes (must be a multiple of the page size).flags
refers to allocation flags.
Returns the base virtual address of the reserved area. If it is not possible to reserve a memory area, the function returns RTL_NULL.
Allocation flags
In the flags
parameter, you can use the following flags (vmm/flags.h
):
- VMM_FLAG_RESERVE is a required flag.
- VMM_FLAG_COMMIT lets you reserve and commit memory pages to one
KnVmAllocate()
call in so-called "lazy" mode. - VMM_FLAG_LOCKED is used together with VMM_FLAG_COMMIT and lets you immediately commit physical memory pages instead of "lazy" commitment.
- VMM_FLAG_WRITE_BACK, VMM_FLAG_WRITE_THROUGH, VMM_FLAG_WRITE_COMBINE, VMM_FLAG_CACHE_DISABLE and VMM_FLAG_CACHE_MASK manage caching of memory pages.
- VMM_FLAG_READ, VMM_FLAG_WRITE, VMM_FLAG_EXECUTE and VMM_FLAG_RWX_MASK are memory protection attributes.
- VMM_FLAG_LOW_GUARD and VMM_FLAG_HIGH_GUARD add a protective page before and after the allocated memory, respectively.
- VMM_FLAG_GROW_DOWN defines the direction of memory access (from older addresses to newer addresses).
Permissible combinations of memory protection attributes:
- VMM_FLAG_READ allows reading page contents.
- VMM_FLAG_READ | VMM_FLAG_WRITE allows reading and modifying page contents.
- VMM_FLAG_READ | VMM_FLAG_EXECUTE allows reading and executing page contents.
- VMM_FLAG_RWX_MASK or VMM_FLAG_READ | VMM_FLAG_WRITE | VMM_FLAG_EXECUTE refers to full access to page contents (these entries are equivalent).
Example
coredump->base = KnVmAllocate(RTL_NULL, vmaSize,
VMM_FLAG_READ | VMM_FLAG_RESERVE |
VMM_FLAG_WRITE | VMM_FLAG_COMMIT |
VMM_FLAG_LOCKED).
The KnVmProtect()
function can be used to modify the defined memory area protection attributes if necessary.
KnVmCommit()
This function is declared in the coresrv/vmm/vmm_api.h
file.
Retcode KnVmCommit(void *addr, rtl_size_t size, int flags);
Commits a range of physical pages defined by the "addr" and "size" parameters.
All committed pages must be reserved in advance.
Parameters:
addr
is the page-aligned base virtual address of the memory area.size
is the size of the memory area in bytes (must be a multiple of the page size).flags
is an unused parameter (indicate the VMM_FLAG_LOCKED flag in this parameter value to ensure compatibility).
If pages are successfully committed, the function returns rcOk.
Page topKnVmDecommit()
This function is declared in the coresrv/vmm/vmm_api.h
file.
Retcode KnVmDecommit(void *addr, rtl_size_t size);
Frees a range of pages (switches them to the reserved state).
Parameters:
addr
is the page-aligned base virtual address of the memory area.size
is the size of the memory area in bytes (must be a multiple of the page size).
If pages are successfully freed, the function returns rcOk.
Page topKnVmProtect()
This function is declared in the coresrv/vmm/vmm_api.h
file.
Retcode KnVmProtect(void *addr, rtl_size_t size, int newFlags);
Modifies the protection attributes of reserved or committed memory pages.
Parameters:
addr
is the page-aligned base virtual address of the memory area.size
is the size of the memory area in bytes (must be a multiple of the page size).newFlags
refers to new protection attributes.
If the protection attributes are successfully changed, the function returns rcOk.
Permissible combinations of memory protection attributes:
- VMM_FLAG_READ allows reading page contents.
- VMM_FLAG_READ | VMM_FLAG_WRITE allows reading and modifying page contents.
- VMM_FLAG_READ | VMM_FLAG_EXECUTE allows reading and executing page contents.
- VMM_FLAG_RWX_MASK or VMM_FLAG_READ | VMM_FLAG_WRITE | VMM_FLAG_EXECUTE refers to full access to page contents (these entries are equivalent).
KnVmUnmap()
This function is declared in the coresrv/vmm/vmm_api.h
file.
Retcode KnVmUnmap(void *addr, rtl_size_t size);
Frees the memory area.
Parameters:
addr
refers to the page-aligned address of the memory area.size
refers to the memory area size.
If pages are successfully freed, the function returns rcOk.
Page topKosMemAlloc()
This function is declared in the kos/alloc.h
file.
void *KosMemAlloc(rtl_size_t size);
This function allocates (reserves and commits) a memory area equal to the specific size
of bytes.
This function returns a pointer to the allocated area or RTL_NULL if memory could not be allocated.
Memory allocated by using the KosMemAlloc()
function has the following allocation flags: VMM_FLAG_READ | VMM_FLAG_WRITE, VMM_FLAG_RESERVE, VMM_FLAG_COMMIT, VMM_FLAG_LOCKED. To allocate memory with other allocation flags, use the KnVmAllocate()
function.
KosMemAllocEx()
This function is declared in the kos/alloc.h
file.
void *KosMemAllocEx(rtl_size_t size, rtl_size_t align, int zeroed);
This function is analogous to KosMemAlloc()
, but it also has additional parameters:
align
refers to the alignment of the memory area in bytes (power of two).zeroed
determines whether or not the memory area needs to be filled with zeros (1 means fill, 0 means do not fill).
KosMemFree()
This function is declared in the kos/alloc.h
file.
void KosMemFree(void *ptr);
This function frees a memory area that was allocated using the KosMemAlloc()
, KosMemZalloc()
or KosMemAllocEx()
function.
ptr
is the pointer to the freed memory area.
KosMemGetSize()
This function is declared in the kos/alloc.h
file.
rtl_size_t KosMemGetSize(void *ptr);
This function returns the size (in bytes) of the memory area allocated using the KosMemAlloc()
, KosMemZalloc()
or KosMemAllocEx()
function.
ptr
is the pointer to the memory area.
KosMemZalloc()
This function is declared in the kos/alloc.h
file.
void *KosMemZalloc(rtl_size_t size);
This function is analogous to KosMemAlloc()
, but it also fills the allocated memory area with zeros.
KosThreadCallback()
The callback function prototype is declared in the kos/thread.h
file.
typedef void KosThreadCallback(KosThreadCallbackReason reason);
/* Callback function argument */
typedef enum KosThreadCallbackReason {
KosThreadCallbackReasonCreate,
KosThreadCallbackReasonDestroy,
} KosThreadCallbackReason;
When a new thread is created, all registered callback functions will be called with the KosThreadCallbackReasonCreate
argument. When the thread is terminated, they will be called with the KosThreadCallbackReasonDestroy
argument.
KosThreadCallbackRegister()
This function is declared in the kos/thread.h
file.
Retcode KosThreadCallbackRegister(KosThreadCallback *callback);
This function registers a custom callback function. When a thread is created and terminated, all registered callback functions will be called.
Page topKosThreadCallbackUnregister()
This function is declared in the kos/thread.h
file.
Retcode KosThreadCallbackUnregister(KosThreadCallback *callback);
This function deregisters the custom callback function (removes it from the list of called functions).
Page topKosThreadCreate()
This function is declared in the kos/thread.h
file.
Retcode KosThreadCreate(Tid *tid,
rtl_uint32_t priority,
rtl_uint32_t stackSize,
ThreadRoutine routine,
void *context,
int suspended);
This function creates a new thread.
Input parameters:
priority
must be within the interval from 0 to 31; the following priority constants are available:ThreadPriorityLowest
(0),ThreadPriorityNormal
(15) andThreadPriorityHighest
(31).stackSize
is the size of the stack.routine
is the function that will be executed in the thread.context
is the argument that will be passed to theroutine
function.suspended
lets you create a thread in the suspended state (1 means create suspended, 0 means create not suspended).
Output parameters:
tid
is the ID of the created thread.
Example
int main(int argc, char **argv)
{
Tid tidB;
Tid tidC;
Retcode rcB;
Retcode rcC;
static ThreadContext threadContext[] = {
{.ddi = "B", .deviceName = "/pci/bus0/dev2/fun0/DDI_B"},
{.ddi = "C", .deviceName = "/pci/bus0/dev2/fun0/DDI_C"},
};
rcB = KosThreadCreate(&tidB, ThreadPriorityNormal,
ThreadStackSizeDefault,
FbHotplugThread,
&threadContext[0], 0);
if (rcB != rcOk)
ERR("Failed to start thread %s", threadContext[0].ddi);
rcC = KosThreadCreate(&tidC, ThreadPriorityNormal,
ThreadStackSizeDefault,
FbHotplugThread,
&threadContext[1], 0);
if (rcC != rcOk)
ERR("Failed to start thread %s", threadContext[1].ddi);
/* Waiting for the threads to complete */
...
}
KosThreadCurrentId()
This function is declared in the kos/thread.h
file.
Tid KosThreadCurrentId(void);
This function requests the TID of the calling thread.
If successful, the function returns the thread ID (TID).
Page topKosThreadExit()
This function is declared in the kos/thread.h
file.
void KosThreadExit(rtl_int32_t exitCode);
This function forcibly terminates the current thread with the exitCode
.
KosThreadGetStack()
This function is declared in the kos/thread.h
file.
void *KosThreadGetStack(Tid tid, rtl_uint32_t *size);
This function gets the stack of the thread with the specific tid
.
Output parameter size
contains the stack size.
If successful, the function returns the pointer to the beginning of the stack.
Page topKosThreadOnce()
This function is declared in the kos/thread.h
file.
typedef int KosThreadOnceState;
Retcode KosThreadOnce(KosThreadOnceState *onceControl,
void (* initRoutine) (void));
This function lets you call the defined initRoutine
procedure precisely one time, even when it is called from multiple threads.
The onceControl
parameter is designed to control the one-time call of the procedure.
If the procedure is successfully called, and if it was called previously, the KosThreadOnce()
function returns rcOk.
KosThreadResume()
This function is declared in the kos/thread.h
file.
Retcode KosThreadResume(Tid tid);
This function resumes the thread with the identifier tid
that was created in the suspended state.
If successful, the function returns rcOk.
Page topKosThreadSleep()
This function is declared in the kos/thread.h
file.
Retcode KosThreadSleep(rtl_uint32_t mdelay);
Suspends execution of the current thread for mdelay
(in milliseconds).
If successful, the function returns rcOk.
Page topKosThreadSuspend()
This function is declared in the kos/thread.h
file.
Retcode KosThreadSuspend(Tid tid);
Permanently stops the current thread without finishing it.
The tid
parameter must be equal to the identifier of the current thread (a limitation of the current implementation).
If successful, the function returns rcOk.
Page topKosThreadTerminate()
This function is declared in the kos/thread.h
file.
Retcode KosThreadTerminate(Tid tid, rtl_int32_t exitCode);
This function terminates the thread of the calling process. The tid
parameter defines the ID of the thread.
If the tid
points to the current thread, the exitCode
parameter defines the thread exit code.
If successful, the function returns rcOk.
Page topKosThreadTlsGet()
This function is declared in the kos/thread.h
file.
void *KosThreadTlsGet(void);
This function returns the pointer to the local storage of the thread (TLS) or RTL_NULL if there is no TLS.
Page topKosThreadTlsSet()
This function is declared in the kos/thread.h
file.
Retcode KosThreadTlsSet(void *tls);
This function defines the address of the local storage for the thread (TLS).
Input argument tls
contains the TLS address.
KosThreadWait()
This function is declared in the kos/thread.h
file.
int KosThreadWait(rtl_uint32_t tid, rtl_uint32_t timeout);
This function suspends execution of the current thread until termination of the thread with the identifier tid
or until the timeout
(in milliseconds).
The KosThreadWait()
call with a zero value for timeout
is analogous to the KosThreadYield()
call .
If successful, the function returns rcOk. In case of timeout, it returns rcTimeout.
Page topKosThreadYield()
This function is declared in the kos/thread.h
file.
void KosThreadYield(void);
Passes execution of the thread that called it to the next thread.
The KosThreadYield()
call is analogous to the KosThreadSleep()
call with a zero value for mdelay
.
KnHandleClose()
This function is declared in the coresrv/handle/handle_api.h
file.
Retcode KnHandleClose(Handle handle);
Deletes the handle
.
If successful, the function returns rcOk, otherwise it returns an error code.
Deleting a handle does not invalidate its ancestors and descendants (in contrast to revoking a handle, which actually invalidates the descendants of the handle – see KnHandleRevoke()
and KnHandleRevokeSubtree()
). When a handle is deleted, the integrity of the handle inheritance tree is also preserved. The location of a deleted handle is taken over by its parent, which becomes the immediate ancestor of the descendants of the deleted handle.
KnHandleCreateBadge()
This function is declared in the coresrv/handle/handle_api.h
file.
Retcode KnHandleCreateBadge(Notice notice, rtl_uintptr_t eventId,
void *context, Handle *handle);
This function creates a resource transfer context object for the specified resource transfer context
and configures a notification receiver named notice
for receiving notifications about this object. The notification receiver is configured to receive notifications about events that match the EVENT_OBJECT_DESTROYED
and EVENT_BADGE_CLOSED
flags of the event mask.
Input parameter eventId
defines the ID of a "resource–event mask" entry in the notification receiver.
Output parameter handle
contains the handle of the resource transfer context object.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnHandleCreateUserObject()
This function is declared in the coresrv/handle/handle_api.h
file.
Retcode KnHandleCreateUserObject(rtl_uint32_t type, rtl_uint32_t rights,
void *context, Handle *handle);
Creates the specified handle
of the specified type
with the rights
permissions mask.
The type
parameter can take values ranging from HANDLE_TYPE_USER_FIRST
to HANDLE_TYPE_USER_LAST
.
The HANDLE_TYPE_USER_FIRST
and HANDLE_TYPE_USER_LAST
macros are defined in the handle/handletype.h
header file.
The context
parameter defines the context of the user resource. If successful, the function returns rcOk, otherwise it returns an error code.
Example
Retcode ServerPortInit(ServerPort *serverPort)
{
Retcode rc = rcInvalidArgument;
Notice serverEventNotice;
rc = KnHandleCreateUserObject(HANDLE_TYPE_USER_FIRST, OCAP_HANDLE_SET_EVENT | OCAP_HANDLE_GET_EVENT,
serverPort, &serverPort->handle);
if (rc == rcOk) {
KosRefObject(serverPort);
rc = KnNoticeSubscribeToObject(serverEventNotice,
serverPort->handle,
EVENT_OBJECT_DESTROYED,
(rtl_uintptr_t) serverPort);
if (rc != rcOk) {
KosPutObject(serverPort);
KnHandleClose(serverPort->handle);
serverPort->handle = INVALID_HANDLE;
}
}
return rc;
}
KnHandleRevoke()
This function is declared in the coresrv/handle/handle_api.h
file.
Retcode KnHandleRevoke(Handle handle);
Deletes the handle
and revokes all of its descendants.
If successful, the function returns rcOk, otherwise it returns an error code.
Revoked handles are not deleted. However, you cannot query resources via revoked handles. Any function that accepts a handle will end with the rcHandleRevoked error if this function is called with a revoked handle.
KnHandleRevokeSubtree()
This function is declared in the coresrv/handle/handle_api.h
file.
Retcode KnHandleRevokeSubtree(Handle handle, Handle badge);
This function revokes the handles that make up the handle inheritance subtree of the specified handle
.
The root node of the inheritance subtree is the handle that was generated by the transfer of the specified handle
associated with the badge
resource transfer context object.
If successful, the function returns rcOk, otherwise it returns an error code.
Revoked handles are not deleted. However, you cannot query resources via revoked handles. Any function that accepts a handle will end with the rcHandleRevoked error if this function is called with a revoked handle.
nk_get_badge_op()
This function is declared in the nk/types.h
file.
static inline
nk_err_t nk_get_badge_op(const nk_handle_desc_t *desc,
nk_rights_t operation,
nk_badge_t *badge);
This function extracts the pointer to the badge
resource transfer context from the transport container of desc
if the operation
flags are set in the permissions mask that is placed in the transport container of desc
.
If successful, the function returns NK_EOK, otherwise it returns an error code.
Page topnk_is_handle_dereferenced()
This function is declared in the nk/types.h
file.
static inline
nk_bool_t nk_is_handle_dereferenced(const nk_handle_desc_t *desc);
This function returns a non-zero value if the handle in the transport container of desc
was obtained as a result of a handle dereferencing operation.
This function returns zero if the handle in the transport container of desc
was obtained as a result of a handle transfer operation.
Managing handles
Handles are managed by using functions of the Handle Manager and Notification Subsystem.
The Handle Manager is provided for the user in the following files:
coresrv/handle/handle_api.h
is a header file of thelibkos
library.services/handle/Handle.idl
is an IDL description of the Handle Manager's IPC interface.
The Notification Subsystem is provided for the user in the following files:
coresrv/handle/notice_api.h
is a header file of thelibkos
library.services/handle/Notice.idl
is an IDL description of the IPC interface of the Notification Subsystem.
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 services/ocap.h
header file). 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 services/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 services/ocap.h
header file. The resource provider must export the public header files describing the structure 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 services/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
The handles of user resources are created by the providers of the resources. The KnHandleCreateUserObject()
function declared in the coresrv/handle/handle_api.h
header file is used to create handles of user resources.
handle_api.h (fragment)
/**
* Creates the specified handle of the specified type with the rights permissions mask.
* The "type" parameter can take values ranging from HANDLE_TYPE_USER_FIRST to
* HANDLE_TYPE_USER_LAST. The HANDLE_TYPE_USER_FIRST and HANDLE_TYPE_USER_LAST macros
* are defined in the handletype.h header file. The "context" parameter defines the context
* of the user resource.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode KnHandleCreateUserObject(rtl_uint32_t type, rtl_uint32_t rights,
void *context, Handle *handle);
The user resource context is the data that allows the resource provider to identify the resource and its state when access to the resource is requested by other programs. 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.
The type
parameter of the KnHandleCreateUserObject()
function is reserved for potential future use and does not affect the behavior of the function, but it must take a value from the interval specified in the function comments.
For details about a handle permissions mask, see "Handle permissions mask".
Page topTransferring handles
Overview
Handles are transferred between programs so that clients (programs that utilize resources) can obtain 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 program. This handle is registered as a descendant of the transferred handle and identifies the same resource.
One handle can be transferred multiple times by one or multiple programs. Each transfer initiates the creation of a new descendant of the transferred handle on the recipient program side. A program can transfer the handles that it received from other programs or from the KasperskyOS kernel (when creating handles of system resources). 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 program can transfer handles for user resources and system resources if the access rights of these handles permit such a transfer. A descendant may have less access rights than an ancestor. For example, a transferring program with read-and-write permissions for a file can transfer read-only permissions. The transferring program can also prohibit the recipient program from further transferring the handle. Access rights are defined in the transferred permissions mask for the handle.
Conditions for transferring handles
For programs to transfer handles to other programs, the following conditions must be met:
- An IPC channel is created between the programs.
- The solution security policy (
security.psl
) allows interaction between the programs. - Interface methods are implemented for transferring handles.
- The client program received the endpoint ID (RIID) of the server program that has methods for transferring handles.
Interface methods for transferring handles are declared in the IDL language with input (in
) and/or output (out
) parameters of the Handle
type. Methods with input parameters of the Handle
type are intended for transferring handles from the client program to the server program. Methods with output parameters of the Handle
type are intended for transferring handles from the server program to the client program. No more than seven input and seven output parameters of the Handle
type can be declared for one method.
Example IDL description containing declarations of interface methods for transferring handles:
package IpcTransfer
interface {
PublishResource1(in Handle handle, out UInt32 result);
PublishResource7(in Handle handle1, in Handle handle2,
in Handle handle3, in Handle handle4,
in Handle handle5, in Handle handle6,
in Handle handle7, out UInt32 result);
OpenResource(in UInt32 ID, out Handle handle);
}
For each parameter of the Handle
type, the NK compiler generates a field in the *_req
request structure and/or *_res
response structure of the nk_handle_desc_t
type (hereinafter also referred to as the transport container of the handle). This type is declared in the nk/types.h
header file 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 is the data that allows the server program 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. A server program receives a pointer to the resource transfer context when dereferencing a handle.
Regardless of whether or not a server program is the resource provider, it 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 request.
If the server program 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 program that is the resource provider can use 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 program uses multiple various-type resources of the server program, 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 program can verify that the client program 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 program could mistakenly send the interface method a resource handle that does not correspond to this method. For example, a client program receives a file handle and sends it to an interface method for working with volumes.
To associate a handle transfer with a resource transfer context, the server program 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 object that stores the pointer to the resource transfer context. The resource transfer context object is created by the KnHandleCreateBadge()
function, which is declared in the coresrv/handle/handle_api.h
header file. This function is bound to the Notification Subsystem regarding the state of resources because a server program needs to know when a resource transfer context object will be closed and terminated. The server program 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 when deleting or revoking the handle descendants (see Deleting handles, Revoking handles) that were generated during its transfer in association with this object. (A transferred handle may be deleted intentionally or unintentionally, such as when a recipient client program is unexpectedly terminated.) After receiving a notification regarding the closure of a resource transfer context object, the server program deletes the handle of this object. After this, the resource transfer context object is terminated. After receiving a notification regarding the termination of the resource transfer context object, the server program 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.
handle_api.h (fragment)
/**
* Creates a resource transfer context object for
* the resource transfer "context" and configures the
* notification receiver "notice" to receive notifications about
* this object. The notification receiver is configured to
* receive notifications about events that match the
* event mask flags OBJECT_DESTROYED and EVENT_BADGE_CLOSED.
* Input parameter eventId defines the identifier of the
* "resource–event mask" entry in the notification receiver.
* Output parameter handle contains the handle of the
* resource transfer context.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode KnHandleCreateBadge(Notice notice, rtl_uintptr_t eventId,
void *context, Handle *handle);
Packaging data into the transport container of a handle
The nk_handle_desc()
macro declared in the nk/types.h
header file is used to package a handle, handle permissions mask and resource transfer context object handle into a handle transport container. This macro receives a variable number of arguments.
If no argument is passed to the macro, the NK_INVALID_HANDLE
value will be written in the handle
field of the nk_handle_desc_t
structure.
If one argument is passed to the macro, this argument is interpreted as the handle.
If two arguments are passed to the macro, the first argument is interpreted as the handle and the second argument is interpreted as the handle permissions mask.
If three arguments are passed to the macro, the first argument is interpreted as the handle, the second argument is interpreted as the handle permissions mask, and the third argument is interpreted as the resource transfer context object handle.
Extracting data from the transport container of a handle
The nk_get_handle()
, nk_get_rights()
and nk_get_badge_op()
(or nk_get_badge()
) functions that are declared in the nk/types.h
header file are used to extract the handle, handle permissions mask, and pointer to the resource transfer context, respectively, from the transport container of a handle. The nk_get_badge_op()
and nk_get_badge()
functions are used only when dereferencing handles.
Handle transfer scenarios
A scenario for transferring handles from a client program to the server program includes the following steps:
- The transferring client program packages the handles and handle permissions masks into the fields of the
*_req
requests structure of thenk_handle_desc_t
type. - The transferring client program calls the interface method for transferring handles to the server program. This method executes the
Call()
system call. - The recipient server program receives the request by executing the
Recv()
system call. - The dispatcher on the recipient server program side calls the method corresponding to the request. This method extracts the handles and handle permissions masks from the fields of the
*_req
request structure of thenk_handle_desc_t
type.
A scenario for transferring handles from the server program to a client program includes the following steps:
- The recipient client program calls the interface method for receiving handles from the server program. This method executes the
Call()
system call. - The transferring server program receives the request by executing the
Recv()
system call. - The dispatcher on the transferring server program side calls the method corresponding to the request. This method packages the handles, handle permissions masks and resource transfer context object handles into the fields of the
*_res
response structure of thenk_handle_desc_t
type. - The transferring server program responds to the request by executing the
Reply()
system call. - On the recipient client program side, the interface method returns control. After this, the recipient client program extracts the handles and handle permissions masks from the fields of the
*_res
response structure of thenk_handle_desc_t
type.
If the transferring program 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 made by the transferring or recipient client program or the Reply()
system call made by the transferring server program ends with the rcSecurityDisallow
error.
Dereferencing handles
When dereferencing a handle, the client program sends the server program the handle, and the server program 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 program and already owned by the server program. Dereferencing occurs when a client program that called methods for working with a resource (such as read/write or access closure) sends the server program the handle that was received from this server program 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 program packages the handle into a field of the
*_req
request structure of thenk_handle_desc_t
type. - The client program calls the interface method for sending the handle to the server program for the purpose of performing operations with the resource. This method executes the
Call()
system call. - The server program receives the request by executing the
Recv()
system call. - The dispatcher on the server program side calls the method corresponding to the 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 program) 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 verifications, the server program utilizes the nk_is_handle_dereferenced()
and nk_get_badge_op()
functions that are declared in the nk/types.h
header file.
types.h (fragment)
/**
* Returns a value different from null if
* the handle in the transport container of
* "desc" is received as a result of dereferencing
* the handle. Returns null if the handle
* in the transport container of "desc" is received
* as a result of a handle transfer.
*/
static inline
nk_bool_t nk_is_handle_dereferenced(const nk_handle_desc_t *desc)
/**
* Extracts the pointer to the resource transfer context
* "badge" from the transport container of "desc"
* if the permissions mask that was put in the transport
* container of the desc handle has the operation flags set.
* If successful, the function returns NK_EOK, otherwise it returns an error code.
*/
static inline
nk_err_t nk_get_badge_op(const nk_handle_desc_t *desc,
nk_rights_t operation,
nk_badge_t *badge)
Generally, the server program does not require the handle that was received from dereferencing because the server program normally retains the handles that it owns, for example, within the contexts of user resources. However, the server program can extract this handle from the handle transport container if necessary.
Page topRevoking handles
A program can revoke descendants of a handle that it owns. Handles are revoked according to the handle inheritance tree.
Revoked handles are not deleted. However, you cannot query resources via revoked handles. Any function that accepts a handle will end with the rcHandleRevoked
error if this function is called with a revoked handle.
Handles are revoked by using the KnHandleRevoke()
and KnHandleRevokeSubtree()
functions declared in the coresrv/handle/handle_api.h
header file. The KnHandleRevokeSubtree()
function uses the resource transfer context object that is created when transferring handles.
handle_api.h (fragment)
/**
* Deletes the handle and revokes all of its descendants.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode KnHandleRevoke(Handle handle);
/**
* Revokes handles that form the
* inheritance subtree of the handle. The root node of the inheritance subtree
* is the handle that is generated by transferring
* the handle associated with the object of the
* "badge" resource transfer context.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode KnHandleRevokeSubtree(Handle handle, Handle badge);
Notifying about the state of resources
Programs can track events that occur with resources (system resources as well as user resources), and inform other programs about events involving user resources.
Functions of the Notification Subsystem are declared in the coresrv/handle/notice_api.h
header file. The Notification Subsystem provides for the use of event masks.
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 general part describes the general events that are not specific to any particular resource (the flags of these events are defined in the handle/event_descr.h
header file). For example, the general part contains the EVENT_OBJECT_DESTROYED
flag, which defines the "resource termination" event. The specialized part describes the events that are specific to a particular user resource. The structure of the specialized part is defined by the resource provider by using the OBJECT_EVENT_SPEC()
macro that is defined in the handle/event_descr.h
header file. The resource provider must export the public header files describing the structure of the specialized part.
The scenario for receiving notifications about events that occur with a resource consists of the following steps:
- The
KnNoticeCreate()
function creates a notification receiver (object that stores notifications). - The
KnNoticeSubscribeToObject()
function adds "resource–event mask" entries to the notification receiver to configure it to receive notifications about events that occur with relevant resources. The set of tracked events is defined for each resource by an event mask. - The
KnNoticeGetEvent()
function is called to extract notifications from the notification receiver.
The KnNoticeSetObjectEvent()
function is used to notify a program about events that occur with a user resource. A call of this function initiates the corresponding notifications in the notification receivers that are configured to track these events that occur with this resource.
notice_api.h (fragment)
/**
* Creates the notification receiver named "notice".
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode Kn
NoticeCreate(Notice *notice);
/**
* Adds a "resource–event mask" entry
* to the "notice" notification receiver so that it will receive notifications about
* events that occur with the "object" resource and that match the
* evMask event mask. Input parameter evId defines the identifier
* of the entry that is assigned by the user and used to
* identify the entry in received notifications.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode Kn
NoticeSubscribeToObject(Notice notice,
Handle object,
rtl_uint32_t evMask,
rtl_uintptr_t evId);
/**
* Extracts notifications from the "notice" notification receiver
* while waiting for events to occur within the specific number of milliseconds.
* Input parameter countMax defines the maximum number
* of notifications that can be extracted. Output parameter
* "events" contains a set of extracted notifications of the EventDesc type.
* Output parameter "count" contains the number of notifications that
* were extracted.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode Kn
NoticeGetEvent(Notice notice,
rtl_uint64_t msec,
rtl_size_t countMax,
EventDesc *events,
rtl_size_t *count);
/* Notification structure */
typedef struct {
/* Identifier of the "resource–event mask" entry
* in the notification receiver */
rtl_uintptr_t eventId;
/* Mask of events that occurred. */
rtl_uint32_t eventMask;
} EventDesc;
/**
* Signals that events from event mask
* evMask occurred with the "object" user resource.
* You cannot set flags of the general part of an event mask
* because events from the general part of an event mask can be
*signaled only by the KasperskyOS kernel.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode Kn
NoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);
Deleting handles
A program can delete the handles that it owns. Deleting 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 deleted handle can still be used to provide access to the resource that they identify. Also, deleting a handle does not disrupt the handle inheritance tree associated with the resource identified by the particular handle. The place of a deleted handle is occupied by its ancestor. In other words, the ancestor of a deleted handle becomes the direct ancestor of the descendants of the deleted handle.
Handles are deleted by using the KnHandleClose()
function, which is declared in the coresrv/handle/handle_api.h
header file.
handle_api.h (fragment)
/**
* Deletes the handle.
* If successful, the function returns rcOk, otherwise it returns an error code.
*/
Retcode KnHandleClose(Handle handle);
OCap usage example
This article describes an OCap usage scenario in which the server program 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 client program uses these methods.
IDL description of interface methods:
package SimpleOCap
interface {
OpenResource(in UInt32 ID, out Handle handle);
UseResource(in Handle handle, in UInt8 param, out UInt8 result);
CloseResource(in Handle handle);
}
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 client 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 or termination 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 client, which means that the client receives a descendant of the handle owned by the resource provider.
- The
OpenResource()
method call completes successfully. The client 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 client to query the resource, but is transferred so that the client can find out its permissions for accessing the resource.
- The resource provider creates the resource transfer context and calls the
- The client calls the
UseResource()
method to utilize the resource.- The handle that was received from the resource provider at step 2 is used as an argument of the
UseResource()
method. Before calling this method, the client 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 client) 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 client. Then the resource provider sends the client the results of this operation.
- The
UseResource()
method call completes successfully. The client receives the results of the operation performed on the resource.
- The handle that was received from the resource provider at step 2 is used as an argument of the
- The client 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 an argument of the
CloseResource()
method. Before calling this method, the client uses thenk_handle_desc()
macro to package the handle into the handle transport container. After theCloseResource()
method is called, the client uses theKnHandleClose()
function to delete 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 client. The resource handle owned by the resource provider and the handle of the resource transfer context object are used as arguments 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 client does not have to be revoked because the client already deleted it. However, the revoke operation is performed in case the resource provider is not sure if the client actually deleted the handle). - The
CloseResource()
method call completes successfully.
- The handle that was received from the resource provider at step 2 is used as an argument of the
- The resource provider frees up the memory that was allocated for the resource transfer context and the 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 delete 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 has been terminated, and frees up the memory that was allocated for the resource transfer context. - The resource provider uses the
KnHandleClose()
function to delete the resource handle and to free up the memory that was allocated for the user resource context.
- The resource provider calls the
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 general part describes the general events that are not specific to any particular resource (the flags of these events are defined in the handle/event_descr.h
header file). For example, the general part contains the EVENT_OBJECT_DESTROYED
flag, which defines the "resource termination" event. The specialized part describes the events that are specific to a particular user resource. The structure of the specialized part is defined by the resource provider by using the OBJECT_EVENT_SPEC()
macro that is defined in the handle/event_descr.h
header file. The resource provider must export the public header files describing the structure of the specialized part.
EventDesc
The structure describing the notification is declared in the file coresrv/handle/notice_api.h
.
typedef struct {
rtl_uintptr_t eventId;
rtl_uint32_t eventMask;
} EventDesc;
eventId
is the ID of the "resource–event mask" entry in the notification receiver.
eventMask
is the mask of events that occurred.
KnNoticeCreate()
This function is declared in the file coresrv/handle/notice_api.h
.
Retcode KnNoticeCreate(Notice *notice);
This function creates a notification receiver named notice
(object that stores notifications).
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnNoticeGetEvent()
This function is declared in the file coresrv/handle/notice_api.h
.
Retcode KnNoticeGetEvent(Notice notice,
rtl_uint64_t msec,
rtl_size_t countMax,
EventDesc *events,
rtl_size_t *count);
This function extracts notifications from the notice
notification receiver while waiting for events to occur within the specific number of milliseconds (msec
).
Input parameter countMax
defines the maximum number of notifications that can be extracted.
Output parameter events
contains a set of extracted notifications of the EventDesc
type.
Output parameter count
contains the number of notifications that were extracted.
If successful, the function returns rcOk, otherwise it returns an error code.
Example
const int maxEventsPerNoticeCall = 10;
Retcode rc;
EventDesc events[maxEventsPerNoticeCall];
rtl_size_t eventCount;
rc = KnNoticeGetEvent(notice, INFINITE_TIMEOUT, rtl_countof(events),
&events[0], &eventCount);
KnNoticeSetObjectEvent()
This function is declared in the file coresrv/handle/notice_api.h
.
Retcode KnNoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);
This function signals that events from the event mask evMask
occurred with the object
resource.
You cannot set flags of the general part of an event mask because only the KasperskyOS kernel can provide signals regarding events from the general part of an event mask.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnNoticeSubscribeToObject()
This function is declared in the file coresrv/handle/notice_api.h
.
Retcode KnNoticeSubscribeToObject(Notice notice,
Handle object,
rtl_uint32_t evMask,
rtl_uintptr_t evId);
This function adds a "resource–event mask" entry to the notice
notification receiver so that it can receive notifications about events that occur with the object
resource and match the event mask evMask
.
Input parameter evId
defines the entry ID that is assigned by the user and is used to identify the entry in received notifications.
If successful, the function returns rcOk, otherwise it returns an error code.
For a usage example, see KnHandleCreateUserObject()
.
EntityConnect()
This function is declared in the header file coresrv/entity/entity_api.h
.
Retcode EntityConnect(Entity *cl, Entity *sr);
This function connects processes with an IPC channel. To do so, the function creates IPC handles for the client process cl
and the server process sr
, and then binds the handles to each other. The created channel will be included into the default group of channels (the name of this group matches the name of the server process). The connected processes must be in the stopped state.
If successful, the function returns rcOk.
Page topEntityConnectToService()
This function is declared in the header file coresrv/entity/entity_api.h
.
Retcode EntityConnectToService(Entity *cl, Entity *sr, const char *name);
This function connects processes with an IPC channel. To do so, the function creates IPC handles for the client process cl
and the server process sr
, and then binds the handles to each other. The created channel will be added to the group of channels with the specified name
. The connected processes must be in the stopped state.
If successful, the function returns rcOk.
Page topEntityInfo
The EntityInfo
structure describing the process is declared in the file named if_connection.h
.
typedef struct EntityInfo {
/* process class name */
const char *eiid;
/* maximum number of endpoints */
nk_iid_t max_endpoints;
/* information about the process endpoints */
const EndpointInfo *endpoints;
/* arguments to be passed to the process when it is started */
const char *args[ENTITY_ARGS_MAX + 1];
/* environment variables to be passed to the process when it is started */
const char *envs[ENTITY_ENV_MAX + 1];
/* process flags */
EntityFlags flags;
/* process components tree */
const struct nk_component_node *componentTree;
} EntityInfo;
typedef struct EndpointInfo {
char *name; /* fully qualified name of the endpoint */
nk_iid_t riid; /* endpoint ID */
char *iface_name; /* name of the interface implemented by the endpoint */
} EndpointInfo;
typedef enum {
ENTITY_FLAGS_NONE = 0,
/* the process is reset if an unhandled exception occurs */
ENTITY_FLAG_DUMPABLE = 1,
} EntityFlags;
EntityInit()
This function is declared in the header file coresrv/entity/entity_api.h
.
Entity *EntityInit(const EntityInfo *info);
This function creates a process. The info
parameter defines the name of the process class and (optionally) its endpoints, arguments and environment variables.
The created process will have the default name (matching the process class name), and the default name for the executable file (also matching the process class name).
If successful, the function returns the structure describing the new process. The created process is in the stopped state.
If an error occurs, the function returns RTL_NULL.
Page topEntityInitEx()
This function is declared in the header file coresrv/entity/entity_api.h
.
Entity *EntityInitEx(const EntityInfo *info, const char *name,
const char *path);
This function creates a process.
The info
parameter defines the name of the process class and (optionally) its endpoints, arguments and environment variables.
The name
parameter defines the name of the process. If it has the RTL_NULL value, the process class name from the info
parameter will be used as the process name.
The path
parameter defines the name of the executable file in the solution's ROMFS image. If it has the RTL_NULL value, the process class name from the info
parameter will be used as the file name.
If successful, the function returns the structure describing the new process. The created process is in the stopped state.
If an error occurs, the function returns RTL_NULL.
Page topEntityRun()
This function is declared in the header file coresrv/entity/entity_api.h
.
Retcode EntityRun(Entity *entity);
This function starts a process that is in the stopped state. The process is described by the entity
structure.
If successful, the function returns rcOk.
Page topKnCmAccept()
This function is declared in the coresrv/cm/cm_api.h
file.
Retcode KnCmAccept(const char *client, const char *service, rtl_uint32_t rsid,
Handle listener, Handle *handle);
This function accepts the client process channel creation request that was previously received using the KnCmListen()
call. This function is called by the server process.
Input parameters:
client
is the name of the client process that sent the request to create the channel.service
is the fully qualified name of the endpoint requested by the client process (for example,blkdev.ata
).rsid
is the endpoint ID.listener
is the listener handle; if it has the INVALID_HANDLE value, a new listener handle is created and will be used as the server IPC handle of the channel being created.
Output parameter handle
contains the server IPC handle of the channel being created.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnCmConnect()
This function is declared in the coresrv/cm/cm_api.h
file.
Retcode KnCmConnect(const char *server, const char *service,
rtl_uint32_t msecs, Handle *handle,
rtl_uint32_t *rsid);
This function sends a request to create a channel with the server process. This function is called by the client process.
Input parameters:
server
is the name of the server process that provides the endpoint.service
is the fully qualified name of the endpoint (for example,blkdev.ata
).msecs
is the timeout for accepting the request, in milliseconds.
Output parameters:
handle
is the client IPC handle.rsid
is the endpoint ID.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnCmDrop()
This function is declared in the coresrv/cm/cm_api.h
file.
Retcode KnCmDrop(const char *client, const char *service);
This function rejects the client process channel creation request that was previously received using the KnCmListen()
call. This function is called by the server process.
Parameters:
client
is the name of the client process that sent the request to create the channel.service
is the fully qualified name of the endpoint requested by the client process (for example,blkdev.ata
).
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnCmListen()
This function is declared in the coresrv/cm/cm_api.h
file.
Retcode KnCmListen(const char *filter, rtl_uint32_t msecs, char *client,
char *service);
This function checks for channel creation requests from client processes. This function is called by the server process.
Input parameters:
filter
is an unused parameter.msecs
is the request timeout, in milliseconds.
Output parameters:
client
is the name of the client process.service
is the fully qualified name of the endpoint requested by the client process (for example,blkdev.ata
).
If successful, the function returns rcOk, otherwise it returns an error code.
Page topNsCreate()
This function is declared in the coresrv/ns/ns_api.h
file.
Retcode NsCreate(const char *name, rtl_uint32_t msecs, NsHandle *ns);
This function attempts to connect to name server name
for the specified number of milliseconds (msecs
). If the name
parameter has the RTL_NULL value, the function attempts to connect to name server ns
(the default name server).
Output parameter ns
contains the handle for the connection with the name server.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topNsEnumServices()
This function is declared in the coresrv/ns/ns_api.h
file.
Retcode NsEnumServices(NsHandle ns, const char *type, unsigned index,
char *server, rtl_size_t serverSize,
char *service, rtl_size_t serviceSize);
This function enumerates the endpoints with the defined interface that are published on the name server.
Input parameters:
ns
is the handle of the connection with the name server that was previously received by using theNsCreate()
call.type
is the name of the interface implemented by the endpoint (for example,kl.drivers.Block
).index
is the index for enumerating endpoints.serverSize
is the maximum size of the buffer for theserver
output parameter in bytes.serviceSize
is the maximum size of the buffer for theservice
output parameter in bytes.
Output parameters:
server
is the name of the server process that provides the endpoint (for example,kl.drivers.Ata
).service
is the fully qualified name of the endpoint (for example,blkdev.ata
).
For example, you can receive a full list of server processes that provide an endpoint with the kl.drivers.Block
interface as follows.
rc = NsEnumServices(ns, "kl.drivers.Block", 0, outServerName, ServerNameSize, outServiceName, ServiceNameSize);
rc = NsEnumServices(ns, "kl.drivers.Block", 1, outServerName, ServerNameSize, outServiceName, ServiceNameSize);
...
rc = NsEnumServices(ns, "kl.drivers.Block", N, outServerName, ServerNameSize, outServiceName, ServiceNameSize);
Function calls with index incrementation continue until the function returns rcResourceNotFound.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topNsPublishService()
This function is declared in the coresrv/ns/ns_api.h
file.
Retcode NsPublishService(NsHandle ns, const char *type, const char *server,
const char *service);
This function publishes the endpoint with the defined interface on the name server.
Parameters:
ns
is the handle of the connection with the name server that was previously received by using theNsCreate()
call.type
is the name of the interface implemented by the published endpoint (for example,kl.drivers.Block
).server
is the name of the server process (for example,kl.drivers.Ata
).service
is the fully qualified name of the endpoint (for example,blkdev.ata
).
If successful, the function returns rcOk, otherwise it returns an error code.
Page topNsUnPublishService()
This function is declared in the coresrv/ns/ns_api.h
file.
Retcode NsUnPublishService( NsHandle ns, const char *type, const char *server,
const char *service);
This function unpublishes the endpoint on the name server.
Parameters:
ns
is the handle of the connection with the name server that was previously received by using theNsCreate()
call.type
is the name of the interface implemented by the published endpoint (for example,kl.drivers.Block
).server
is the name of the server process (for example,kl.drivers.Ata
).service
is the fully qualified name of the endpoint (for example,blkdev.ata
).
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKosCondvarBroadcast()
This function is declared in the kos/condvar.h
file.
void KosCondvarBroadcast(KosCondvar *condvar);
This function wakes all threads from the queue of threads that are blocked by the conditional variable condvar
.
KosCondvarDeinit()
This function is declared in the kos/condvar.h
file.
void KosCondvarDeinit(KosCondvar *condvar);
De-initializes the conditional variable condvar
.
KosCondvarInit()
This function is declared in the kos/condvar.h
file.
void KosCondvarInit(KosCondvar *condvar);
Initializes the conditional variable condvar
.
KosCondvarSignal()
This function is declared in the kos/condvar.h
file.
void KosCondvarSignal(KosCondvar *condvar);
This function wakes one thread from the queue of threads that are blocked by the conditional variable condvar
.
KosCondvarWait()
This function is declared in the kos/condvar.h
file.
Retcode KosCondvarWait(KosCondvar *condvar, KosMutex *mutex);
This function blocks execution of the current thread via the conditional variable condvar
until it is awakened using KosCondvarSignal() or KosCondvarBroadcast().
mutex
refers to the mutex that will be used for protecting the critical section.
If successful, the function returns rcOk.
Page topKosCondvarWaitTimeout()
This function is declared in the kos/condvar.h
file.
Retcode KosCondvarWaitTimeout(KosCondvar *condvar, KosMutex *mutex,
rtl_uint32_t mdelay);
This function blocks execution of the current thread via the conditional variable condvar
until it is awakened using KosCondvarSignal() or KosCondvarBroadcast(). The thread is blocked for no more than mdelay
(in milliseconds).
mutex
refers to the mutex that will be used for protecting the critical section.
This function returns rcOk if successful, or rcTimeout if it times out.
Page topKosEventDeinit()
This function is declared in the kos/event.h
file.
void KosEventDeinit(KosEvent *event);
This function frees the resources associated with an event
(deletes the event).
KosEventInit()
This function is declared in the kos/event.h
file.
void KosEventInit(KosEvent *event);
This function creates an event
.
The created event is in a non-signaling state.
Page topKosEventReset()
This function is declared in the kos/event.h
file.
void KosEventReset(KosEvent *event);
This function switches an event
to the non-signaling state (resets the event).
KosEventSet()
This function is declared in the kos/event.h
file.
void KosEventSet(KosEvent *event);
This function switches an event
to the signaling state (signals the event) and thereby wakes all threads that are waiting for it.
KosEventWait()
This function is declared in the kos/event.h
file.
void KosEventWait(KosEvent *event, rtl_bool reset);
Waits for the event to switch to signaling state.
The reset
parameter indicates whether the event should be automatically reset when the wait successfully ends.
Returns rcOk if successful.
Page topKosEventWaitTimeout()
This function is declared in the kos/event.h
file.
Retcode KosEventWaitTimeout(KosEvent *event, rtl_bool reset,
rtl_uint32_t msec);
Waits for the event to switch to signaling state for a period of msec
(milliseconds).
The reset
parameter indicates whether the event should be automatically reset when the wait successfully ends.
This function returns rcOk if successful, or rcTimeout if the timeout is exceeded.
Page topKosMutexDeinit()
This function is declared in the kos/mutex.h
file.
void KosMutexDeinit(KosMutex *mutex);
Deletes the specified mutex
.
KosMutexInit()
This function is declared in the kos/mutex.h
file.
void KosMutexInit(KosMutex *mutex);
Initializes the mutex
in an unlocked state.
KosMutexInitEx()
This function is declared in the kos/mutex.h
file.
void KosMutexInitEx(KosMutex *mutex, int recursive);
Initializes the mutex
in an unlocked state.
To initialize a recursive mutex, you need to pass the value 1 to the recursive
parameter.
KosMutexLock()
This function is declared in the kos/mutex.h
file.
void KosMutexLock(KosMutex *mutex);
Captures the specified mutex
.
If the mutex is already captured, the thread is locked and waits to be unlocked.
Page topKosMutexLockTimeout()
This function is declared in the kos/mutex.h
file.
Retcode KosMutexLockTimeout(KosMutex *mutex, rtl_uint32_t mdelay);
Captures the specified mutex
.
If the mutex is already captured, the thread is locked for mdelay
and waits to be unlocked.
This function returns rcOk if successful, or rcTimeout if it times out.
Page topKosMutexTryLock()
This function is declared in the kos/mutex.h
file.
Retcode KosMutexTryLock(KosMutex *mutex);
Attempts to capture the specified mutex
.
This function returns rcOk if the mutex could be captured, and returns rcBusy if the mutex could not be captured because it is already captured.
Page topKosMutexUnlock()
This function is declared in the kos/mutex.h
file.
void KosMutexUnlock(KosMutex *mutex);
Unlocks the specified mutex
.
To unlock a recursive mutex, you need to perform the same amount of KosMutexUnlock()
calls to match the amount of times the recursive mutex was locked.
KosRWLockDeinit()
This function is declared in the kos/rwlock.h
file.
void KosRWLockDeinit(KosRWLock *rwlock);
De-initializes the read-write lock rwlock
.
KosRWLockInit()
This function is declared in the kos/rwlock.h
file.
void KosRWLockInit(KosRWLock *rwlock);
Initializes the read-write lock rwlock
.
KosRWLockRead()
This function is declared in the kos/rwlock.h
file.
void KosRWLockRead(KosRWLock *rwlock);
Locks the read threads.
Page topKosRWLockTryRead()
This function is declared in the kos/rwlock.h
file.
Retcode KosRWLockTryRead(KosRWLock *rwlock);
Attempts to lock the read threads.
If successful, the function returns rcOk.
Page topKosRWLockTryWrite()
This function is declared in the kos/rwlock.h
file.
Retcode KosRWLockTryWrite(KosRWLock *rwlock);
Attempts to lock the write threads.
If successful, the function returns rcOk.
Page topKosRWLockUnlock()
This function is declared in the kos/rwlock.h
file.
void KosRWLockUnlock(KosRWLock *rwlock);
Removes the read-write lock rwlock
.
KosRWLockWrite()
This function is declared in the kos/rwlock.h
file.
void KosRWLockWrite(KosRWLock *rwlock);
Locks the write threads.
Page topKosSemaphoreDeinit()
This function is declared in the kos/semaphore.h
file.
Retcode KosSemaphoreDeinit(KosSemaphore *semaphore);
This function destroys the specified semaphore
that was previously initialized by the KosSemaphoreInit()
function.
It is safe to destroy an initialized semaphore on which there are currently no locked threads. There could be an unpredictable effect from destroying a semaphore on which other threads are currently locked.
The function returns the following:
- rcOk if successful;
- rcInvalidArgument, if the
semaphore
points to an invalid semaphore; - rcFail if there are threads being locked by this semaphore.
KosSemaphoreInit()
This function is declared in the kos/semaphore.h
file.
Retcode KosSemaphoreInit(KosSemaphore *semaphore, unsigned count);
Initializes the defined semaphore
with the initial count
value.
The function returns the following:
- rcOk if successful;
- rcInvalidArgument, if the
semaphore
points to an invalid semaphore; - rcFail if the
count
value exceeds KOS_SEMAPHORE_VALUE_MAX.
KosSemaphoreSignal()
This function is declared in the kos/semaphore.h
file.
Retcode KosSemaphoreSignal(KosSemaphore *semaphore);
Frees (signals) the defined semaphore
.
The function returns the following:
- rcOk if successful;
- rcInvalidArgument, if the
semaphore
points to an invalid semaphore.
KosSemaphoreTryWait()
This function is declared in the kos/semaphore.h
file.
Retcode KosSemaphoreTryWait(KosSemaphore *semaphore);
Attempts to acquire the defined semaphore
.
The function returns the following:
- rcOk if successful;
- rcInvalidArgument, if the
semaphore
points to an invalid semaphore; - rcBusy if the semaphore is already acquired.
KosSemaphoreWait()
This function is declared in the kos/semaphore.h
file.
Retcode KosSemaphoreWait(KosSemaphore *semaphore);
Waits for acquisition of the defined semaphore
.
The function returns the following:
- rcOk if successful;
- rcInvalidArgument, if the
semaphore
points to an invalid semaphore.
KosSemaphoreWaitTimeout()
This function is declared in the kos/semaphore.h
file.
Retcode KosSemaphoreWaitTimeout(KosSemaphore *semaphore, rtl_uint32_t mdelay);
Waits for acquisition of the defined semaphore
for a period of mdelay
in milliseconds.
The function returns the following:
- rcOk if successful;
- rcInvalidArgument, if the
semaphore
points to an invalid semaphore; - rcTimeout if the timeout expired.
DmaInfo
The structure describing the DMA buffer is declared in the io/io_dma.h
file.
typedef struct {
/** DMA flags (attributes). */
DmaAttr flags;
/** Minimum order of DMA blocks in the buffer. */
rtl_size_t orderMin;
/** DMA buffer size. */
rtl_size_t size;
/** Number of DMA blocks (less than or equal to DMA_FRAMES_COUNT_MAX).
* It may be equal to 0 if a DMA buffer is not available for the device. */
rtl_size_t count;
/** Array of DMA block descriptors. */
union DmaFrameDescriptor {
struct {
/** Order of the DMA block. The number of pages in a block is equal to two
* to the power of the specified order. */
DmaAddr order: DMA_FRAME_ORDER_BITS;
/** Physical or IOMMU address of the DMA block. */
DmaAddr frame: DMA_FRAME_BASE_BITS;
};
/** DMA block descriptor */
DmaAddr raw;
} descriptors[1];
} DmaInfo;
DMA flags
DMA flags (attributes) are declared in the io/io_dma.h
file.
- DMA_DIR_TO_DEVICE allows transactions from the main memory to the device memory.
- DMA_DIR_FROM_DEVICE allows transactions from the device memory to the main memory.
- DMA_DIR_BIDIR allows transactions from the main memory to the device memory, and vice versa.
- DMA_ZONE_DMA32 allows the use of only the first 4 GB of memory for the buffer.
- DMA_ATTR_WRITE_BACK, DMA_ATTR_WRITE_THROUGH, DMA_ATTR_CACHE_DISABLE, and DMA_ATTR_WRITE_COMBINE are for managing the cache of memory pages.
KnIoDmaBegin()
This function is declared in the coresrv/io/dma.h
file.
Retcode KnIoDmaBegin(Handle rid, Handle *handle);
Allows the device to access the DMA buffer with the handle rid
.
Output parameter handle
contains the handle of this permission.
If successful, the function returns rcOk.
For a usage example, see KnIoDmaCreate().
To prevent a device from accessing the DMA buffer, you need to call the KnIoClose()
function while passing the specified handle
of the permission in this function.
KnIoDmaCreate()
This function is declared in the coresrv/io/dma.h
file.
Retcode KnIoDmaCreate(rtl_uint32_t order, rtl_size_t size, DmaAttr flags,
Handle *outRid);
This function registers and allocates a physical DMA buffer.
Input parameters:
order
is the minimum permissible order of DMA block allocation; the actual order of each block in the DMA buffer is chosen by the kernel (but will not be less than the specified order) and is indicated in the block handle; the order of a block determines the number of pages in it. For example, a block with an order of N consists of 2^N pages.size
refers to the size of the DMA buffer, in bytes (must be a multiple of the page size); the sum of all sizes of allocated DMA blocks will be no less than the specifiedsize
.flags
refers to DMA flags.
Output parameter outRid
contains the handle of the allocated DMA buffer.
If successful, the function returns rcOk.
If a DMA buffer is no longer being used, it must be freed by using the KnIoClose()
function.
Example
Retcode RegisterDmaMem(rtl_size_t size,
DmaAttr attr,
Handle *handle,
Handle *dmaHandle,
Handle *mappingHandle,
void **addr)
{
Retcode ret;
*handle = INVALID_HANDLE;
*dmaHandle = INVALID_HANDLE;
*mappingHandle = INVALID_HANDLE;
ret = KnIoDmaCreate(rtl_roundup_order(size >> PAGE_SHIFT),
size,
attr,
handle);
if (ret == rcOk) {
ret = KnIoDmaBegin(*handle, dmaHandle);
}
if (ret == rcOk) {
ret = KnIoDmaMap(*handle,
0,
size,
RTL_NULL,
VMM_FLAG_READ | VMM_FLAG_WRITE,
addr,
mappingHandle);
}
if (ret != rcOk) {
if (*mappingHandle != INVALID_HANDLE)
KnHandleClose(*mappingHandle);
if (*dmaHandle != INVALID_HANDLE)
KnHandleClose(*dmaHandle);
if (*handle != INVALID_HANDLE)
KnHandleClose(*handle);
}
return ret;
}
KnIoDmaGetInfo()
This function is declared in the coresrv/io/dma.h
file.
Retcode KnIoDmaGetInfo(Handle rid, DmaInfo **outInfo);
This function gets information about the DMA buffer with the handle rid
.
Output parameter outInfo
contains information about the DMA buffer.
If successful, the function returns rcOk.
In contrast to KnIoDmaGetPhysInfo()
, the outInfo
parameter contains IOMMU addresses of DMA blocks instead of physical addresses.
KnIoDmaGetPhysInfo()
This function is declared in the coresrv/io/dma.h
file.
Retcode KnIoDmaGetPhysInfo(Handle rid, DmaInfo **outInfo);
This function gets information about the DMA buffer with the handle rid
.
Output parameter outInfo
contains information about the DMA buffer.
If successful, the function returns rcOk.
In contrast to KnIoDmaGetInfo()
, the outInfo
parameter contains physical addresses of DMA blocks instead of IOMMU addresses.
KnIoDmaMap()
This function is declared in the coresrv/io/dma.h
file.
Retcode KnIoDmaMap(Handle rid, rtl_size_t offset, rtl_size_t length, void *hint,
int vmflags, void **addr, Handle *handle);
This function maps a DMA buffer area to the address space of a process.
Input parameters:
rid
is the handle of the DMA buffer allocated usingKnIoDmaCreate()
.offset
refers to the page-aligned offset of the start of the area from the start of the buffer, indicated in bytes.length
refers to the size of the area; it must be a multiple of the page size and must not exceed <buffer size -offset
>.hint
is the virtual address of the start of mapping; if it is equal to 0, the address is selected by the kernel.vmflags
refers to allocation flags.
In the vmflags
parameter, you can use the following allocation flags (vmm/flags.h
):
- VMM_FLAG_READ and VMM_FLAG_WRITE are memory protection attributes.
- VMM_FLAG_LOW_GUARD and VMM_FLAG_HIGH_GUARD add a protective page before and after the allocated memory, respectively.
Permissible combinations of memory protection attributes:
- VMM_FLAG_READ allows reading page contents.
- VMM_FLAG_WRITE allows modification of page contents.
- VMM_FLAG_READ | VMM_FLAG_WRITE allows reading and modifying page contents.
Output parameters:
addr
is the pointer to the virtual address of the start of the mapped area.handle
refers to the handle of the created mapping.
If successful, the function returns rcOk.
For a usage example, see KnIoDmaCreate().
To delete a created mapping, you must call the KnIoClose()
function and pass the specified mapping handle
in this function.
KnIommuAttachDevice()
This function is declared in the coresrv/iommu/iommu_api.h
file.
Retcode KnIommuAttachDevice(rtl_uint16_t bdf);
This function adds the PCI device with the bdf
identifier to the IOMMU group of the calling process (IOMMU domain).
Returns rcOk if successful.
Page topKnIommuDetachDevice()
This function is declared in the coresrv/iommu/iommu_api.h
file.
Retcode KnIommuDetachDevice(rtl_uint16_t bdf);
This function removes the PCI device with the bdf
identifier from the IOMMU group of the calling process (IOMMU domain).
If successful, the function returns rcOk.
Page topIoReadIoPort8(), IoReadIoPort16(), IoReadIoPort32()
These functions are declared in the coresrv/io/ports.h
file.
rtl_uint8_t IoReadIoPort8(rtl_size_t port);
rtl_uint16_t IoReadIoPort16(rtl_size_t port);
rtl_uint32_t IoReadIoPort32(rtl_size_t port);
These functions read one, two, or four bytes, respectively, from the specified port
and return the read value.
IoReadIoPortBuffer8(), IoReadIoPortBuffer16(), IoReadIoPortBuffer32()
These functions are declared in the coresrv/io/ports.h
file.
void IoReadIoPortBuffer8(rtl_size_t port, rtl_uint8_t *dst, rtl_size_t cnt);
void IoReadIoPortBuffer16(rtl_size_t port, rtl_uint16_t *dst, rtl_size_t cnt);
void IoReadIoPortBuffer32(rtl_size_t port, rtl_uint32_t *dst, rtl_size_t cnt);
These functions read the sequence of one-, two-, or four-byte values, respectively, from the specified port
and write the values to the dst
array.
cnt
is the length of sequence.
IoWriteIoPort8(), IoWriteIoPort16(), IoWriteIoPort32()
These functions are declared in the coresrv/io/ports.h
file.
void IoWriteIoPort8(rtl_size_t port, rtl_uint8_t data);
void IoWriteIoPort16(rtl_size_t port, rtl_uint16_t data);
void IoWriteIoPort32(rtl_size_t port, rtl_uint32_t data);
The functions write a one-, two-, or four-byte data
value to the specified port
.
IoWriteIoPortBuffer8(), IoWriteIoPortBuffer16(), IoWriteIoPortBuffer32()
These functions are declared in the coresrv/io/ports.h
file.
void IoWriteIoPortBuffer8(rtl_size_t port, const rtl_uint8_t *src,
rtl_size_t cnt);
void IoWriteIoPortBuffer16(rtl_size_t port, const rtl_uint16_t *src,
rtl_size_t cnt);
void IoWriteIoPortBuffer32(rtl_size_t port, const rtl_uint32_t *src,
rtl_size_t cnt);
These functions write the sequence of one-, two-, or four-byte values, respectively, from the src
array to the specified port
.
cnt
is the length of sequence.
KnIoPermitPort()
This function is declared in the coresrv/io/ports.h
file.
Retcode KnIoPermitPort(Handle rid, Handle *handle);
This function allows a process to access the port (range of ports) with the handle rid
.
Output parameter handle
contains the handle of this permission.
Returns rcOk if successful.
Example
static Retcode PortInit(IOPort *resource)
{
Retcode rc = rcFail;
rc = KnRegisterPorts(resource->base,
resource->size,
&resource->handle);
if (rc == rcOk)
rc = KnIoPermitPort(resource->handle, &resource->permitHandle);
resource->addr = (void *) (rtl_uintptr_t) resource->base;
return rc;
}
KnRegisterPort8(), KnRegisterPort16(), KnRegisterPort32()
These functions are declared in the coresrv/io/ports.h
file.
Retcode KnRegisterPort8(rtl_uint16_t port, Handle *outRid);
Retcode KnRegisterPort16(rtl_uint16_t port, Handle *outRid);
Retcode KnRegisterPort32(rtl_uint16_t port, Handle *outRid);
These functions register an eight-, sixteen-, or thirty-two-bit port, respectively, with the port
address and assign the outRid
handle to it.
Return rcOk if the port allocation is successful.
If a port is no longer being used, it must be freed by using the KnIoClose()
function.
KnRegisterPorts()
This function is declared in the coresrv/io/ports.h
file.
Retcode KnRegisterPorts(rtl_uint16_t port, rtl_size_t size, Handle *outRid);
This function registers a range of ports (memory area) with the base address port
and the specified size
(in bytes) and assigns the outRid
handle to it.
Returns rcOk if allocation of the port range is successful.
For a usage example, see KnIoPermitPort()
.
If a range of ports is no longer being used, it must be freed by using the KnIoClose()
function.
IoReadMmBuffer8(), IoReadMmBuffer16(), IoReadMmBuffer32()
These functions are declared in the coresrv/io/mmio.h
file.
void IoReadMmBuffer8(volatile rtl_uint8_t *baseReg, rtl_uint8_t *dst,
rtl_size_t cnt);
void IoReadMmBuffer16(volatile rtl_uint16_t *baseReg, rtl_uint16_t *dst,
rtl_size_t cnt);
void IoReadMmBuffer32(volatile rtl_uint32_t *baseReg, rtl_uint32_t *dst,
rtl_size_t cnt);
These functions read the sequence of one-, two-, or four-byte values, respectively, from the register mapped to the baseReg
address and write the values to the dst
array. cnt
is the length of the sequence.
IoReadMmReg8(), IoReadMmReg16(), IoReadMmReg32()
These functions are declared in the coresrv/io/mmio.h
file.
rtl_uint8_t IoReadMmReg8(volatile void *reg);
rtl_uint16_t IoReadMmReg16(volatile void *reg);
rtl_uint32_t IoReadMmReg32(volatile void *reg);
These functions read one, two, or four bytes, respectively, from the register mapped to the reg
address and return the read value.
IoWriteMmBuffer8(), IoWriteMmBuffer16(), IoWriteMmBuffer32()
These functions are declared in the coresrv/io/mmio.h
file.
void IoWriteMmBuffer8(volatile rtl_uint8_t *baseReg, const rtl_uint8_t *src,
rtl_size_t cnt);
void IoWriteMmBuffer16(volatile rtl_uint16_t *baseReg, const rtl_uint16_t *src,
rtl_size_t cnt);
void IoWriteMmBuffer32(volatile rtl_uint32_t *baseReg, const rtl_uint32_t *src,
rtl_size_t cnt);
These functions write the sequence of one-, two-, or four-byte values, respectively, from the src array to the register mapped to the baseReg
address. cnt
is the length of the sequence.
IoWriteMmReg8(), IoWriteMmReg16(), IoWriteMmReg32()
These functions are declared in the coresrv/io/mmio.h
file.
void IoWriteMmReg8(volatile void *reg, rtl_uint8_t data);
void IoWriteMmReg16(volatile void *reg, rtl_uint16_t data);
void IoWriteMmReg32(volatile void *reg, rtl_uint32_t data);
These functions write a one-, two-, or four-byte data
value to the register mapped to the reg
address.
KnIoMapMem()
This function is declared in the coresrv/io/mmio.h
file.
Retcode KnIoMapMem(Handle rid, rtl_uint32_t prot, rtl_uint32_t attr,
void **addr, Handle *handle);
This function maps the registered memory area that was assigned the handle rid
to the address space of the process.
You can use the prot
and attr
input parameters to change the memory area protection attributes, or to disable caching.
Output parameters:
addr
is the pointer to the starting address of the virtual memory area.handle
refers to the handle of the virtual memory area.
Returns rcOk if successful.
prot
refers to the attributes of memory area protection via MMU, with the following possible values:
- VMM_FLAG_READ – allow read.
- VMM_FLAG_WRITE – allow write.
- VMM_FLAG_READ | VMM_FLAG_WRITE – allow read and write.
- VMM_FLAG_RWX_MASK or VMM_FLAG_READ | VMM_FLAG_WRITE | VMM_FLAG_EXECUTE – full access to the memory area (these entries are equivalent).
attr
– memory area attributes. Possible values:
- VMM_FLAG_CACHE_DISABLE – disable caching.
- VMM_FLAG_LOW_GUARD and VMM_FLAG_HIGH_GUARD add a protective page before and after the allocated memory, respectively.
- VMM_FLAG_ALIAS – flag indicates that the memory area may have multiple virtual addresses.
Example
static Retcode MemInit(IOMem *resource)
{
Retcode rc = rcFail;
rc = KnRegisterPhyMem(resource->base,
resource->size,
&resource->handle);
if (rc == rcOk)
rc = KnIoMapMem(resource->handle,
VMM_FLAG_READ | VMM_FLAG_WRITE,
VMM_FLAG_CACHE_DISABLE,
(void **) &resource->addr, &resource->permitHandle);
if (rc == rcOk)
resource->addr = ((rtl_uint8_t *) resource->addr
+ resource->offset);
return rc;
}
KnRegisterPhyMem()
This function is declared in the coresrv/io/mmio.h
file.
Retcode KnRegisterPhyMem(rtl_uint64_t addr, rtl_size_t size, Handle *outRid);
This function registers a memory area with the specified size
(in bytes) and beginning at the address addr
.
If registration is successful, the handle assigned to the memory area will be passed to the outRid
parameter, and the function will return rcOk.
The address addr
must be page-aligned, and the specified size
must be a multiple of the page size.
For a usage example, see KnIoMapMem()
.
If a memory area is no longer being used, it must be freed by using the KnIoClose()
function.
Interrupts
The interface described here is a low-level interface. In most cases, it is recommended to use the interface provided by the kdf library to manage interrupts.
KnIoAttachIrq()
This function is declared in the coresrv/io/irq.h
file.
Retcode KnIoAttachIrq(Handle rid, rtl_uint32_t flags, Handle *handle);
This function attaches the calling thread to the interrupt.
Input parameters:
rid
is the interrupt handle received by using theKnRegisterIrq()
call.flags
refer to the interrupt flags.
Output parameter handle
contains the IPC handle that will be used by the calling thread to wait for the interrupt after making the Recv()
call.
If successful, the function returns rcOk, otherwise it returns an error code.
Interrupt flags
- IRQ_LEVEL_LOW indicates low level generation.
- IRQ_LEVEL_HIGH indicates high level generation.
- IRQ_EDGE_RAISE indicates rising edge generation.
- IRQ_EDGE_FALL indicates falling edge generation.
- IRQ_SHARED indicates a shared interrupt.
- IRQ_PRIO_LOW indicates a low-priority interrupt.
- IRQ_PRIO_NORMAL indicates normal priority.
- IRQ_PRIO_HIGH indicates high priority.
- IRQ_PRIO_RT indicates real-time priority.
KnIoDetachIrq()
This function is declared in the coresrv/io/irq.h
file.
Retcode KnIoDetachIrq(Handle rid);
This function detaches the calling thread from the interrupt.
rid
is the interrupt handle received by using the KnRegisterIrq()
call.
If successful, the function returns rcOk, otherwise it returns an error code.
Page topKnIoDisableIrq()
This function is declared in the coresrv/io/irq.h
file.
Retcode KnIoDisableIrq(Handle rid);
Masks (prohibits) the interrupt with the handle rid
.
If successful, the function returns rcOk.
Page topKnIoEnableIrq()
This function is declared in the coresrv/io/irq.h
file.
Retcode KnIoEnableIrq(Handle rid);
Unmasks (allows) the interrupt with the handle rid
.
If successful, the function returns rcOk.
Page topKnRegisterIrq()
This function is declared in the coresrv/io/irq.h
file.
Retcode KnRegisterIrq(int irq, Handle *outRid);
Registers the interrupt with the number irq
.
Output parameter outRid
contains the interrupt handle.
If successful, the function returns rcOk.
If an interrupt is no longer being used, it must be freed by using the KnIoClose()
function.
KnIoClose()
This function is declared in the coresrv/io/io_api.h
file.
Retcode KnIoClose(Handle rid);
This function frees a registered input/output resource (I/O port(s), DMA buffer, interrupt or memory area for MMIO) with the rid
handle.
If successfully freed, the function returns rcOk.
For a usage example, see KnIoDmaCreate().
Page topKnGetMSecSinceStart()
This function is declared in the coresrv/time/time_api.h
file.
rtl_size_t KnGetMSecSinceStart(void);
Returns the number of milliseconds that have elapsed since the start of the system.
Page topKnGetRtcTime()
This function is declared in the coresrv/time/time_api.h
file.
Retcode KnGetRtcTime(RtlRtcTime *rt);
This function writes the POSIX system time (in RTC format) to the rt
parameter.
If successful, returns rcOk, or returns rcFail if an error occurs.
The RTC time format is defined by the RtlRtcTime
structure (declared in the rtl/rtc.h
file.):
typedef struct {
rtl_uint32_t msec; /**< milliseconds */
rtl_uint32_t sec; /**< second (0..59) */
rtl_uint32_t min; /**< minute (0..59) */
rtl_uint32_t hour; /**< hour (0..23) */
rtl_uint32_t mday; /**< day (1..31) */
rtl_uint32_t month; /**< month (0..11) */
rtl_int32_t year; /**< year - 1900 */
rtl_uint32_t wday; /**< week day (0..6) */
} RtlRtcTime;
KnGetSystemTime()
This function is declared in the coresrv/time/time_api.h
file.
Retcode KnGetSystemTime(RtlTimeSpec *time);
This function lets you get the system time.
Output parameter time
contains the POSIX system time in RtlTimeSpec
format.
KnSetSystemTime()
This function is declared in the coresrv/time/time_api.h
file.
Retcode KnSetSystemTime(RtlTimeSpec *time);
This function lets you set the system time.
The time
parameter must contain the POSIX time in RtlTimeSpec
format.
It is not recommended to call the KnSetSystemTime()
function in the interrupt handler thread.
KnGetSystemTimeRes()
This function is declared in the coresrv/time/time_api.h
file.
Retcode KnGetSystemTimeRes(RtlTimeSpec *res);
This function lets you get the resolution of the system time source.
Output parameter res
contains the resolution in RtlTimeSpec
format.
KnGetUpTime()
This function is declared in the coresrv/time/time_api.h
file.
Retcode KnGetUpTime(RtlTimeSpec *time);
This function lets you get the time that has elapsed since the start of the system.
Output parameter time
contains the time in RtlTimeSpec
format.
KnGetUpTimeRes()
This function is declared in the coresrv/time/time_api.h
file.
Retcode KnGetUpTimeRes(RtlTimeSpec *res);
This function receives the resolution of the source of time whose value can be obtained via KnGetUpTime()
.
Output parameter res
contains the resolution in RtlTimeSpec
format.
RtlTimeSpec
The timespec time format is defined by the RtlTimeSpec
structure (declared in the rtl/rtc.h
file).
typedef struct {
rtl_time_t sec; /**< integer number of seconds that have elapsed since the start of the Unix epoch
* or another defined point in time */
rtl_nsecs_t nsec; /**< adjustment in nanoseconds (number of nanoseconds
* that have elapsed since the point in time defined by the number of seconds*/
} RtlTimeSpec;
KosQueueAlloc()
This function is declared in the kos/queue.h
file.
void *KosQueueAlloc(KosQueueHandle queue);
Allocates memory for the new object from the queue
buffer.
If successful, the function returns the pointer to the memory for this object. If the buffer is full, it returns RTL_NULL.
Page topKosQueueCreate()
This function is declared in the kos/queue.h
file.
KosQueueHandle KosQueueCreate(unsigned objCount,
unsigned objSize,
unsigned objAlign,
void *buffer);
This function creates a queue of objects (fifo) and the buffer associated with this queue.
Parameters:
objCount
is the maximum number of objects in the queue.objSize
is the object size (bytes).objAlign
is the object alignment in bytes, and must be a power of two.buffer
is the pointer to the external buffer for objects; if it is set equal to RTL_NULL, the buffer will be allocated by using theKosMemAlloc()
function.
Returns the handle of the created queue and RTL_NULL if there is an error.
Page topKosQueueDestroy()
This function is declared in the kos/queue.h
file.
void KosQueueDestroy(KosQueueHandle queue);
This function deletes the specified queue
and frees its allocated buffer.
KosQueueFlush()
This function is declared in the kos/queue.h
file.
void KosQueueFlush(KosQueueHandle queue);
This function extracts all objects from the specified queue
and frees all the memory occupied by it.
KosQueueFree()
This function is declared in the kos/queue.h
file.
void KosQueueFree(KosQueueHandle queue, void *obj);
This function frees the memory occupied by object obj
in the buffer of the specified queue
.
The obj
pointer can be received by calling the KosQueueAlloc()
or KosQueuePop()
function.
For a usage example, see KosQueuePop()
.
KosQueuePop()
This function is declared in the kos/queue.h
file.
void *KosQueuePop(KosQueueHandle queue, rtl_uint32_t timeout);
This function extracts the object from the start of the specified queue
and returns the pointer to it.
The timeout
parameter determines the behavior of the function if the queue is empty:
- 0 – immediately return RTL_NULL.
- INFINITE_TIMEOUT – lock and wait for a new object in the queue.
- Any other value of
timeout
means that the system is waiting for a new object in the queue for the specifiedtimeout
in milliseconds; when this timeout expires, RTL_NULL is returned.
Example
int GpioEventDispatch(void *context)
{
GpioEvent *event;
GpioDevice *device = context;
rtl_bool proceed = rtl_true;
do {
event = KosQueuePop(device->queue, INFINITE_TIMEOUT);
if (event != RTL_NULL) {
if (event->type == GPIO_EVENT_TYPE_THREAD_ABORT) {
proceed = rtl_false;
} else {
GpioDeliverEvent(device, event);
}
KosQueueFree(device->queue, event);
}
} while (proceed);
KosPutObject(device);
return rcOk;
}
KosQueuePush()
This function is declared in the kos/queue.h
file.
void KosQueuePush(KosQueueHandle queue, void *obj);
Adds the obj
object to the end of the specified queue
.
The obj
pointer can be received by calling the KosQueueAlloc()
or KosQueuePop()
function.
IoReadBarrier()
This function is declared in the coresrv/io/barriers.h
file.
void IoReadBarrier(void);
Adds a read memory barrier. Linux equivalent: rmb()
.
IoReadWriteBarrier()
This function is declared in the coresrv/io/barriers.h
file.
void IoReadWriteBarrier(void);
Adds a combined barrier. Linux equivalent: mb()
.
IoWriteBarrier()
This function is declared in the coresrv/io/barriers.h
file.
void IoWriteBarrier(void);
Adds a write memory barrier. Linux equivalent: wmb()
.
Receiving information about CPU time and memory usage
The libkos
library provides an API that lets you receive information about CPU time and memory usage. This API is defined in the header file sysroot-*-kos/include/coresrv/stat/stat_api.h
from the KasperskyOS SDK.
To get information about CPU time and memory usage and other statistical data, you need to build a solution with a KasperskyOS kernel version that supports performance counters. For more details, refer to "Image library".
Receiving information about CPU time
CPU uptime is counted from the startup of the KasperskyOS kernel.
To receive information about CPU time, you need to use the KnGroupStatGetParam()
and KnTaskStatGetParam()
functions. The values provided in the table below need to be passed in the param
parameter of these functions.
Information about CPU time
Function |
Value of the |
Obtained value |
---|---|---|
|
|
CPU uptime in kernel mode |
|
|
CPU uptime in user mode |
|
|
CPU uptime in idle mode |
|
|
CPU uptime spent on process execution |
|
|
CPU uptime spent on process execution in user mode |
The CPU uptime obtained by calling the KnGroupStatGetParam()
or KnTaskStatGetParam()
function is presented in nanoseconds.
Receiving information about memory usage
To receive information about memory usage, you need to use the KnGroupStatGetParam()
and KnTaskStatGetParam()
functions. The values provided in the table below need to be passed in the param
parameter of these functions.
Information about memory usage
Function |
Value of the |
Obtained value |
---|---|---|
|
|
Total size of all installed RAM |
|
|
Size of free RAM |
|
|
Size of RAM used by the process |
The memory size obtained by calling the KnGroupStatGetParam()
or KnTaskStatGetParam()
function is presented as the number of memory pages. The size of a memory page is 4 KB for all hardware platforms supported by KasperskyOS.
The amount of RAM used by a process refers only to the memory allocated directly for this process. For example, if the memory of a process is mapped to an MDL buffer created by another process, the size of this buffer is not included in this value.
Enumerating processes
To get information about CPU time and memory usage by each process, do the following:
- Get the list of processes by calling the
KnGroupStatGetTaskList()
function. - Get the number of items on the list of processes by calling the
KnTaskStatGetTasksCount()
function. - Iterate through the list of processes, repeating the following steps:
- Get an item from the list of processes by calling the
KnTaskStatEnumTaskList()
function. - Get the process name by calling the
KnTaskStatGetName()
function.This is necessary to identify the process for which the information about CPU time and memory usage will be received.
- Get information about CPU time and memory usage by calling the
KnTaskStatGetParam()
function. - Verify that the process was not terminated. If the process was terminated, do not use the obtained information about CPU time and memory usage by this process.
To verify that the process was not terminated, you need to call the
KnTaskStatGetParam()
function, using theparam
parameter to pass theTASK_PARAM_STATE
value. A value other thanTaskStateTerminated
should be received. - Finish working with the item on the list of processes by calling the
KnTaskStatCloseTask()
function.
- Get an item from the list of processes by calling the
- Finish working with the list of processes by calling the
KnTaskStatCloseTaskList()
function.
Calculating CPU load
CPU load can be indicated as a percentage of total CPU load or as a percentage of CPU load by each process. These indicators are calculated for a specific time interval, at the start and end of which the information about CPU time utilization was received. (For example, CPU load can be monitored with periodic receipt of information about CPU time utilization.) The values obtained at the start of the interval need to be subtracted from the values obtained at the end of the interval. In other words, the following increments need to be obtained for the interval:
- TK – CPU uptime in kernel mode.
- TU – CPU uptime in user mode.
- TIDLE – CPU uptime in idle mode.
- Ti [i=1,2,...,n] – CPU time spent on execution of the ith process.
The percentage of total CPU load is calculated as follows:
(TK+TU)/(TK+TU+TIDLE).
The percentage of CPU load by the ith process is calculated as follows:
Ti/(TK+TU+TIDLE).
Receiving additional information about processes
In addition to information about CPU time and memory usage, the KnGroupStatGetParam()
and KnTaskStatGetParam()
functions also let you obtain the following information:
- Number of processes
- Number of threads
- Number of threads in one process
- Parent process ID (PPID)
- Process priority
- Number of handles owned by a process
- Size of virtual memory of a process
The KnTaskStatGetId()
function gets the process ID (PID).