Asynchronous Hardware Interrupt Delivery

In OKL4 2.1, interrupts are delivered using the asynchronous notification (async notify) mechanism. Async notify allows the sender thread to deliver a set of bits in the receiver thread's memory, in a reserved location known as notify bits.

Summary

Hardware interrupts are now delivered to threads using asynchronous notifications, completely replacing the previous synchronous IPC delivery of hardware interrupts.

Motivation

The use of asynchronous notification to deliver interrupts, allows for the removal of TCBs used to represent hardware interrupt threads, resulting in a reduction of the memory footprint.

Also as asynchronous notification is a simpler form of communication, there are potential benefits from a shorter and simpler code path in comparison to equivalent synchronous IPC code paths. This is expected to reduce interrupt latency and further reduce kernel footprint.

Asynchronous Interrupt Delivery Usage

Interrupt Registration

Interrupt registration may still be performed by the OKL4 root server function, hardware_register_interrupt().

Alternatively, the following two-step process may be followed:

  1. A privileged thread, such as the root server, calls L4_AllowInterruptControl(space) on the L4 space that the handler thread belongs to. Prior to the call, the privileged thread must load the interrupt number to be granted to MR[0].

  2. A non-privileged thread calls L4_RegisterInterrupt() with the handler thread as the target argument. The non-privileged thread must reside in the same L4 space as the handler thread. Prior to the call, the non-privileged thread must load the interrupt number to be granted to MR[0].

   1 /*
   2  * The following variables must be set up before threads begin execution
   3  */
   4 static L4_SpaceId_t space;
   5 static L4_ThreadId_t handler_tid;
   6 
   7 /*
   8  * This function is run by the root server
   9  */
  10 void
  11 priv_thread(void)
  12 {
  13     /* Suppose we want to grant interrupt 16 to space */
  14     int irq = 16;
  15 
  16     /* Grant the interrupt */
  17     L4_LoadMR(0, irq);
  18     L4_AllowInterruptControl(space);
  19     
  20     /* Continue execution... */
  21 }
  22 
  23 /*
  24  * This function is run by the handler thread
  25  */
  26 void
  27 handler_thread(void)
  28 {
  29     /* Suppose we want notify bit 31 to be set on hardware interrupt */
  30     int irq_bit = 31;
  31     int irq = 16;
  32 
  33     /* Register the interrupt */
  34     L4_LoadMR(0, irq);
  35     L4_RegisterInterrupt(handler_tid, irq_bit, 0, 0);
  36     
  37     /* Continue execution... */
  38 }

Interrupt Delivery and Acknowledgement

Interrupt handling threads should no longer inspect the from field of incoming IPCs in order to determine whether the IPC represents a hardware interrupt. from will be set to L4_nilthread when an asynchronous notification is received.

Interrupt handling threads should progressively handle each bit that is set in the async notify bitfield. If the bit that represents hardware interrupts is set, that is a signal to the thread that an interrupt has arrived. By default, this will be bit 31 (the most significant bit).

To determine the hardware interrupt number that has arrived, the thread should read the first word in the platform reserved region of the UTCB. The word contains the hardware interrupt number.

Finally, the thread should acknowledge to the kernel that the interrupt has been received, and requests the kernel to perform the hardware acknowledgement on its behalf.

   1 /*
   2  * This function is run by the handler thread
   3  */
   4 void
   5 handler_thread(void)
   6 {
   7     /* Continued execution from previous example... */
   8 
   9     int irq;
  10     int irq_bit = 31;
  11     L4_Word_t irq_mask = 1 << irq_bit;
  12     
  13     L4_ThreadId_t from;
  14     L4_Msg_t msg;
  15     L4_MsgTag_t tag;
  16     L4_Word_t notify_bits;
  17 
  18     /* This is the server loop */
  19     while(1)
  20     {
  21         L4_Set_NotifyMask(irq_mask);
  22         L4_Accept(L4_NotifyMsgAcceptor);
  23 
  24         tag = L4_Wait(&from);
  25         L4_MsgStore(tag, &msg);
  26         notify_bits = L4_MsgWord(&msg, 0);
  27         
  28         if (L4_IsNilThread(from))   /* Async IPC received */
  29         {
  30             if (notify_bits & irq_mask != 0)    /* Notify bit 31 is set */
  31             {
  32                 /* Obtain the interrupt number */
  33                 irq = __L4_TCR_PlatformReserved(0);
  34                 
  35                 /* Call the interrupt handler for irq... */
  36                 
  37                 /* Acknowledge the interrupt */
  38                 L4_LoadMR(0, irq);
  39                 L4_AcknowledgeInterrupt(0, 0);
  40             }
  41         }
  42     }
  43 }

Further Reading

Interrupts are further described in Section A-7 Interrupts of the OKL4 Microkernel Programming Manual.

AsyncIrq (last edited 2008-08-11 02:34:28 by localhost)