KasperskyOS Community Edition 1.1

Contents

[Topic api][Topic libkos]

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 of libkos are in the kos 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:

#include <coresrv/io/io_api.h>

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 the libkos library.
  • services/io/IO.idl is the IDL description of the I/O manager.
  • io/io_dma.h and io/io_irq.h are header files of the kernel.
Page top
[Topic libkos_intro][Topic api_memory]

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 top
[Topic api_memory_states]

KnVmAllocate()

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; if addr 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.

Page top
[Topic kn_vm_allocate]

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 top
[Topic kn_vm_commit]

KnVmDecommit()

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 top
[Topic kn_vm_decommit]

KnVmProtect()

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).
Page top
[Topic kn_vm_protect]

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 top
[Topic kn_vm_unmap][Topic api_memory_alloc]

KosMemAlloc()

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.

Page top
[Topic kos_mem_alloc]

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).
Page top
[Topic kos_mem_alloc_ex]

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.
Page top
[Topic kos_mem_free]

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.
Page top
[Topic kos_mem_get_size]

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.

Page top
[Topic kos_mem_zalloc][Topic libkos_threads]

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.

Page top
[Topic kos_thread_callback]

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 top
[Topic kos_thread_callback_register]

KosThreadCallbackUnregister()

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 top
[Topic kos_thread_callback_unregister]

KosThreadCreate()

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) and ThreadPriorityHighest (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 the routine 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 */

...

}

Page top
[Topic kos_thread_create]

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 top
[Topic kos_thread_current_id]

KosThreadExit()

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.

Page top
[Topic kos_thread_exit]

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 top
[Topic kos_thread_get_stack]

KosThreadOnce()

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.

Page top
[Topic kos_thread_once]

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 top
[Topic kos_thread_resume]

KosThreadSleep()

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 top
[Topic kos_thread_sleep]

KosThreadSuspend()

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 top
[Topic kos_thread_suspend]

KosThreadTerminate()

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 top
[Topic kos_thread_terminate]

KosThreadTlsGet()

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 top
[Topic kos_thread_tls_get]

KosThreadTlsSet()

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.

Page top
[Topic kos_thread_tls_set]

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 top
[Topic kos_thread_wait]

KosThreadYield()

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.

Page top
[Topic kos_thread_yield][Topic api_handles]

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.

Page top
[Topic kn_handle_close]

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 top
[Topic kn_handle_create_badge]

KnHandleCreateUserObject()

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;

}

Page top
[Topic kn_handle_create_user_object]

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.

Page top
[Topic kn_handle_revoke]

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.

Page top
[Topic kn_handle_revoke_subtree]

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 top
[Topic nk_get_badge_op]

nk_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.

Page top
[Topic nk_is_handle_dereferenced]

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 the libkos 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 the libkos library.
  • services/handle/Notice.idl is an IDL description of the IPC interface of the Notification Subsystem.

In this section

Handle permissions mask

Creating handles

Transferring handles

Dereferencing handles

Revoking handles

Notifying about the state of resources

Deleting handles

OCap usage example

Page top
[Topic handles_manage]

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 top
[Topic libkos_handles_rights]

Creating 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 top
[Topic handles_create]

Transferring 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:

  1. An IPC channel is created between the programs.
  2. The solution security policy (security.psl) allows interaction between the programs.
  3. Interface methods are implemented for transferring handles.
  4. 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:

  1. The transferring client program packages the handles and handle permissions masks into the fields of the *_req requests structure of the nk_handle_desc_t type.
  2. The transferring client program calls the interface method for transferring handles to the server program. This method executes the Call() system call.
  3. The recipient server program receives the request by executing the Recv() system call.
  4. 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 the nk_handle_desc_t type.

A scenario for transferring handles from the server program to a client program includes the following steps:

  1. The recipient client program calls the interface method for receiving handles from the server program. This method executes the Call() system call.
  2. The transferring server program receives the request by executing the Recv() system call.
  3. 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 the nk_handle_desc_t type.
  4. The transferring server program responds to the request by executing the Reply() system call.
  5. 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 the nk_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.

Page top
[Topic libkos_handles_transfer]

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:

  1. The client program packages the handle into a field of the *_req request structure of the nk_handle_desc_t type.
  2. 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.
  3. The server program receives the request by executing the Recv() system call.
  4. 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 the nk_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 top
[Topic libkos_handles_dereference]

Revoking 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);

Page top
[Topic libkos_handles_revoke]

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:

  1. The KnNoticeCreate() function creates a notification receiver (object that stores notifications).
  2. 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.
  3. 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 KnNoticeCreate(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 KnNoticeSubscribeToObject(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 KnNoticeGetEvent(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 KnNoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);

Page top
[Topic libkos_handles_notification]

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);

Page top
[Topic libkos_handles_delete]

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:

  1. 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.
  2. The client calls the OpenResource() method to open access to the resource.
    1. 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.
    2. 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.
    3. 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.
    4. The OpenResource() method call completes successfully. The client extracts the handle and permissions mask of the handle from the handle transport container by using the nk_get_handle() and nk_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.
  3. The client calls the UseResource() method to utilize the resource.
    1. 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 the nk_handle_desc() macro to package the handle into the handle transport container.
    2. The handle is dereferenced, after which the resource provider receives the pointer to the resource transfer context.
    3. The resource provider uses the nk_is_handle_dereferenced() function to verify that the dereferencing operation was completed instead of a handle transfer.
    4. 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.
    5. 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.
    6. The UseResource() method call completes successfully. The client receives the results of the operation performed on the resource.
  4. The client calls the CloseResource() method to close access to the resource.
    1. 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 the nk_handle_desc() macro to package the handle into the handle transport container. After the CloseResource() method is called, the client uses the KnHandleClose() function to delete the handle.
    2. The handle is dereferenced, after which the resource provider receives the pointer to the resource transfer context.
    3. The resource provider uses the nk_is_handle_dereferenced() function to verify that the dereferencing operation was completed instead of a handle transfer.
    4. The resource provider uses the nk_get_badge() function to extract the pointer to the resource transfer context from the handle transport container.
    5. 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).
    6. The CloseResource() method call completes successfully.
  5. The resource provider frees up the memory that was allocated for the resource transfer context and the user resource context.
    1. The resource provider calls the KnNoticeGetEvent() function to receive a notification that the resource transfer context object was closed, and uses the KnHandleClose() function to delete the handle of the resource transfer context object.
    2. 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.
    3. 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.
