Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 54
Текст из файла (страница 54)
First instantiate theDKernelEventHandler class on the kernel heap. This requires twoparameters – aCb is a pointer to a function to be called back when anynotifiable event occurs, and aP is an arbitrary cookie which is suppliedas an argument to aCb when notifying an event.After instantiating the class, call Add() on it to start receiving eventcallbacks. From this point on, whenever a notifiable event occurs, thekernel will call the specified function, aCb. It calls the function in thecontext of the thread that caused the event, with the thread itself in acritical section. The aEvent parameter to the callback indicates the eventthe callback relates to; the value EEventHwExc indicates a processorexception. For processor exception callbacks, parameter a1 points to thesaved processor state (for example, TArmExcInfo which I mentionedpreviously) and parameter a2 is not used.
The return value from thehandler function will take one of the following values:• DKernelEventHandler::EExcHandled if the exception has beenhandled and normal program execution should be resumed• DKernelEventHandler::ERunNext if the exception has not beenhandled and the next kernel event handler (if any) should be run.6.4.3.3 ARM coprocessor handlersOn ARM-based hardware, Symbian OS provides additional APIs to support lazy context switching and software support for coprocessors.
ARMsystems may have several coprocessors; examples of these are the VectorFloating Point (VFP), DSP and motion estimation units.Here is the coprocessor API:const TInt KMaxCoprocessors=16;enum TCpOperation{EArmCp_Exc, /* UNDEF exc executing a coproc instr */EArmCp_ThreadExit, /* Coproc current owning thread exited */ABORTS, TRAPS AND FAULTS247EArmCp_ContextInit /* Initialise coprocessor */};struct SCpInfo;typedef TInt (*TCpHandler)(SCpInfo*, TInt, TAny*);struct SCpInfo{TCpHandler iHandler; /*Hdler:contextswitch,init&threadexit*/NThread* iThread; /*Current owning thread, NULL if none */TUint16 iContextSize; /* context size for this coprocr */TInt8 iCpRemap; /* Coproc no to remap this one to if >=0 */TUint8 iSpare;TInt iContextOffset; /* Offset in thread extra context */};class Arm{...public:static void SetCpInfo(TInt aCpNum, const SCpInfo* aInfo);static void SetStaticCpContextSize(TInt aSize);static void AllocExtraContext(TInt aRequiredSize);static TUint32 Car();static TUint32 ModifyCar(TUint32 aClearMask, TUint32 aSetMask);static TUint32 FpExc();static TUint32 ModifyFpExc(TUint32 aClearMask, TUint32 aSetMask);...};The code responsible for handling the coprocessor (which may be in thekernel or in the ASSP, the variant or an extension) should call the following function during the Init1 initialization phase (see Chapter 16, BootProcesses, for a detailed description of the system initialization phases):Arm::SetCpInfo(TInt aCpNum, const SCpInfo* aInfo);Parameter aCpNum specifies the number of the coprocessor whose handler is being defined.
Parameter aInfo specifies information about thecoprocessor, as follows:• SCpInfo::iHandler specifies the function that should be called atsystem boot if a thread exits or if an undefined instruction exceptionoccurs trying to access the coprocessor. The second parameter passedto the function specifies which of these events has occurred, specifiedby the TCpOperation enumeration• SCpInfo::iThread specifies which thread owns the coprocessor.On initialization this should be NULL• SCpInfo::iContextSize specifies the size in bytes of the perthread context for this coprocessor248INTERRUPTS AND EXCEPTIONS• SCpInfo::iCpRemap specifies whether this coprocessor is reallypart of another coprocessor.
If set to zero or a positive value, thisspecifies the number of the primary coprocessor. All events for thiscoprocessor will be redirected to the primary coprocessor. A value of−1 indicates that no redirection is required• SCpInfo::iContextOffset is calculated by the kernel and neednot be set. When the kernel calls back the handler function specifiedin SCpInfo::iHandler it passes the following parameters:TInt h(SCpInfo* aInfo, TInt aOp, TAny* aContext);If aOp == EArmCp_ContextInit, the system is in the Init2 phaseof boot. The handler should initialize the coprocessor and then save itsstate to the memory area pointed to by aContext.
It should then disableaccess to the coprocessor.If aOp == EArmCp_ThreadExit, a thread is exiting. The handler iscalled in the context of the exiting thread. If the exiting thread currentlyowns the coprocessor, the handler should mark the coprocessor asunowned, so that subsequent accesses do not try to save the state to athread control block that no longer exists.If aOp == EArmCp_Exc, an undefined instruction exception hasoccurred on an instruction targeted at this coprocessor.
aContext pointsto the register state saved by the nanokernel exception preamble. Thekernel calls the handler in the context of the thread attempting the instruction. If this is not the coprocessor’s current owning thread, the handlershould save the coprocessor state for the current owning thread and thendisable the coprocessor for that thread. It should then enable the coprocessor for the current thread and restore the current thread’s coprocessorstate.
If the exception is successfully handled the handler should returnKErrNone, otherwise KErrGeneral.The following functions are used to modify the access permissions fora coprocessor:Arm::ModifyCar(TUint32 aClear, TUint32 aSet);Arm::ModifyFpExc(TUint32 aClear, TUint32 aSet);The functions return the original value of the register that they modify.Access to the VFP is controlled by the FPEXC register; access to othercoprocessors is controlled by the CAR. Since these functions modify thehardware registers directly, they affect the current thread. To modify coprocessor access for another thread, the corresponding functions are used:NThread::ModifyCar(TUint32 aClear, TUint32 aSet);NThread::ModifyFpExc(TUint32 aClear, TUint32 aSet);SUMMARY249These do not modify the hardware registers – instead they modify thecopy of those registers saved in the thread’s control block.6.4.4Exceptions in the emulatorThe emulator installs an exception handler on its Windows threads sothat it can detect and handle exceptions occurring in Windows on thatthread.
This is similar to the data abort exception vector in the ARM codeon a phone.If the kernel is locked when an exception occurs the system halts, asthis is a fatal error.If the kernel is unlocked, the first action on taking an exception is tolock it. Next, we have to deal with the effect of a race condition betweenexception handling and forced exit – otherwise it is possible that a threadthat has been killed will not actually die!The exception handler then records the exception information andcauses the thread to ‘‘return’’ to a second exception handler once theWindows exception mechanism has unwound.
Running the second stageoutside of the Windows exception handler allows the nanokernel to be inbetter control of the thread context; in particular it allows for the thread tobe panicked and so on. The kernel remains locked through this process,so the saved exception data cannot be overwritten.The second stage saves the full thread context including the originalinstruction pointer (this allows debuggers to display a complete callstack), then unlocks the kernel and invokes the nanokernel thread’sexception handler.
This handler can supply a final ‘‘user-mode’’ exceptionhandler and parameters which is invoked before returning to the originalexception location.6.5 SummaryIn this chapter, I’ve described interrupts and exceptions, and lookedat their causes and the way in which processors react to them. I’veshown how an operating system, in particular Symbian OS, makes useof exceptions, and I’ve gone on to examine how EKA2 handles them indetail. Finally, I have discussed the APIs that are available to allow youto make use of exceptions in base ports and device drivers.The management of CPU resources is one of the key tasks of anoperating system.
The other is the management of memory, and it is thisthat I shall discuss in the next chapter, Memory Models.7Memory Modelsby Andrew ThoelkeA memory is what is left when something happens and does notcompletely unhappen.Edward de BonoThe kernel is responsible for two key resources on a device: the CPU andthe memory.
In Chapter 6, Interrupts and Exceptions, I described how thekernel shares the CPU between execution threads and interrupts.In this chapter I will examine the high-level memory services providedby EKA2, and the way that the kernel interacts with the physical memoryin the device to provide them.