Wednesday, September 06, 2006

Installable ISR

Origin of writing this article is that when I am working to support the Microsoft Windows Automotive for ARM platform project, there is a requirement to support the installable isr for LCD interrupt. After I finished it, I summarize the process and write this article.

Introduction

An installable interrupt service routine (ISR) is one that can be installed and allowed to hook an interrupt after the kernel is built. Usually, if an interrupt had to be hooked to service some event, the code had to be built into the kernel when it was originally built. If a new device was inserted into the board, the code to handle the IRQ would need to already be in the kernel; otherwise, the IRQ could not be hooked.

Interrupt Handling
The main technique for handling an interrupt is to associate an event to a specified ISR. Windows CE schedules your IST when the event is triggered.

1) Typical normal interrupt handling sequence:
a) Hardware raises an interrupt.
b) Kernel looks up IRQ of the interrupt, calls the registered ISR, and disables all lower-priority interrupts.
c) ISR performs necessary handling, and then returns an interrupt identifier (SYSINTR_xxx).
d) If the interrupt identifier value returned by the ISR is SYSINTR_NOP, kernel completes processing without setting an event. all interrupts enabled. Otherwise, kernel sets the event. When the ISR returns, the kernel enables all other interrupts except the one that is being processed.
e) The kernel schedules the IST indicated by the SYSINTR to run.
f) IST call InterruptDone, InterruptDone calls OEMInterruptDone to perform any hardware actions necessary to enable the next interrupt of the target device.

2) Function call sequence in the interrupt handling
InterruptInitialize --> OEMInterruptEnable --> OALIntrEnableIrqs
InterruptDisable --> OEMInterruptDisable --> OALIntrDisableIrqs
InterruptDone --> OEMInterruptDone --> OALIntrDoneIrqs
Hardware IRQ --> OEMInterruptHandler --> static ISRs or installable ISRs --> IST

For an installable ISR, driver's IST is the same with the normal ISR, both of them will call InterruptInitialize, WaitForSingleObject, InterruptDone, InterruptDisable functions. Installable ISR will be called by the OEMInterruptHandler, If OEMInterruptHandler doesn't NKCallIntChain, the installable ISR will not be called. Installable ISR does things just like the static ISR does in the OEMInterruptHandler called functions, so the enable/disable interrupt still need be implemented in the OAL. We can only use the installable ISR for those IRQs that had been handled in the OALIntrEnableIrqs, OALIntrDisableIrqs & OALIntrDoneIrqs function.

Related Functions in Driver

1) LoadIntChainHandler
> This function is called by a driver to install an ISR to handle a particular interrupt.
> Parameters: DLL name, ISR function name, IRQ value.
> Return value: the handle to the installed handler, NULL if failed.
> Default ISR for all interrupt is the OEMInterruptHandler
> Sample code:
HANDLE hIISR = LoadIntChainHandler(_T("lcd_isr.dll"), _T("LcdISR"), IRQ_LCD);

2) FreeIntChainHandler
> This function unloads an existing interrupt handler.
> Parameters: handle of the installed ISR.
> Return value: TRUE/FALSE.
> Code of the ISR will not be freed from memory until reset.
> Sample code: FreeIntChainHandler(hIISR);

3) KernelIoControl
> This function provides the kernel with a generic I/O control for carrying out I/O operations.
> Will use this function to call IOCTL_HAL_REQUEST_SYSINTR to map IRQ-to-SYSINTR.
> Will call IOCTL_HAL_RELEASE_SYSINTR also.
> Parameters: IOCTL code, Out & In buffer.
> Return value: TRUE/FALSE.
> Sample code:
DWORD dwSYSINTR, dwIRQ = IRQ_LCD;
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIRQ, sizeof(dwIRQ), &dwSYSINTR, sizeof(dwSYSINTR), NULL);

4) KernelLibIoControl
> This function is called by a driver to communicate with an interrupt handler.
> Parameters: ISR handle, OEM or ISV specified IOCTL, ...
> Return value: TRUE/FALSE (ERROR: Use GetLastError() to retrieve)
> This function will call IOControl function implemented in the interrupt handler.
> Sample code:
GIISR_INFO iisr_info;
memset(&iisr_info, 0, sizeof(GIISR_INFO));
iisr_info.SysIntr = dwSYSINTR;
if (!KernelLibIoControl(hIISR, IOCTL_GIISR_INFO, &iisr_info, sizeof(iisr_info), NULL, 0, NULL))
{
RETAILMSG(1, (TEXT("KernelLibIoControl failed!\r\n")));
//...
}