Page top
[Topic libkos_handles_simple_scenario][Topic libkos_notice]

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.

Page top
[Topic event_mask]

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.

Page top
[Topic event_desc]

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 top
[Topic notice_create]

KnNoticeGetEvent()

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);

Page top
[Topic notice_get_event]

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 top
[Topic notice_set_object_event]

KnNoticeSubscribeToObject()

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().

Page top
[Topic notice_subscribe_to_object][Topic libkos_tasks]

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 top
[Topic entity_connect]

EntityConnectToService()

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 top
[Topic entity_connect_to_service]

EntityInfo

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;

Page top
[Topic entity_info]

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 top
[Topic entity_init]

EntityInitEx()

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 top
[Topic entity_init_ex]

EntityRun()

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 top
[Topic entity_run][Topic libkos_ns_cm]

KnCmAccept()

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 top
[Topic kn_cm_accept]

KnCmConnect()

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 top
[Topic kn_cm_connect]

KnCmDrop()

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 top
[Topic kn_cm_drop]

KnCmListen()

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 top
[Topic kn_cm_listen]

NsCreate()

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 top
[Topic ns_create]

NsEnumServices()

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 the NsCreate() 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 the server output parameter in bytes.
  • serviceSize is the maximum size of the buffer for the service 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 top
[Topic ns_enum_services]

NsPublishService()

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 the NsCreate() 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 top
[Topic ns_publish_service]

NsUnPublishService()

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 the NsCreate() 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 top
[Topic ns_unpublish_service][Topic api_sync]

KosCondvarBroadcast()

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.

Page top
[Topic kos_condvar_broadcast]

KosCondvarDeinit()

This function is declared in the kos/condvar.h file.

void KosCondvarDeinit(KosCondvar *condvar);

De-initializes the conditional variable condvar.

Page top
[Topic kos_condvar_deinit]

KosCondvarInit()

This function is declared in the kos/condvar.h file.

void KosCondvarInit(KosCondvar *condvar);

Initializes the conditional variable condvar.

Page top
[Topic kos_condvar_init]

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.

Page top
[Topic kos_condvar_signal]

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 top
[Topic kos_condvar_wait]

KosCondvarWaitTimeout()

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 top
[Topic kos_condvar_wait_timeout]

KosEventDeinit()

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).

Page top
[Topic kos_event_deinit]

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 top
[Topic kos_event_init]

KosEventReset()

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).

Page top
[Topic kos_event_reset]

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.

Page top
[Topic kos_event_set]

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 top
[Topic kos_event_wait]

KosEventWaitTimeout()

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 top
[Topic kos_event_wait_timeout]

KosMutexDeinit()

This function is declared in the kos/mutex.h file.

void KosMutexDeinit(KosMutex *mutex);

Deletes the specified mutex.

Page top
[Topic kos_mutex_deinit]

KosMutexInit()

This function is declared in the kos/mutex.h file.

void KosMutexInit(KosMutex *mutex);

Initializes the mutex in an unlocked state.

Page top
[Topic kos_mutex_init]

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.

Page top
[Topic kos_mutex_init_ex]

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 top
[Topic kos_mutex_lock]

KosMutexLockTimeout()

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 top
[Topic kos_mutex_lock_timeout]

KosMutexTryLock()

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 top
[Topic kos_mutex_try_lock]

KosMutexUnlock()

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.

Page top
[Topic kos_mutex_unlock]

KosRWLockDeinit()

This function is declared in the kos/rwlock.h file.

void KosRWLockDeinit(KosRWLock *rwlock);

De-initializes the read-write lock rwlock.

Page top
[Topic kos_rw_lock_deinit]

KosRWLockInit()

This function is declared in the kos/rwlock.h file.

void KosRWLockInit(KosRWLock *rwlock);

Initializes the read-write lock rwlock.

Page top
[Topic kos_rw_lock_init]

KosRWLockRead()

This function is declared in the kos/rwlock.h file.

void KosRWLockRead(KosRWLock *rwlock);

Locks the read threads.

Page top
[Topic kos_rw_lock_read]

KosRWLockTryRead()

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 top
[Topic kos_rw_lock_try_read]

KosRWLockTryWrite()

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 top
[Topic kos_rw_lock_try_write]

KosRWLockUnlock()

This function is declared in the kos/rwlock.h file.

void KosRWLockUnlock(KosRWLock *rwlock);

Removes the read-write lock rwlock.

Page top
[Topic kos_rw_lock_unlock]

KosRWLockWrite()

This function is declared in the kos/rwlock.h file.

