Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 48
Текст из файла (страница 48)
The TSS contains various fields related tothe IA-32 hardware task switching mechanism but the only one relevantto Symbian OS is the privilege level 0 initial stack pointer, SS0:ESP0.When an exception occurs and control is transferred to privilege level0 from a less privileged level, SS:ESP is loaded with the SS0:ESP0 valuefrom the TSS. In Symbian OS this is always set to point to the top of thecurrent thread’s supervisor stack.With this background information given, I can now describe in detailthe response of an IA-32 processor to an exception:1.The processor uses the exception vector number to index the IDTand obtain the CS:EIP of the exception handler2.If the new CS specified in the IDT necessitates a transfer to a moreprivileged level, the processor loads SS and ESP from the currentlyactive TSS and then pushes the original SS and ESP onto the newstack. All subsequent stack operations use the new stack3.The processor pushes the EFLAGS register and then the current CSand EIP values4.If the IDT entry contains an interrupt gate, the processor clears theIF flag so that maskable interrupts are disabled.
A trap gate does notaffect the IF flagINTERRUPTS2195. Depending on the type of exception, the processor may push an errorcode6. The processor transfers control to the handler indicated by the CSand EIP values read from the IDT.Like the ARM, the IA-32 architecture supports only two physical interruptinputs to the processor. However, these inputs behave very differently tothose on the ARM.The NMI line always causes a vector 2 interrupt and may not bemasked by software. It is of limited use in most IA-32 systems. Mosthardware interrupts are directed to the INTR line. Interrupts signaled onthis line are maskable by clearing the IF flags in the EFLAGS register.IA-32 processors are used with external interrupt controller hardware,typically located in the motherboard chipset.
The interrupt controller,which accepts inputs from a number of interrupt sources, allows the interrupt sources to be individually masked and prioritized. It also associatesa vector number with each interrupt source.When an enabled interrupt source becomes active, the interrupt controller signals an interrupt to the processor and passes the associatedvector number.
If interrupts are enabled (IF = 1) the processor calls theappropriate vector handler, as listed in the IDT. While the interrupt is inservice the interrupt controller prevents lower priority interrupt sourcesfrom being signaled to the processor.At the end of the software handler, the processor signals EOI (end ofinterrupt) to the interrupt controller. At this point lower priority interruptscan once more be signaled to the processor.6.3 InterruptsIn this section, I will return to EKA2, and describe how it handlesinterrupts.6.3.1 EKA2 interrupt handlingThere are four phases in the handling of any interrupt.
Figure 6.3 illustratesthese four phases, and shows where in the kernel the code for each phaseis located.Interrupts occur very frequently during normal system operation – thesystem tick interrupts every millisecond and during some I/O operations,such as bulk data transfer over USB, an interrupt may occur every 50 µs.Because of this, the interrupt handling code is optimized for speed.The fewest possible registers are saved at each stage and the entireinterrupt code path within the kernel and the dispatcher is written inhand-optimized assembler.220ApplicationINTERRUPTS AND EXCEPTIONSNanokernelASSPDevice DriverPreambleHardwareInterruptDispatcherISRReturn fromInterruptPostambleFigure 6.3Code flow during interrupt6.3.1.1 PreambleThe first code to execute following the processor response to an interruptis the preamble, which is part of the nanokernel.On ARM processors the preamble is entered directly from both theIRQ and the FIQ vectors.On IA-32 processors, each IDT entry points to a preamble entry stubthat saves the vector number, and then jumps to a common interruptpreamble.
The preamble’s job is to establish the correct processor state,by taking care of any nonautomatic stack switching and register savingbefore the dispatcher and interrupt service routine run. Because interruptsare asynchronous to program execution, the preamble can make noassumptions about the processor state on entry.EKA2 uses a separate stack for interrupts. This means that we don’tneed to reserve stack space for interrupts on each thread’s supervisorstack, which reduces RAM usage.
Depending on processor architecture, the switching of stacks may be performed automatically or by thesoftware preamble:• On ARM-based hardware, the stack is switched automatically, sincean interrupt causes the processor to switch to mode irq or mode fiqand thus R13 irq or R13 fiq becomes the active stack pointer• On IA-32 hardware, the processor interrupt response includes a switchto the current thread’s supervisor stack if the interrupt occurs in usermode (CPL = 3).
If the interrupt occurs in supervisor mode (CPL = 0),no stack switch occurs and so the active stack may be a threadsupervisor stack or the interrupt stack, if another ISR was interrupted.INTERRUPTS221On the first of a nest of interrupts, the preamble switches to a separate interrupt stack and saves the original stack pointer on the newstack. This can be seen in lines 10–15 of the IA-32 preamble. TheIrqNestCount variable is initialized to −1, so if incrementing itgives zero, this is the first of a nest of interrupts.Symbian OS interrupt service routines are generally written in C++.Each processor has a calling convention that specifies which registersare preserved across function calls and which are not.
On ARM, R0–R3,R12 and CPSR are destroyed by function calls; on IA-32, EAX, ECX, EDXand EFLAGS are destroyed by function calls. Lines 1 and 2 of the ARMinterrupt preamble, and lines 1, 2, 3, 6 and 7 of the IA-32 interruptpreamble, save these registers.ARM interrupt preamble12345SUBSTMFDLDRLDRLDRLR, LR, #4SP!, {R0-R3, R12, LR}R12, IrqHandlerLR, ArmVectorIrqPC, [R12]IA-32 interrupt preamble1PUSH2PUSH3PUSH4MOV5CLD6PUSH7PUSH8MOV9MOV10MOV11INC12JNZ13LEA14PUSH15 Nested:16CALLDSESEAXAX, SSECXEDXDS, AXES, AXEAX, ESPDWORD PTR IrqNestCountNestedESP, IrqStackTopEAX[IrqHandler]The preamble may need to set up more state, depending on theprocessor architecture. On IA-32, the hardware interrupt response sets upthe SS and CS segment selectors, but not DS and ES.
The preamble savesthese selectors, then sets them both equal to SS, which is the privilegelevel 0 data segment covering the entire 4 GB linear address range. Inaddition, it clears the D flag, so that the IA-32 repeated string operationswork in the forward direction, from low to high addresses.On ARM, no further state setup is needed unless we want to supportnested interrupts. In this case, ISRs cannot execute in mode irq.
This222INTERRUPTS AND EXCEPTIONSis because a nested interrupt would corrupt R14 irq, which may holdthe return address from a subroutine called during execution of the firstISR. So, if support for nested interrupts is required, a switch to mode syswill occur during the preamble. If the interrupt occurred in mode sys (asindicated by SPSR irq), it must be a nested interrupt, so R13 usr pointsto the interrupt stack. If the interrupt occurred in any other mode, thepreamble saves R13 usr, then sets R13 usr to point to the top of theinterrupt stack.
It must also save R14 usr, since it will be corrupted byany subroutine calls made by the ISR.6.3.1.2 Interrupt dispatcherThe role of the dispatcher is to determine the source of the interrupt andto call the registered service routine for that source. It is written as part ofthe base port for a given hardware platform. On platforms with an ASSP,the dispatcher is usually part of the ASSP extension; otherwise it is part ofthe variant.On hardware without vectored interrupt support – which includes mostcurrent ARM-based hardware – the dispatcher interrogates the interruptcontroller to establish which interrupts are both pending and enabled.
Itthen selects one of these according to a fixed priority scheme, and invokesthe corresponding service routine. Once the service routine is completed,the dispatcher will loop and interrogate the interrupt controller again; thiscontinues until there are no more pending interrupts. In the code sampleExample ARM IRQ dispatcher, lines 5–8 discover which interrupts arepending and select the one corresponding to the highest numbered bit inthe hardware IRQ pending register. If no interrupts are pending, line 7returns from the dispatcher.Example ARM IRQ dispatcher1STMFD2LDR3LDR4 dispatch:5LDR6CMP7LDMEQFD8CLZ9ADD10ADR11LDMIASP!, {R4-R6, LR}R4, InterruptControllerBaseR5, HandlersR12, [R4, #IRQPendingRegOffset]R12, #0SP!, {R4-R6, PC}R3, R12R0, R5, R3, LSL #3LR, dispatchR0, {R0, PC}On hardware with vectored interrupt support, which includes IA-32architectures, the dispatcher knows immediately from the vector numberwhich interrupt source is involved.
It immediately invokes the serviceroutine and then returns.EKA2 typically allows only one service routine for eachinterrupt – although since the dispatcher is outside the Symbian-suppliedINTERRUPTS223kernel, this decision is actually up to the base porter, who could easilychange this code to allow several service routines to be associated witha single interrupt. It is fairly common among hardware designs to findseveral interrupts attached to the same line on the interrupt controller.This situation is normally handled by using a sub-dispatcher rather thanby registering several handlers with the main dispatcher. A sub-dispatcheris a routine that is bound to a given interrupt source at system boot time,and which performs a similar function to the main dispatcher, but onlyfor interrupts that are routed to a particular line.
A common pattern isthat the main interrupt dispatcher is in the ASSP and this deals with thedifferent interrupt sources recognized by the on-chip interrupt controller.Sub-dispatchers are in the variant, and these deal with interrupts from‘‘companion’’ chips – peripheral devices external to the ASSP. Thesechips generally produce a single combined interrupt output, which isrecognized as a single source by the main interrupt controller.6.3.1.3 Interrupt service routinesThe role of the interrupt service routine (ISR) is to perform whatever actionis necessary to service the peripheral that generated the interrupt and toremove the condition that caused it to interrupt. This usually involvestransferring data to or from the peripheral.ISRs may be located in the ASSP, variant, an extension or a devicedriver.
ISRs are typically written in C++, although some frequently usedones such as the system tick ISR are written in assembler.In Chapter 12, Drivers and Extensions, I will discuss ISRs in more detail,but this is for the most part irrelevant in understanding how Symbian OShandles interrupts. All we need to know now is that the ISR runs, and thatit may make use of a small number of OS services, as follows:• It may queue an IDFC or DFC (which I will describe in Sections 6.3.2.2and 6.3.2.3) or, in the case of the millisecond tick ISR, trigger areschedule directly if the current thread’s timeslice has expired• It may queue or cancel a nanokernel timer• It may disable or enable interrupts using APIs provided by the ASSPor variant.