KasperskyOS Community Edition 1.1

Contents

[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]