void KosRWLockWrite(KosRWLock *rwlock);

Locks the write threads.

Page top
[Topic kos_rw_lock_write]

KosSemaphoreDeinit()

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.
Page top
[Topic kos_semaphore_deinit]

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.
Page top
[Topic kos_semaphore_init]

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.
Page top
[Topic kos_semaphore_signal]

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.
Page top
[Topic kos_semaphore_try_wait]

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.
Page top
[Topic kos_semaphore_wait]

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.
Page top
[Topic kos_semaphore_wait_timeout][Topic libkos_dma]

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;

Page top
[Topic dma_info]

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.
Page top
[Topic dma_attr]

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.

Page top
[Topic kn_io_dma_begin]

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 specified size.
  • 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;

}

Page top
[Topic kn_io_dma_create]

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.

Page top
[Topic kn_io_dma_get_info]

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.

Page top
[Topic kn_io_dma_get_phys_info]

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 using KnIoDmaCreate().
  • 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.

Page top
[Topic kn_io_dma_map][Topic libkos_iommu]

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 top
[Topic kn_iommu_attach_device]

KnIommuDetachDevice()

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 top
[Topic kn_iommu_detach_device][Topic libkos_ports]

IoReadIoPort8(), 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.

Page top

[Topic io_read_io_port]

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.

Page top
[Topic io_read_io_port_buffer]

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.

Page top
[Topic io_write_io_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.

Page top
[Topic io_write_io_port_buffer]

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;

}

Page top
[Topic kn_io_permit_port]

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.

Page top
[Topic kn_register_port]

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.

Page top
[Topic kn_register_ports][Topic libkos_mmio]

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.

Page top

[Topic io_read_mm_buffer]

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.

Page top
[Topic io_read_mm_reg]

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.

Page top
[Topic io_write_mm_buffer]

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.

Page top
[Topic io_write_mm_reg]

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;

}

Page top
[Topic kn_io_map_mem]

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.

Page top
[Topic kn_register_phy_mem]

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.

In this section

KnIoAttachIrq()

KnIoDetachIrq()

KnIoDisableIrq()

KnIoEnableIrq()

KnRegisterIrq()

Page top
[Topic libkos_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 the KnRegisterIrq() 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.
Page top
[Topic kn_io_attach_irq]

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 top
[Topic kn_io_detach_irq]

KnIoDisableIrq()

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 top
[Topic kn_io_disable_irq]

KnIoEnableIrq()

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 top
[Topic kn_io_enable_irq]

KnRegisterIrq()

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.

Page top
[Topic kn_register_irq]

Deallocating resources

In this section

KnIoClose()

Page top
[Topic libkos_close_resource]

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 top
[Topic kn_io_close][Topic libkos_time]

KnGetMSecSinceStart()

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 top
[Topic kn_get_msec_since_start]

KnGetRtcTime()

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;

Page top
[Topic kn_get_rtc_time]

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.

Page top
[Topic kn_get_system_time]

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.

Page top
[Topic kn_set_system_time]

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.

Page top
[Topic kn_get_system_time_res]

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.

Page top
[Topic kn_get_up_time]

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.

Page top
[Topic kn_get_up_time_res]

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;

Page top
[Topic rtl_time_spec][Topic libkos_queues]

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 top
[Topic kos_queue_alloc]

KosQueueCreate()

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 the KosMemAlloc() function.

Returns the handle of the created queue and RTL_NULL if there is an error.

Page top
[Topic kos_queue_create]

KosQueueDestroy()

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.

Page top
[Topic kos_queue_destroy]

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.

Page top
[Topic kos_queue_flush]

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().

Page top
[Topic kos_queue_free]

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 specified timeout 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;

}

Page top
[Topic kos_queue_pop]

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.

Page top
[Topic kos_queue_push][Topic libkos_memory_barriers]

IoReadBarrier()

This function is declared in the coresrv/io/barriers.h file.

void IoReadBarrier(void);

Adds a read memory barrier. Linux equivalent: rmb().

Page top
[Topic io_read_barrier]

IoReadWriteBarrier()

This function is declared in the coresrv/io/barriers.h file.

void IoReadWriteBarrier(void);

Adds a combined barrier. Linux equivalent: mb().

Page top
[Topic io_read_write_barrier]

IoWriteBarrier()

This function is declared in the coresrv/io/barriers.h file.

void IoWriteBarrier(void);

Adds a write memory barrier. Linux equivalent: wmb().

Page top
[Topic io_write_barrier]

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 param parameter

Obtained value

KnGroupStatGetParam()

GROUP_PARAM_CPU_KERNEL

CPU uptime in kernel mode

KnGroupStatGetParam()

GROUP_PARAM_CPU_USER

CPU uptime in user mode

KnGroupStatGetParam()

GROUP_PARAM_CPU_IDLE

CPU uptime in idle mode

KnTaskStatGetParam()

TASK_PARAM_TIME_TOTAL

CPU uptime spent on process execution

KnTaskStatGetParam()

TASK_PARAM_TIME_USER

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 param parameter

Obtained value

KnGroupStatGetParam()

GROUP_PARAM_MEM_TOTAL

Total size of all installed RAM

KnGroupStatGetParam()

GROUP_PARAM_MEM_FREE

Size of free RAM

KnTaskStatGetParam()

