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