5) BusTransBusAddrToStatic
> This function translate a bus address to a system address. Then, it creates a static, process independent, virtual address mapping for that address.
> Parameters:
- hBusAccess: handle obtained from CreateBusAccessHandle
- InterfaceType: Bus type
- BusNumber: bus number where the device resides.
- BusAddress: bus-relative address of registers and ports on the device.
- Length: number of bytes to map on the device.
- AddressSpace: flag
- MappedAddress: virtual address mapped.
> Return value: TRUE/FALSE

Related Functions in OAL
1) NKCallIntChain
> This function is called by OEM from the OAL ISR routine (such as OEMInterruptHandler).
> This function determines which chained or shared interrupt device triggered an IRQ event.
> Parameter: IRQ value.
> Return value: return SYSINTR_CHAIN if no ISR has handled the IRQ event, otherwise return valid SYSINTR value to the OEM, and OEM passes back this value to kernel to trigger IST.
> Sample code: DWORD dwSysIntr = NKCallIntChain(nIrq);

2) OALIntrTranslateSysIntr
> This function returns the list of IRQs for a specified SYSINTR. It will be called by OEMInterruptEnable, OEMInterruptDisable & OEMInterruptDone function.
> Parameters: SYSINTR value, buffer for the IRQs list
> Return value: TRUE/FALSE

3) OALIntrEnableIrqs
> This function enables the list of interrupts identified by an IRQ.
> Parameters: number of IRQs in the list, Pointer to the list of IRQs.
> Return value: TRUE/FALSE

4) OALIntrDisableIrqs
> This function disables the list of interrupts identified by an IRQ.

5) OALIntrDoneIrqs
> This function scans the list of identified by an IRQ, signaling the end of interrupt processing.

6) OEMInterruptHandler
> This function is called by the kernel when an interrupt occurs. This function is only used by the ARM kernel, and provides all ISR functionality for ARM-based platforms. You do not need to call HookInterrupt in OEMInit for ARM-based platforms.
> Parameters: instruction counter when the interrupt occurred.
> Return value: a SYSINTR_* value.

Related Functions in an Installable ISR DLL
Installable ISR DLL must implement the following functions:
1) DllEntry
> DllEntry is a placeholder for the library-defined function name. You must specify the name you use when you build your DLL.

2) CreateInstance
> This function is implemented by an ISR to return a value that references an instance of the ISR. It's the DLL's first function called when the LoadIntChainHandler function is called to install the ISR handler, after the handler is loaded.
> Parameters: none

> Return value: a reference value that identifies an instance of the ISR handler, -1 identifies an error in the ISR.

3) DestroyInstance
> This function is called when an installable ISR is unloaded using the FreeIntChainHandler function.
> Parameters: instance of the ISR being unloaded.
> Return value: TRUE/FALSE.

4) ISRHandler
> This function prototype is used by an OEM/IHV to create and export an installable interrupt handler.
> Parameters: Instance of the ISR being registered.
> Return value: the SYSINTR value that corresponds to the IST that should be schedule to run. This can also include returning SYSINTR_CHAIN if the IRQ is not handled by your handler.

4) IOControl
> This function, exported by the installable ISR DLL, enables a communication path from the interrupt service thread (IST) to the ISR.

Notes about the Installable ISR DLL
1) The DLL is loaded into the kernel process space.
2) The DLL must be in the FILES section with no fixup variable or in the MODULES section with the kernel flag, K, set for a kernel-style fixup variable. A fixup variable is functionality of ROMIMAGE that allows you to initialize a global variable in the NK.exe at MAKEIMG time.
3) The DLL can contain more than one ISR handler and can be used in several call to LoadIntChainHandler. All ISR handlers have a full stack, based on the CPU.
4) The DLL cannot have dependent DLLs.
5) The DLL cannot implicitly to any other DLL, and all code must be contained in the DLL. You can set NOMIPS16CODE=1 in the sources file to prevent importing external functions.
6) Must be compiled to eliminate the C Run-Time Library from being included by default.

Samples of the Installable ISR
There is a sample of the installable ISR -GIISR in Windows CE under the public\common\oak\drivers\giisr\ folder.

3 Comments:

At 9/16/2008 3:44 AM , Blogger Unknown said...

A very informative and easy to read post about IISR.
Keep up the good work

 
At 12/04/2008 9:47 PM , Anonymous Anonymous said...

In one line.. 10/10.. :-)

 
At 5/16/2013 6:56 PM , Blogger Unknown said...

Very Good Article

 

Post a Comment

Subscribe to Post Comments [Atom]

<< Home