TASK_PARAM_MEM_PHY

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:

  1. Get the list of processes by calling the KnGroupStatGetTaskList() function.
  2. Get the number of items on the list of processes by calling the KnTaskStatGetTasksCount() function.
  3. Iterate through the list of processes, repeating the following steps:
    1. Get an item from the list of processes by calling the KnTaskStatEnumTaskList() function.
    2. 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.

    3. Get information about CPU time and memory usage by calling the KnTaskStatGetParam() function.
    4. 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 the param parameter to pass the TASK_PARAM_STATE value. A value other than TaskStateTerminated should be received.

    5. Finish working with the item on the list of processes by calling the KnTaskStatCloseTask() function.
  4. 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).

Page top
[Topic comp_res_util]

Sending and receiving IPC messages

In this section

Call()

Recv()

Reply()

Page top
[Topic ipc_api]

Call()

This function is declared in the coresrv/syscalls.h file.

Retcode Call(Handle handle, const SMsgHdr *msgOut, SMsgHdr *msgIn);

This function sends an IPC request to the server process and locks the calling thread until an IPC response or error is received. This function is called by the client process.

Parameters:

  • handle is the client IPC handle of the utilized channel.
  • msgOut is the buffer containing the IPC request.
  • msgIn is the buffer for the IPC response.

Returned value:

  • rcOk means that the exchange of IPC messages was successfully completed.
  • rcInvalidArgument means that the IPC request and/or IPC response has an invalid structure.
  • rcSecurityDisallow means that the Kaspersky Security Module prohibits forwarding of the IPC request or IPC response.
  • rcNotConnected means that the server IPC handle of the channel was not found.

Other return codes are available.

Page top
[Topic ipc_call]

Recv()

This function is declared in the coresrv/syscalls.h file.

Retcode Recv(Handle handle, SMsgHdr *msgIn);

This function locks the calling thread until an IPC request is received. This function is called by the server process.

Parameters:

  • handle is the server IPC handle of the utilized channel.
  • msgIn is the buffer for an IPC request.

Returned value:

  • rcOk means that an IPC request was successfully received.
  • rcInvalidArgument means that the IPC request has an invalid structure.
  • rcSecurityDisallow means that IPC request forwarding is prohibited by the Kaspersky Security Module.

Other return codes are available.

Page top
[Topic ipc_recv]

Reply()

This function is declared in the coresrv/syscalls.h file.

Retcode Reply(Handle handle, const SMsgHdr *msgOut);

This function sends an IPC response and locks the calling thread until the client receives a response or until an error is received. This function is called by the server process.

Parameters:

  • handle is the server IPC handle of the utilized channel.
  • msgOut is the buffer containing an IPC response.

Returned value:

  • rcOk means that an IPC response was successfully received by the client.
  • rcInvalidArgument means that the IPC response has an invalid structure.
  • rcSecurityDisallow means that IPC response forwarding is prohibited by the Kaspersky Security Module.

Other return codes are available.

Page top
[Topic ipc_reply][Topic posix_api]

POSIX support limitations

KasperskyOS uses a limited POSIX interface oriented toward the POSIX.1-2008 standard (without XSI support). These limitations are primarily due to security precautions.

Limitations affect the following:

  • Interaction between processes
  • Interaction between threads via signals
  • Standard input/output
  • Asynchronous input/output
  • Use of robust mutexes
  • Terminal operations
  • Shell usage
  • Management of file handles

Limitations include:

  • Unimplemented interfaces
  • Interfaces that are implemented with deviations from the POSIX.1-2008 standard
  • Stub interfaces that do not perform any operations except assign the ENOSYS value to the errno variable and return the value -1

In KasperskyOS, signals cannot interrupt the Call(), Recv(), and Reply() system calls that support the operation of libraries that implement the POSIX interface.

The KasperskyOS kernel does not transmit signals.

Limitations on interaction between processes

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

fork()

Create a new (child) process.

Stub

unistd.h

pthread_

atfork()

Register the handlers that are called before and after the child process is created.

Not implemented

pthread.h

wait()

Wait for the child process to stop or complete.

Stub

sys/wait.h

waitid()

Wait for the state of the child process to change.

Not implemented

sys/wait.h

waitpid()

Wait for the child process to stop or complete.

Stub

sys/wait.h

execl()

Run the executable file.

Stub

unistd.h

execle()

Run the executable file.

Stub

unistd.h

execlp()

Run the executable file.

Stub

unistd.h

execv()

Run the executable file.

Stub

unistd.h

execve()

Run the executable file.

Stub

unistd.h

execvp()

Run the executable file.

Stub

unistd.h

fexecve()

Run the executable file.

Stub

unistd.h

setpgid()

Move the process to another group or create a group.

Stub

unistd.h

setsid()

Create a session.

Not implemented

unistd.h

getpgrp()

Get the group ID for the calling process.

Not implemented

unistd.h

getpgid()

Get the group ID.

Stub

unistd.h

getppid()

Get the ID of the parent process.

Not implemented

unistd.h

getsid()

Get the session ID.

Stub

unistd.h

times()

Get the time values for the process and its descendants.

Stub

sys/times.h

kill()

Send a signal to the process or group of processes.

Only the SIGTERM signal can be sent. The pid parameter is ignored.

signal.h

pause()

Wait for a signal.

Not implemented

unistd.h

sigpending()

Check for received blocked signals.

Not implemented

signal.h

sigprocmask()

Get and change the set of blocked signals.

Stub

signal.h

sigsuspend()

Wait for a signal.

Stub

signal.h

sigwait()

Wait for a signal from the defined set of signals.

Stub

signal.h

sigqueue()

Send a signal to the process.

Not implemented

signal.h

sigtimedwait()

Wait for a signal from the defined set of signals.

