OCEOS/oceos kernel/interrupt

From wiki
Revision as of 17:49, 23 March 2022 by Okhoruzhyy (talk | contribs) (→‎API Functions (SPARC only))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

OCEOS Interrupts

Introduction

SPARC

Interrupt handler code is written by the application developer. Normal practice is to keep interrupt handlers as short as possible, and to delegate processing to an appropriate task by placing a job on the ready queue. If this is done, to ensure a high priority job is started immediately, the scheduler needs to be called at the end of interrupt processing, i.e. at the end of the outermost nested interrupt if nesting is used.

SPARC Interrupts Introduction

Interrupting traps are controlled by the Processor Interrupt Level (PIL) field of the Processor Status Register (PSR) and by the Trap Enable (ET) field of the PSR.
The Trap Base Address (TBA) in the Trap Base register (TBR) must be set to the top 20 bits of the trap table address, which must be on a 4k boundary for MVT.

When the target hardware is configured to support single vector trapping (SVT), the -qsvt switch can be used with the linker to build an image which uses a two-level trap dispatch table rather than the standard one-level trap table. The code saving amounts to ~4KiB for the trap table and trap handling is slightly slower with single vector trapping. The number of extra instructions needed for single vector trapping dispatching is constant.

Interrupts are re-enabled automatically on exit from the interrupt handler, when the processor state is restored to its previous value. Alternatively, the interrupt handler itself can re-enable interrupts before processing of the current interrupt is complete. If this is done a higher priority interrupt can pre-empt the processor from the current interrupt handler and 'interrupt nesting' occur.

OCEOS can be configured to use interrupt nesting.

During OCEOS initialization, each IRQ handler entry in Vector table is replaced with OCEOS interrupt handler for Multi or Single Vector Table (MVT or SVT). User must call OCEOS directives for registering and unregistering IRQ handlers. If IRQ is asserted, then OCEOS service code runs first, then user code => to handle IRQ and then finishes OCEOS handler code. This way the scheduling is possible to perform and other necessary OCEOS system calls.

SPARC Interrupts Configurations

User must not modify Interrupt Vector Table directly. User must use OCEOS directive oceos_interrupt_handle_register() and oceos_interrupt_handle_unregister() to register/unregister Interrupt handlers.

Interrupt nesting is disabled by default in BCC, meaning that an interrupt service routine can not be preempted by any other interrupt.

/*
 * Create the application configuration structure
 */
 struct application_configuration           app_config = {0};
 app_config.interrupt_nesting_enabled     = FALSE;

Disable interrupt nesting in OCEOS. PSR.PIL will be raised to 0xf (highest) when an interrupt occurs on any level.

/*
 * Create the application configuration structure
 */
 struct application_configuration           app_config = {0};
 app_config.interrupt_nesting_enabled     = TRUE;

Enable interrupt nesting in OCEOS. PSR.PIL will be raised to the current interrupt level when an interrupt occurs.

Support for single vector trapping (SVT) in OCEOS is enabled when application developer passes -qsvt switch to BCC Linker

ARM Cortex-M

ARM Cortex-M Interrupts Introduction

ARM Cortex-M uses Nested Interrupt Controller. User must modify Vector Trap table to add IRQ handlers for required IRQs.

Note

OCEOS uses some Exception handlers for own needs. User must pay attention to such handlers and not replace :

  • oceos_SysTick_Handler()
  • oceos_PendSV_Handler()

ARM Cortex-M processor has two modes:

  • Thread Mode
  • Handler Mode

OCEOS is running in Thread mode. OCEOS uses only one stack (main stack). When task is started by IRQ handler (in Handler mode) OCEOS has to switch to Thread mode in order to schedule execution of the task. For this purpose, OCEOS uses PendSV exception and implements oceos_PendSV_Handler() which must be present in Vector table (user responsibility).

Note

OCEOS initializes PendSV exception to the lowest priority (0xFF) and no other exceptions must have the same priority (user responsibility).

When task is started in IRQ handler, OCEOS asserts PendSV exception and because it is the lowest priority, it is serviced at the end when nesting level is zero.

ARM Cortex-M Interrupts Configurations

User must add described above labels to the Vector table.

	.extern oceos_SysTick_Handler
	.extern oceos_PendSV_Handler
	.section .isr_vector
	.align	2
	.globl	__isr_vector
__isr_vector:
	.long	__StackTop          /*0: Top of Stack        */
	.long Reset_Handler         /*1: Reset Handler       */
	.long NMI_Handler           /*2: NMI Handler         */
	.long HardFault_Handler     /*3: Hard Fault Handler  */
	.long MemManage_Handler     /*4: MPU Fault Handler   */
	.long BusFault_Handler      /*5: Bus Fault Handler   */
	.long UsageFault_Handler    /*6: Usage Fault Handler */
	.long 0 /* Reserved */      /*7: Reserved            */
	.long 0 /* Reserved */      /*8: Reserved            */
	.long 0 /* Reserved */      /*9: Reserved            */
	.long 0 /* Reserved */      /*10: Reserved           */
	.long SVC_Handler  	        /*11: SVCall Handler     */
	.long 0 /* Reserved */      /*12: Debug Monitor Handler */
	.long 0 /* Reserved */      /*13: Reserved           */
	.long oceos_PendSV_Handler  /*14: PendSV Handler     */
	.long oceos_SysTick_Handler /*15: SysTick Handler    */

API Functions (SPARC only)

API Functions
Directive Description main task IRQ handler
oceos_interrupt_handle_register() Register IRQ Handler * * *
oceos_interrupt_handle_unregister() Unregister IRQ Handler * * *

oceos_interrupt_handle_register()

Header File
oceos_interrupt.h

Description
OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node) in order to check if user not interfering with OCEOS internal configurations. Sets the function to be used for the given interrupt number.
This directive can be called from main() after oceos_init().

Prototype

enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(
   struct bcc_isr_node *isr_node
);

Parameters

Parameter Description
isr_node Pointer to struct bcc_isr_node

Returns
This function returns U64_t.

enum DIRECTIVE_STATUS Description
NOT_CONFIGURED Tried to call before initialization
INVALID_NODE isr_node is NULL
INVALID_NUMBER Source number is used by OCEOS internally
SUCCESSFUL All OK

Example Usage

struct bcc_isr_node node;
enum DIRECTIVE_STATUS status;
node.source = 12;
node.handler = interrupt_handler;
node.arg = NULL;
status = oceos_interrupt_handle_register(&node);
if (SUCCESSFUL != status) {
 // Handle ERROR
}

oceos_interrupt_handle_unregister()

Header File
oceos_interrupt.h

Description
OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node) in order to check if user not interfering with OCEOS internal configurations. Removes the function for the given interrupt number.
This directive can be called from main() after oceos_init().

Prototype

enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(
   const struct bcc_isr_node *isr_node
);

Parameters

Parameter Description
isr_node Pointer to struct bcc_isr_node

Returns
This function returns U64_t.

enum DIRECTIVE_STATUS Description
NOT_CONFIGURED Tried to call before initialization
INVALID_NODE isr_node is NULL
INVALID_NUMBER Source number is used by OCEOS internally
SUCCESSFUL All OK

Example Usage

struct bcc_isr_node node;
enum DIRECTIVE_STATUS status;
node.source = 12;
node.handler = interrupt_handler;
node.arg = NULL;
status = oceos_interrupt_handle_unregister(&node);
if (SUCCESSFUL != status) {
 // Handle ERROR
}