The API is defined in the header file sysroot-*-kos/include/coresrv/io/irq.h from the KasperskyOS SDK.
The API manages the handling of hardware interrupts. A hardware interrupt is a signal sent from a device to direct the processor to immediately pause execution of the current program and instead handle an event related to this device. For example, pressing a key on the keyboard invokes a hardware interrupt that ensures the required response to this pressed key (for example, input of a character).
A hardware interrupt occurs when the device queries the interrupt controller. This query can be transmitted through a hardware interrupt line between the device and the interrupt controller or through MMIO memory. In the second case, the device writes to MMIO memory by calling the Message Signaled Interrupt (MSI).
Each hardware interrupt line corresponds to one interrupt with a unique number.
Two types of message signaled interrupts are supported: MSI and MSI-X (extended version).
Information about API functions is provided in the table below.
Using the API
To attach an interrupt to its handler, complete the following steps:
To register an interrupt that occurs when a device queries the interrupt controller through the hardware interrupt line, call the KnRegisterIrq() function. If such an interrupt needs to be registered multiple times, the MMIO_U_SHARED flag must be specified in the flags parameter during each registration. If the registered interrupt is used by the kernel code, the MMIO_K_SHARED flag must be specified. If these flags are not specified, only the code that requests this access first (this can be either the kernel code or the code that is executed in user mode) will have access to the interrupt. All subsequent registration attempts by calling the KnRegisterIrq() function will end with the rcAlreadyExists error, and messages regarding the interrupt sharing problem will be added to the diagnostic output. If the kernel fails to access the interrupt because this interrupt is already registered by the code being executed in user mode, a message regarding the interrupt sharing problem will also be added to the diagnostic output.
To register a message signaled interrupt, call the KnIoRegisterMsiIrq() function after first creating a message signaled interrupt object by calling the KnIoAllocMsi() function. The MSI object handle can be transferred to another process via IPC. One object can be associated with only one message signaled interrupt at a time. A message signaled interrupt registration object can be reused only after closing the handle of the previously registered interrupt. After registering the message signaled interrupt, the object handle can be closed.
The data received through the addr and data output parameters of the KnIoAllocMsi() function must be passed to the PCIe bus controller to configure the message signaled interrupts (such as the MSI or MSI-X type) for the specified device. Moreover, one interrupt of the MSI type or one or more interrupts of the MSI-X type can be configured for one device. (The KnIoAllocMsi() function does not allow allocation of a sequence of interrupt vectors, thereby making it impossible to support multiple interrupts of the MSI type for one device.) If you need to configure one interrupt of the MSI or MSI-X type for a device, you must create one message signaled interrupt object via a single call of the KnIoAllocMsi() function. If you need to configure multiple MSI-X interrupts for a device, you must create the same number of message signaled interrupt objects via several calls of the KnIoAllocMsi() function. If the maximum possible number of message signaled interrupt objects have been created in the system, the KnIoAllocMsi() function returns rcResourceNotFound. If the maximum possible number of message signaled interrupt objects with the same interrupt priority have been created in the system, the KnIoAllocMsi() function returns rcFail. If the maximum number of message signaled interrupt objects have been created for the device, the KnIoAllocMsi() function returns rcFail.
An interrupt handle obtained by calling the KnRegisterIrq() or KnIoRegisterMsiIrq() function can be passed to another process via IPC.
KnIoAttachIrq() function.This step is performed by the thread in whose context the interrupt will be handled.
When using the interrupt handle obtained by calling the KnRegisterIrq() or KnIoRegisterMsiIrq() function, you can attach only one thread to an interrupt. In contrast to a message signaled interrupt, the interrupt that occurs when the device queries the interrupt controller via the hardware interrupt line can be attached to multiple threads in one or more processes. To do so, you must use different handles of the same interrupt obtained from separate calls of the KnRegisterIrq() function with the same flags in the flags parameter.
A handle obtained by calling the KnIoAttachIrq() function cannot be transferred to another process via IPC.
To deny (mask) an interrupt, call the KnIoDisableIrq() or KnIoDisableIrqNoSync() function. The KnIoDisableIrq() function returns control after completion of the current iteration in the maskable interrupt handler except for a case in which the function is called from this handler. In this case, the KnIoDisableIrq() function behaves like the KnIoDisableIrqNoSync() function, which always returns control without waiting for completion of the current iteration in the maskable interrupt handler. In other words, the current iteration in the interrupt handler may be completed after the KnIoDisableIrqNoSync() function has returned control. The KnIoDisableIrq() function cannot be called from a critical section that is synchronized with a critical section in the maskable interrupt handler or in the handler of another interrupt.
To allow (unmask) the interrupt, call the KnIoEnableIrq() function. (After an interrupt is registered and a thread is attached to it, this interrupt does not require unmasking.)
Although the KnIoDisableIrq(), KnIoDisableIrqNoSync(), and KnIoEnableIrq() functions receive an interrupt handle through which only one thread is attached to the interrupt, their effect applies to all threads attached to this interrupt. (This does not apply to message signaled interrupts to which only one thread can be attached.)
To initiate detachment of a thread from an interrupt, call the KnIoDetachIrq() function outside of the thread that is attached to the interrupt. Detachment is performed by the thread attached to the interrupt by calling the KnThreadDetachIrq() function from the thread_api.h API.
Handling an interrupt
After attaching to an interrupt, the thread calls the Call() function from the syscalls.h API. The thread is locked as a result of this call. When an interrupt occurs or the KnIoDetachIrq() function is called, the KasperskyOS kernel sends an IPC message to the process that contains this thread. This IPC message contains a request to handle the interrupt or a request to detach the thread from the interrupt. When a process receives an IPC message, the Call() function in the thread attached to the interrupt returns control and provides the contents of the IPC message to the thread. The thread extracts the request from the IPC message and either processes the interrupt or detaches from the interrupt. If the interrupt is processed, information about its failure or success upon completion is added to the response IPC message that is sent to the kernel by the next Call() function call in the loop.
When processing an interrupt, use the IoGetIrqRequest() and IoSetIrqAnswer() functions that are declared in the header file sysroot-*-kos/include/io/io_irq.h from the KasperskyOS SDK. These functions let you extract data from IPC messages and add data to IPC messages for data exchange between the kernel and the thread attached to the interrupt.
The standard interrupt processing loop includes the following steps:
IoSetIrqAnswer() function.To complete this step, call the Call() functions. In the handle parameter, you must specify the handle that was received when the KnIoAttachIrq() function was called. You must use the msgOut parameter to define the IPC message that will be sent to the kernel, and use the msgIn parameter to define the IPC message that will be received from the kernel.
IoGetIrqRequest() function.If the request requires detachment from the interrupt, exit the interrupt processing loop and call the KnThreadDetachIrq() function from the API thread_api.h.
Deregistering an interrupt
To deregister an interrupt, complete the following steps:
To complete this step, use the KnThreadDetachIrq() function from the API thread_api.h.
KnIoAttachIrq() function was called.In the case of a message signaled interrupt, you must additionally close or revoke the message signaled interrupt object handles in all processes that own these handles.
Information about API functions
irq.h functions
Function |
Information about the function |
|---|---|
|
Purpose Registers an interrupt that occurs when a device queries an interrupt controller through a hardware interrupt line. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Attaches the calling thread to an interrupt. Parameters
Returned values If successful, the function returns |
|
Purpose Sends a request to a thread. When this request is fulfilled, the thread must detach from the interrupt. Parameters
Returned values If successful, the function returns |
|
Purpose Enables (unmasks) an interrupt. Parameters
Returned values If successful, the function returns |
|
Purpose Denies (masks) an interrupt, optionally waiting for completion of the current iteration in the maskable interrupt handler. Parameters
Returned values If successful, the function returns Additional information The function does not wait for completion of the current iteration in the maskable interrupt handler if it is called from this handler. |
|
Purpose Denies (masks) an interrupt without waiting for completion of the current iteration in the maskable interrupt handler. Parameters
Returned values If successful, the function returns |
|
Purpose Creates a message signaled interrupt object. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Registers a message signaled interrupt. Parameters
Returned values If successful, the function returns |