Not implemented

signal.h

sigwaitinfo()

Wait for a signal from the defined set of signals.

Not implemented

signal.h

sem_init()

Create an unnamed semaphore.

You cannot create an unnamed semaphore for synchronization between processes. If a non-zero value is passed to the function through the pshared parameter, it will only return the value -1 and will assign the ENOTSUP value to the errno variable.

semaphore.h

sem_open()

Create/open a named semaphore.

You cannot open a named semaphore that was created by another process. Named semaphores (like unnamed semaphores) are local, which means that they are accessible only to the process that created them.

semaphore.h

pthread_

mutexattr_

setpshared()

Define the mutex attribute that allows the mutex to be used by multiple processes.

You cannot define the mutex attribute that allows the mutex to be used by multiple processes. If the PTHREAD_PROCESS_SHARED value is passed to the function through the pshared parameter, it will only return the ENOSYS value.

pthread.h

pthread_

barrierattr_

setpshared()

Define the barrier attribute that allows the barrier to be used by multiple processes.

You cannot define the barrier attribute that allows the barrier to be used by multiple processes. If the PTHREAD_PROCESS_SHARED value is passed to the function through the pshared parameter, it will only return the ENOSYS value.

pthread.h

pthread_

condattr_

setpshared()

Define the conditional variable attribute that allows the conditional variable to be used by multiple processes.

You cannot define the conditional variable attribute that allows the conditional variable to be used by multiple processes. If the PTHREAD_PROCESS_SHARED value is passed to the function through the pshared parameter, it will only return the ENOSYS value.

pthread.h

pthread_

rwlockattr_

setpshared()

Define the read/write lock object attribute that allows the read/write lock object attribute to be used by multiple processes.

You cannot define the read/write lock object attribute that allows the read/write lock object attribute to be used by multiple processes. If the PTHREAD_PROCESS_SHARED value is passed to the function through the pshared parameter, it will only return the ENOSYS value.

pthread.h

pthread_

spin_init()

Create a spin lock.

You cannot create a spin lock for synchronization between processes. If the PTHREAD_PROCESS_SHARED value is passed to the function through the pshared parameter, this value will be ignored.

pthread.h

shm_open()

Create or open a shared memory object.

Not implemented

sys/mman.h

mmap()

Map to memory.

You cannot perform memory mapping for interaction between processes. If the MAP_SHARED and PROT_WRITE values are passed to the function through the flags and prot parameters, respectively, the function will return the MAP_FAILED value and will assign the EACCES value to the errno variable. For all other possible values of the prot parameter, the MAP_SHARED value of the flags parameter will be ignored. In addition, you cannot pass combinations of the PROT_WRITE|PROT_EXEC and PROT_READ|PROT_WRITE|PROT_EXEC flags through the prot parameter. In this case, the function will only return the MAP_FAILED value and will assign the ENOMEM value to the errno variable.

sys/mman.h

mprotect()

Define the memory access permissions.

This function works as a stub by default. To use this function, define special settings for the KasperskyOS kernel.

sys/mman.h

pipe()

Create an unnamed channel.

You cannot use an unnamed channel for data transfer between processes. Unnamed channels are local, which means that they are accessible only to the process that created them.

unistd.h

mkfifo()

Create a special FIFO file (named channel).

Stub

sys/stat.h

mkfifoat()

Create a special FIFO file (named channel).

Not implemented

sys/stat.h

Limitations on interaction between threads via signals

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

pthread_kill()

Send a signal to a thread.

You cannot send a signal to a thread. If a signal number is passed to the function through the sig parameter, it only returns the ENOSYS value.

signal.h

pthread_sigmask()

Get and change the set of blocked signals.

Stub

signal.h

siglongjmp()

Restore the state of the control thread and the signals mask.

Not implemented

setjmp.h

sigsetjmp()

Save the state of the control thread and the signals mask.

Not implemented

setjmp.h

Standard input/output limitations

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

dprintf()

Formatted print to file.

Not implemented

stdio.h

fmemopen()

Use memory as a data stream.

Not implemented

stdio.h

open_memstream()

Use dynamically allocated memory as a data stream.

Not implemented

stdio.h

vdprintf()

Formatted print to file.

Not implemented

stdio.h

Asynchronous input/output limitations

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

aio_cancel()

Cancel input/output requests that are waiting to be handled.

Not implemented

aio.h

aio_error()

Receive an error from an asynchronous input/output operation.

Not implemented

aio.h

aio_fsync()

Request the execution of input/output operations.

Not implemented

aio.h

aio_read()

Request a file read operation.

Not implemented

aio.h

aio_return()

Get the status of an asynchronous input/output operation.

Not implemented

aio.h

aio_suspend()

Wait for the completion of asynchronous input/output operations.

Not implemented

aio.h

aio_write()

Request a file write operation.

Not implemented

aio.h

lio_listio()

Request execution of a set of input/output operations.

Not implemented

aio.h

Limitations on the use of robust mutexes

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

pthread_mutex_consistent()

Return a robust mutex to a consistent state.

Not implemented

pthread.h

pthread_mutexattr_getrobust()

Get a robust mutex attribute.

Not implemented

pthread.h

pthread_mutexattr_setrobust()

Define a robust mutex attribute.

Not implemented

pthread.h

Terminal operation limitations

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

ctermid()

Get the path to the file of the control terminal.

This function only returns or passes an empty string through the s parameter.

stdio.h

tcsetattr()

Define the terminal settings.

The input speed, output speed, and other settings specific to hardware terminals are ignored.

