178556Sobrien% 278556Sobrien% Copyright 2014, General Dynamics C4 Systems 378556Sobrien% 4351008Sdelphij% This software may be distributed and modified according to the terms of 578556Sobrien% the GNU General Public License version 2. Note that NO WARRANTY is provided. 678556Sobrien% See "LICENSE_GPLv2.txt" for details. 778556Sobrien% 878556Sobrien% @TAG(GD_GPL) 978556Sobrien% 1078556Sobrien 1178556SobrienThis module defines the types and functions used by the kernel model to implement preemption points and non-preemptible sections in the kernel code. 1278556Sobrien 1378556Sobrien> module SEL4.Model.Preemption( 1478556Sobrien> KernelP, withoutPreemption, preemptionPoint 1578556Sobrien> ) where 1678556Sobrien 1778556Sobrien\begin{impdetails} 1878556Sobrien 1978556Sobrien> import SEL4.Machine 2078556Sobrien> import SEL4.Model.StateData 2178556Sobrien 2278556Sobrien> import Control.Monad.Except 2378556Sobrien 2478556Sobrien\end{impdetails} 2578556Sobrien 2678556Sobrien\subsection{Types} 2778556Sobrien 2878556Sobrien\subsubsection{Interrupts} 2978556Sobrien 3078556SobrienObjects of this type are thrown from an "ExceptT" monad transformer when the simulator signals a pending interrupt at a kernel preemption point. The nature of the interrupt is not relevant here, because the simulator will send it to the kernel model as an "Event" once the kernel has been preempted. 3178556Sobrien 3278556Sobrien\subsubsection{Monads} 3378556Sobrien 3478556SobrienThe "KernelP" monad is a transformation of the "Kernel" monad used for functions which may be preempted. Any function in this monad must not leave the kernel in an inconsistent state when calling other functions in the monad (though the model has no means of effectively enforcing this restriction). 3578556Sobrien 3678556Sobrien> type KernelP a = ExceptT IRQ Kernel a 3778556Sobrien 3878556Sobrien\subsection{Functions} 3978556Sobrien 4078556SobrienIf an operation must be performed during which the kernel state is temporarily inconsistent, it should be performed in the argument of a "withoutPreemption" call, to ensure that no preemption points are encountered during the operation. 4178556Sobrien 4278556Sobrien> withoutPreemption :: Kernel a -> KernelP a 4378556Sobrien> withoutPreemption = lift 4478556Sobrien 4578556SobrienIn preemptible code, the kernel may explicitly mark a preemption point with the "preemptionPoint" function. The preemption will only be taken if an interrupt has occurred and the preemption point has been called "workUnitsLimit" times. 4678556Sobrien 4778556Sobrien> workUnitsLimit = 0x64 4878556Sobrien 4978556Sobrien> preemptionPoint :: KernelP () 5078556Sobrien> preemptionPoint = do 5178556Sobrien> lift $ modifyWorkUnits ((+) 1) 5278556Sobrien> workUnits <- lift $ getWorkUnits 5378556Sobrien> when (workUnitsLimit <= workUnits) $ do 5478556Sobrien> lift $ setWorkUnits 0 5578556Sobrien> preempt <- lift $ doMachineOp (getActiveIRQ True) 5678556Sobrien> case preempt of 5778556Sobrien> Just irq -> throwError irq 5878556Sobrien> Nothing -> return () 5978556Sobrien 6078556Sobrien 6178556Sobrien