termios.h

tcdrain()

Wait for output completion.

This function only returns the value -1.

termios.h

tcflow()

Suspend or resume receipt or transmission of data.

Suspending output and resuming suspended output are not supported.

termios.h

tcflush()

Clear the input queue or output queue, or both of these queues.

This function only returns the value -1.

termios.h

tcsendbreak()

Break the connection with the terminal for a set time.

This function only returns the value -1.

termios.h

ttyname()

Get the path to the terminal file.

This function only returns a null pointer.

unistd.h

ttyname_r()

Get the path to the terminal file.

This function only returns an error value.

unistd.h

tcgetpgrp()

Get the ID of a group of processes using the terminal.

This function only returns the value -1.

unistd.h

tcsetpgrp()

Define the ID for a group of processes using the terminal.

This function only returns the value -1.

unistd.h

tcgetsid()

Get the ID of a group of processes for the leader of the session connected to the terminal.

This function only returns the value -1.

termios.h

Shell operation limitations

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

popen()

Create a child process for command execution and a channel for this process.

This function only assigns the ENOSYS value to the errno variable and returns the value NULL.

stdio.h

pclose()

Close the channel with the child process created by the popen() function, and wait for this child process to terminate.

This function cannot be used because its input parameter is the data stream handle returned by the popen() function, which cannot return anything except the value NULL.

stdio.h

system()

Create a child process for command execution.

Stub

stdlib.h

wordexp()

Perform a shell-like expansion of the string.

Not implemented

wordexp.h

wordfree()

Free up the memory allocated for the results of calling the wordexp() interface.

Not implemented

wordexp.h

Limitations on management of file handles

Interface

Purpose

Implementation

Header file based on the POSIX.1-2008 standard

dup()

Make a copy of the handle of an opened file.

Handles of regular files, standard I/O streams, sockets and channels are supported. There is no guarantee that the lowest available handle will be received.

fcntl.h

dup2()

Make a copy of the handle of an opened file.

Handles of regular files, standard I/O streams, sockets and channels are supported. The handle of an opened file needs to be passed through the fildes2 parameter.

fcntl.h

Page top

[Topic posix_uns_ifaces]

Concurrently using POSIX and other interfaces

Using libkos together with Pthreads

In a thread created using Pthreads, you cannot use the following libkos interfaces:

The following libkos interfaces can be used together with Pthreads (and other POSIX interfaces):

Using POSIX together with libkos threads

POSIX methods cannot be used in threads that were created using libkos threads.

Using IPC together with Pthreads/libkos threads

Methods for IPC can be used in any threads that were created using Pthreads or libkos threads.

Page top
[Topic posix_and_libkos]

MessageBus component

The MessageBus component implements the message bus that ensures receipt, distribution and delivery of messages between applications running KasperskyOS. This bus is based on the publisher-subscriber model. Use of a message bus lets you avoid having to create a large number of IPC channels to connect each subscriber application to each publisher application.

Messages transmitted through the MessageBus cannot contain data. These messages can be used only to notify subscribers about events. See "Message structure" section below.

The MessageBus component provides an additional level of abstraction over KasperskyOS IPC that helps simplify the development and expansion of application-layer applications. MessageBus is a separate program that is accessed through IPC. However, developers are provided with a MessageBus access library that lets you avoid direct use of IPC calls.

The API of the access library provides the following interfaces:

  • IProviderFactory provides factory methods for obtaining access to instances of all other interfaces.
  • IProviderControl is the interface for registering and deregistering a publisher and subscriber in the bus.
  • IProvider (MessageBus component) is the interface for transferring a message to the bus.
  • ISubscriber is the callback interface for sending a message to a subscriber.
  • IWaiter is the interface for waiting for a callback when the corresponding message appears.

Message structure

Each message contains two parameters:

  • topic is the identifier of the message subject.
  • id is an additional parameter that identifies a particular message.

The topic and id parameters are unique for each message. The interpretation of topic+id is determined by the contract between the publisher and subscriber. For example, if there are changes to the configuration data used by the publisher and subscriber, the publisher forwards a message regarding the modified data and the id of the specific entry containing the new data. The subscriber uses mechanisms outside of the MessageBus to receive the new data based on the id key.

In this section

IProviderFactory interface

IProviderControl interface

IProvider interface (MessageBus component)

ISubscriber, IWaiter and ISubscriberRunner interfaces

Page top
[Topic messagebus_component]

IProviderFactory interface

The IProviderFactory interface provides factory methods for receiving the interfaces necessary for working with the MessageBus component.

A description of the IProviderFactory interface is provided in the file named messagebus/i_messagebus_control.h.

An instance of the IProviderFactory interface is obtained by using the free InitConnection() function, which receives the name of the IPC connection between the application software and the MessageBus program. The connection name is defined in the init.yaml.in file when describing the solution configuration. If the connection is successful, the output parameter contains a pointer to the IProviderFactory interface.

  • The interface for registering and deregistering (see "IProviderControl interface") publishers and subscribers in the message bus is obtained by using the IProviderFactory::CreateBusControl() method.
  • The interface containing the methods enabling the publisher to send messages to the bus (see "IProvider interface (MessageBus component)") is obtained by using the IProviderFactory::CreateBus() method.
  • The interfaces containing the methods enabling the subscriber to receive messages from the bus (see "ISubscriber, IWaiter and ISubscriberRunner interfaces") are obtained by using the IProviderFactory::CreateCallbackWaiter and IProviderFactory::CreateSubscriberRunner() methods.

    It is not recommended to use the IWaiter interface, because calling a method of this interface is a locking call.

i_messagebus_control.h (fragment)

class IProviderFactory

{

...

virtual fdn::ResultCode CreateBusControl(IProviderControlPtr& controlPtr) = 0;

virtual fdn::ResultCode CreateBus(IProviderPtr& busPtr) = 0;

virtual fdn::ResultCode CreateCallbackWaiter(IWaiterPtr& waiterPtr) = 0;

virtual fdn::ResultCode CreateSubscriberRunner(ISubscriberRunnerPtr& runnerPtr) = 0;

...

};

...

fdn::ResultCode InitConnection(const std::string& connectionId, IProviderFactoryPtr& busFactoryPtr);

Page top
[Topic messagebus_component_iproviderfactory]

IProviderControl interface

The IProviderControl interface provides the methods for registering and deregistering publishers and subscribers in the message bus.

A description of the IProviderControl interface is provided in the file named messagebus/i_messagebus_control.h.

The IProviderFactory interface is used to obtain an interface instance.

Registering and deregistering a publisher

The IProviderControl::RegisterPublisher() method is used to register the publisher in the message bus. This method receives the message subject and puts the unique ID of the bus client into the output parameter. If the message subject is already registered in the bus, the call will be declined and the client ID will not be filled.

The IProviderControl::UnregisterPublisher() method is used to deregister a publisher in the message bus. This method accepts the bus client ID received during registration. If the indicated ID is not registered as a publisher ID, the call will be declined.

i_messagebus_control.h (fragment)

class IProviderControl

{

...

virtual fdn::ResultCode RegisterPublisher(const Topic& topic, ClientId& id) = 0;

virtual fdn::ResultCode UnregisterPublisher(ClientId id) = 0;

...

};

Registering and deregistering a subscriber

The IProviderControl::RegisterSubscriber() method is used to register the subscriber in the message bus. This method accepts the subscriber name and the list of subjects of messages for the necessary subscription, and puts the unique ID of the bus client into the output parameter.

The IProviderControl::UnregisterSubscriber() method is used to deregister a subscriber in the message bus. This method accepts the bus client ID received during registration. If the indicated ID is not registered as a subscriber ID, the call will be declined.

i_messagebus_control.h (fragment)

class IProviderControl

{

...

virtual fdn::ResultCode RegisterSubscriber(const std::string& subscriberName, const std::set<Topic>& topics, ClientId& id) = 0;

virtual fdn::ResultCode UnregisterSubscriber(ClientId id) = 0;

...

};

Page top
[Topic messagebus_component_icontrol]

IProvider interface (MessageBus component)

The IProvider interface provides the methods enabling the publisher to send messages to the bus.

A description of the IProvider interface is provided in the file named messagebus/i_messagebus.h.

The IProviderFactory interface is used to obtain an interface instance.

Sending a message to the bus

The IProvider::Push() method is used to send a message. This method accepts the bus client ID received during registration and the message ID. If the message queue in the bus is full, the call will be declined.

i_messagebus.h (fragment)

class IProvider

{

public:

...

virtual fdn::ResultCode Push(ClientId id, BundleId dataId) = 0;

...

};

Page top
[Topic messagebus_component_iprovider]

ISubscriber, IWaiter and ISubscriberRunner interfaces

The ISubscriber, IWaiter, and ISubscriberRunner interfaces provide the methods enabling the subscriber to receive messages from the bus and process them.

Descriptions of the ISubscriber, IWaiter and ISubscriberRunner interfaces are provided in the file named messagebus/i_subscriber.h.

The IProviderFactory interface is used to obtain instances of the IWaiter and ISubscriberRunner interfaces. The implementation of the ISubscriber callback interface is provided by the subscriber application.

Receiving a message from the bus

You can use the IWaiter::Wait() or ISubscriberRunner::Run() method to switch a subscriber to standby mode, waiting for a message from the bus. These methods accept the bus client ID and the pointer to the ISubscriber callback interface. If the client ID is not registered, the call will be declined.

It is not recommended to use the IWaiter interface, because calling the IWaiter::Wait() method is a locking call.

The ISubscriber::OnMessage() method will be called when a message is received from the bus. This method accepts the message subject and message ID.

i_subscriber.h (fragment)

class ISubscriber

{

...

virtual fdn::ResultCode OnMessage(const std::string& topic, BundleId id) = 0;

};

...

class IWaiter

{

...

[[deprecated("Use ISubscriberRunner::Run method instead.")]]

virtual fdn::ResultCode Wait(ClientId id, const ISubscriberPtr& subscriberPtr) = 0;

};

...

class ISubscriberRunner

{

...

virtual fdn::ResultCode Run(ClientId id, const ISubscriberPtr& subscriberPtr) = 0;

};

Page top
[Topic messagebus_component_isubwait]

Return codes

Overview

In a KasperskyOS-based solution, the return codes of functions of various APIs (for example, APIs of the libkos and kdf libraries, drivers, transport code, and application software) are 32-bit signed integers. This type is defined in the sysroot-*-kos/include/rtl/retcode.h header file from the KasperskyOS SDK as follows:

typedef __INT32_TYPE__ Retcode;

The set of return codes consists of a success code with a value of 0 and error codes. An error code is interpreted as a data structure whose format is described in the sysroot-*-kos/include/rtl/retcode.h header file from the KasperskyOS SDK. This format provides for multiple fields that contain not only information about the results of a function call, but also the following additional information:

  • Flag in the Customer field indicating that the error code was defined by the developers of the KasperskyOS-based solution and not by the developers of software from the KasperskyOS SDK.

    Thanks to the flag in the Customer field, developers of a KasperskyOS-based solution and developers of software from the KasperskyOS SDK can define error codes from non-overlapping sets.

  • Global ID of the error code in the Space field.

    Global IDs let you define non-overlapping sets of error codes. Error codes can be generic or specific. Generic error codes can be used in the APIs of any solution components and in the APIs of any constituent parts of solution components (for example, a driver or VFS may be a constituent part of a solution component). Specific error codes are used in the APIs of one or more solution components or in the APIs of one or more constituent parts of solution components.

    For example, the RC_SPACE_GENERAL ID corresponds to generic errors, the RC_SPACE_KERNEL ID corresponds to error codes of the kernel, and the RC_SPACE_DRIVERS ID corresponds to error codes of drivers.

  • Local ID of the error code in the Facility field.

    Local IDs let you define non-overlapping subsets of error codes within the set of error codes corresponding to one global ID. For example, the set of error codes with the global ID RC_SPACE_DRIVERS includes non-overlapping subsets of error codes with the local IDs RC_FACILITY_I2C, RC_FACILITY_USB, and RC_FACILITY_BLKDEV.

The global and local IDs of specific error codes are assigned by the developers of a KasperskyOS-based solution and by the developers of software from the KasperskyOS SDK independently of each other. In other words, two sets of global IDs are generated. Each global ID has a unique meaning within one set. Each local ID has a unique meaning within a set of local IDs related to one global ID. Generic error codes can be used in any API.

This type of centralized approach helps avoid situations in which the same error codes have various meanings within a KasperskyOS-based solution. This is necessary to eliminate a potential problem transmitting error codes through different APIs. For example, this problem occurs when drivers call kdf library functions, receive error codes, and return these codes through their own APIs. If error codes are generated without a centralized approach, the same error code can have different meanings for the kdf library and for the driver. Under these conditions, drivers return correct error codes only if the error codes of the kdf library are converted into error codes of each driver. In other words, error codes in a KasperskyOS-based solution are assigned in such way that does not require conversion of these codes during their transit through various APIs.

The information about return codes provided here does not apply to functions of a POSIX interface or the APIs of third-party software used in KasperskyOS-based solutions.

Generic return codes

Return codes that are generic for APIs of all solution components and their constituent parts are defined in the sysroot-*-kos/include/rtl/retcode.h header file from the KasperskyOS SDK. Descriptions of generic return codes are provided in the table below.

Generic return codes

Return code

Description

rcOk (corresponds to the 0 value)

The function completed successfully.

rcInvalidArgument

Invalid function argument.

rcNotConnected

No connection between the client and server sides of interaction.

For example, there is no server IPC handle.

rcOutOfMemory

Insufficient memory to perform the operation.

rcBufferTooSmall

Buffer too small.

rcInternalError

The function ended with an internal error related to incorrect logic.

Some examples of internal errors include values outside of the permissible limits, and null indicators and values where they are not permitted.

rcTransferError

Error sending an IPC message.

rcReceiveError

Error receiving an IPC message.

rcSourceFault

IPC message was not transmitted due to the IPC message source.

rcTargetFault

IPC message was not transmitted due to the IPC message recipient.

rcIpcInterrupt

IPC was interrupted by another process thread.

rcRestart

Indicates that the function needs to be called again.

rcFail

The function ended with an error.

rcNoCapability

The operation cannot be performed on the resource.

rcNotReady

Initialization failed.

rcUnimplemented

The function was not implemented.

rcBufferTooLarge

Buffer too large.

rcBusy

Resource temporarily unavailable.

rcResourceNotFound

Resource not found.

rcTimeout

Timed out.

rcSecurityDisallow

The operation was denied by security mechanisms.

rcFutexWouldBlock

The operation will result in a block.

rcAbort

The operation was aborted.

rcInvalidThreadState

Invalid function called in the interrupt handler.

rcAlreadyExists

Set of elements already contains the element being added.

rcInvalidOperation

Operation cannot be completed.

rcHandleRevoked

Resource access rights were revoked.

rcQuotaExceeded

Resource quota exceeded.

rcDeviceNotFound

Device not found.

Defining error codes

To define an error code, the developer of a KasperskyOS-based solution needs to use the MAKE_RETCODE() macro defined in the sysroot-*-kos/include/rtl/retcode.h header file from the KasperskyOS SDK. The developer must also use the customer parameter to pass the symbolic constant RC_CUSTOMER_TRUE.

Example:

#define LV_EBADREQUEST MAKE_RETCODE(RC_CUSTOMER_TRUE, RC_SPACE_APPS, RC_FACILITY_LogViewer, 5, "Bad request")

An error description that is passed via the desc parameter is not used by the MAKE_RETCODE() macro. This description is needed to create a database of error codes when building a KasperskyOS-based solution. At present, a mechanism for creating and using such a database has not been implemented.

Reading error code structure fields

The RC_GET_CUSTOMER(), RC_GET_SPACE(), RC_GET_FACILITY() and RC_GET_CODE() macros defined in the sysroot-*-kos/include/rtl/retcode.h header file from the KasperskyOS SDK let you read error code structure fields.

The RETCODE_HR_PARAMS() and RETCODE_HR_FMT() macros defined in the sysroot-*-kos/include/rtl/retcode_hr.h header file from the KasperskyOS SDK are used for formatted display of error details.

Page top
[Topic return_codes]