diff --git a/Makefile b/Makefile
index c30a93231..ea0cac5ca 100644
--- a/Makefile
+++ b/Makefile
@@ -208,10 +208,6 @@ STATICHEADERS := $(shell find ${SOURCE_ROOT}/include/ -name "*.h" \
$(shell find ${SOURCE_ROOT}/include/arch/${ARCH} -name "*.h") \
$(shell find ${SOURCE_ROOT}/include/plat/${PLAT} -name "*.h")
-ifeq (${HAVE_AUTOCONF}, 1)
- STATICHEADERS += $(srctree)/include/generated/autoconf.h
-endif
-
STATICSOURCES = $(foreach file,${C_SOURCES_WITH_PARSE} ${ASM_SOURCES}, \
${SOURCE_ROOT}/${file})
@@ -352,6 +348,8 @@ endif
# Only set CFLAGS if we're building standalone.
# common/Makefile.Flags sets NK_CFLAGS in Kbuild environments.
ifndef NK_CFLAGS
+STATICHEADERS += autoconf.h
+DEFINES += -DHAVE_AUTOCONF
ifeq (${ARCH}, arm)
CFLAGS += -mtune=${CPU} -marm -march=${ARMV}
ASFLAGS += -Wa,-mcpu=${CPU} -Wa,-march=${ARMV}
@@ -399,15 +397,18 @@ endif
ifeq ($(PLAT),allwinnerA20)
DEFINES += -DALLWINNERA20
endif
-endif # NK_CFLAGS
-
+endif # ARCH=arm
ifeq (${ARCH}, x86)
CFLAGS += -m32 -mno-mmx -mno-sse
ASFLAGS += -Wa,--32
DEFINES += -DARCH_IA32
LDFLAGS += -Wl,-m,elf_i386
-endif
-endif
+endif # ARCH=x86
+else # NK_CFLAGS
+# Require autoconf to be provided if larger build
+$(if ${HAVE_AUTOCONF},,$(error autoconf.h not provided))
+STATICHEADERS += $(srctree)/include/generated/autoconf.h
+endif # NK_CFLAGS
ifeq (${CPU}, arm1136jf-s)
DEFINES += -DARM1136_WORKAROUND
@@ -537,6 +538,9 @@ kernel.elf: ${OBJECTS} linker.lds_pp
$(Q)${CHANGED} $@ ${CC} ${LDFLAGS} -Wl,-T -Wl,linker.lds_pp \
-o $@ ${OBJECTS}
+autoconf.h: include/plat/${PLAT}/autoconf.h
+ ${Q}cp $< $@
+
############################################################
### Pattern rules
############################################################
@@ -571,7 +575,6 @@ arch/api/syscall.h: ${SOURCE_ROOT}/include/api/syscall.xsd ${SOURCE_ROOT}/includ
$(Q)${SYSCALL_ID_GEN_PATH} --xml $(word 2, $^) \
--kernel_header $@
-
####################
# Bitfield generation
####################
@@ -638,7 +641,7 @@ endif
### Utility targets
############################################################
-CLEANTARGETS = kernel.elf kernel.elf.strip ${GENHEADERS} ${OBJECTS} \
+CLEANTARGETS = kernel.elf kernel.elf.strip ${GENHEADERS} ${OBJECTS} autoconf.h \
parser.out parsetab.py \
kernel_final.s kernel_final.c kernel_all.c kernel_all.c_pp \
${PPFILES} ${THEORIES} c-parser.log c-parser-all.log \
diff --git a/haskell/src/SEL4/API/Syscall.lhs b/haskell/src/SEL4/API/Syscall.lhs
index fab6f0548..66a0f08ea 100644
--- a/haskell/src/SEL4/API/Syscall.lhs
+++ b/haskell/src/SEL4/API/Syscall.lhs
@@ -64,6 +64,7 @@ the enumerated type "Syscall":
> | SysReply
> | SysReplyWait
> | SysYield
+> | SysNBWait
> deriving (Show, Enum, Bounded, Eq)
\subsection{Handling Events}
@@ -82,12 +83,13 @@ System call events are dispatched here to the appropriate system call handlers,
> SysSend -> handleSend True
> SysNBSend -> handleSend False
> SysCall -> handleCall
-> SysWait -> withoutPreemption handleWait
+> SysWait -> withoutPreemption $ handleWait True
> SysReply -> withoutPreemption handleReply
> SysReplyWait -> withoutPreemption $ do
> handleReply
-> handleWait
+> handleWait True
> SysYield -> withoutPreemption handleYield
+> SysNBWait -> withoutPreemption $ handleWait False
\subsubsection{Interrupts}
@@ -176,22 +178,22 @@ The "Reply" system call attempts to perform an immediate IPC transfer to the thr
The "Wait" system call blocks waiting to receive a message through a specified endpoint. It will fail if the specified capability does not refer to an endpoint object.
-> handleWait :: Kernel ()
-> handleWait = do
+> handleWait :: Bool -> Kernel ()
+> handleWait isBlocking = do
> thread <- getCurThread
> epCPtr <- asUser thread $ liftM CPtr $ getRegister capRegister
> (capFaultOnFailure epCPtr True $ do
> epCap <- lookupCap thread epCPtr
> case epCap of
-> EndpointCap { capEPCanReceive = True } ->
+> EndpointCap { capEPCanReceive = True } -> do
> withoutFailure $ do
> deleteCallerCap thread
-> receiveIPC thread epCap
+> receiveIPC thread epCap isBlocking
> AsyncEndpointCap { capAEPCanReceive = True, capAEPPtr = ptr } -> do
> aep <- withoutFailure $ getAsyncEP ptr
> boundTCB <- return $ aepBoundTCB aep
> if boundTCB == Just thread || boundTCB == Nothing
-> then withoutFailure $ receiveAsyncIPC thread epCap
+> then withoutFailure $ receiveAsyncIPC thread epCap isBlocking
> else throw $ MissingCapability { missingCapBitsLeft = 0 }
> _ -> throw $ MissingCapability { missingCapBitsLeft = 0 })
> `catchFailure` handleFault thread
diff --git a/haskell/src/SEL4/Kernel/Init.lhs b/haskell/src/SEL4/Kernel/Init.lhs
index 4836a205a..2c7be457e 100644
--- a/haskell/src/SEL4/Kernel/Init.lhs
+++ b/haskell/src/SEL4/Kernel/Init.lhs
@@ -25,6 +25,7 @@ This module contains functions that create a new kernel state and set up the add
> import SEL4.API.Failures
> import SEL4.Model
> import SEL4.Object
+> import SEL4.Object.Structures
> import SEL4.Machine
> import SEL4.Kernel.Thread
> import SEL4.Kernel.VSpace
@@ -133,7 +134,6 @@ The kernel is bootstrapped by calling "initKernel". The arguments are the addres
Define some useful constants.
-> let wordSize = finiteBitSize entry
> let uiRegion = coverOf $ map (\x -> Region (ptrFromPAddr x, (ptrFromPAddr x) + bit (pageBits))) initFrames
> let kernelRegion = coverOf $ map (\x -> Region (ptrFromPAddr x, (ptrFromPAddr x) + bit (pageBits))) kernelFrames
> let kePPtr = fst $ fromRegion $ uiRegion
@@ -297,7 +297,7 @@ FIXME: Seems we need to setCurThread and setSchedulerAction here, otherwise erro
> freemem <- noInitFailure $ gets initFreeMemory
> (flip mapM) (take maxNumFreememRegions freemem)
> (\reg -> do
-> (\f -> mapM (f reg) [4 .. (finiteBitSize (undefined::Word)) - 2])
+> (\f -> mapM (f reg) [4 .. wordBits - 2])
> (\reg bits -> do
> reg' <- (if not (isAligned (regStartPAddr reg) (bits + 1))
> && (regEndPAddr reg) - (regStartPAddr reg) >= bit bits
diff --git a/haskell/src/SEL4/Kernel/Thread.lhs b/haskell/src/SEL4/Kernel/Thread.lhs
index bd98de820..573902725 100644
--- a/haskell/src/SEL4/Kernel/Thread.lhs
+++ b/haskell/src/SEL4/Kernel/Thread.lhs
@@ -36,6 +36,7 @@ We use the C preprocessor to select a target architecture.
> import {-# SOURCE #-} SEL4.Kernel.Init
> import Data.Bits
+> import Data.Array
\end{impdetails}
@@ -284,8 +285,7 @@ This function is called when an IPC message includes a capability to transfer. I
> _ -> return $ mi { msgExtraCaps = fromIntegral n }
> where
> transferAgain = transferCapsToSlots ep diminish rcvBuffer (n + 1) caps
-> bitN = 1 `shiftL` n
-> miCapUnfolded = mi { msgCapsUnwrapped = msgCapsUnwrapped mi .|. bitN }
+> miCapUnfolded = mi { msgCapsUnwrapped = msgCapsUnwrapped mi .|. bit n}
> (cap, srcSlot) = arg
\subsubsection{Asynchronous IPC}
@@ -327,29 +327,38 @@ If the current thread is no longer runnable, has used its entire timeslice, an I
> setSchedulerAction ResumeCurrentThread
Threads are scheduled using a simple multiple-priority round robin algorithm.
-It iterates through the ready queues, starting with the highest priority
-queue; when it finds a non-empty ready queue, it selects the first
-thread in the queue, and makes it the current thread.
-
+It checks the priority bitmaps to find the highest priority with a non-empty
+queue. It selects the first thread in that queue and makes it the current
+thread.
Note that the ready queues are a separate structure in the kernel
model. In a real implementation, to avoid requiring
dynamically-allocated kernel memory, these queues would be linked
lists using the TCBs themselves as nodes.
+> countLeadingZeros :: (Bits b, FiniteBits b) => b -> Int
+> countLeadingZeros w =
+> length . takeWhile not . reverse . map (testBit w) $ [0 .. finiteBitSize w - 1]
+
+> wordLog2 :: (Bits b, FiniteBits b) => b -> Int
+> wordLog2 w = finiteBitSize w - 1 - countLeadingZeros w
+
> chooseThread :: Kernel ()
> chooseThread = do
-> curdom <- curDomain
-> r <- findM (chooseThread' curdom) (reverse [0 .. maxPriority])
-> when (r == Nothing) $ switchToIdleThread
-> where
-> chooseThread' :: Domain -> Priority -> Kernel Bool
-> chooseThread' qdom prio = do
-> q <- getQueue qdom prio
-> case q of
-> thread : _ -> do
-> switchToThread thread
-> return True
-> [] -> return False
+> curdom <- if numDomains > 1 then curDomain else return 0
+> l1 <- getReadyQueuesL1Bitmap curdom
+> if l1 /= 0
+> then do
+> let l1index = wordLog2 l1
+> l2 <- getReadyQueuesL2Bitmap curdom l1index
+> let l2index = wordLog2 l2
+> let prio = l1IndexToPrio l1index .|. fromIntegral l2index
+> queue <- getQueue curdom prio
+> let thread = head queue
+> runnable <- isRunnable thread
+> assert runnable "Scheduled a non-runnable thread"
+> switchToThread thread
+> else
+> switchToIdleThread
\subsubsection{Switching Threads}
@@ -486,6 +495,49 @@ When setting the scheduler state, we check for blocking of the current thread; i
The following two functions place a thread at the beginning or end of its priority's ready queue, unless it is already queued.
+FIXME DOCUMENT TWEAK AND MOVE
+
+> prioToL1Index :: Priority -> Int
+> prioToL1Index prio = fromIntegral $ prio `shiftR` wordRadix
+
+> l1IndexToPrio :: Int -> Priority
+> l1IndexToPrio i = (fromIntegral i) `shiftL` wordRadix
+
+> getReadyQueuesL1Bitmap :: Domain -> Kernel (Word)
+> getReadyQueuesL1Bitmap tdom = gets (\ks -> ksReadyQueuesL1Bitmap ks ! tdom)
+
+> modifyReadyQueuesL1Bitmap :: Domain -> (Word -> Word) -> Kernel ()
+> modifyReadyQueuesL1Bitmap tdom f = do
+> l1 <- getReadyQueuesL1Bitmap tdom
+> modify (\ks -> ks { ksReadyQueuesL1Bitmap =
+> ksReadyQueuesL1Bitmap ks // [(tdom, f l1)]})
+
+> getReadyQueuesL2Bitmap :: Domain -> Int -> Kernel (Word)
+> getReadyQueuesL2Bitmap tdom i = gets (\ks -> ksReadyQueuesL2Bitmap ks ! (tdom, i))
+
+> modifyReadyQueuesL2Bitmap :: Domain -> Int -> (Word -> Word) -> Kernel ()
+> modifyReadyQueuesL2Bitmap tdom i f = do
+> l2 <- getReadyQueuesL2Bitmap tdom i
+> modify (\ks -> ks { ksReadyQueuesL2Bitmap =
+> ksReadyQueuesL2Bitmap ks // [((tdom, i), f l2)]})
+
+> addToBitmap :: Domain -> Priority -> Kernel ()
+> addToBitmap tdom prio = do
+> let l1index = prioToL1Index prio
+> let l2bit = fromIntegral ((fromIntegral prio .&. mask wordRadix)::Word)
+> modifyReadyQueuesL1Bitmap tdom $ \w -> w .|. bit l1index
+> modifyReadyQueuesL2Bitmap tdom l1index
+> (\w -> w .|. bit l2bit)
+
+> removeFromBitmap :: Domain -> Priority -> Kernel ()
+> removeFromBitmap tdom prio = do
+> let l1index = prioToL1Index prio
+> let l2bit = fromIntegral((fromIntegral prio .&. mask wordRadix)::Word)
+> modifyReadyQueuesL2Bitmap tdom l1index $ \w -> w .&. (complement $ bit l2bit)
+> l2 <- getReadyQueuesL2Bitmap tdom l1index
+> when (l2 == 0) $
+> modifyReadyQueuesL1Bitmap tdom $ \w -> w .&. (complement $ bit l1index)
+
> tcbSchedEnqueue :: PPtr TCB -> Kernel ()
> tcbSchedEnqueue thread = do
> queued <- threadGet tcbQueued thread
@@ -494,6 +546,7 @@ The following two functions place a thread at the beginning or end of its priori
> prio <- threadGet tcbPriority thread
> queue <- getQueue tdom prio
> setQueue tdom prio $ thread : queue
+> when (null queue) $ addToBitmap tdom prio
> threadSet (\t -> t { tcbQueued = True }) thread
> tcbSchedAppend :: PPtr TCB -> Kernel ()
@@ -504,6 +557,7 @@ The following two functions place a thread at the beginning or end of its priori
> prio <- threadGet tcbPriority thread
> queue <- getQueue tdom prio
> setQueue tdom prio $ queue ++ [thread]
+> when (null queue) $ addToBitmap tdom prio
> threadSet (\t -> t { tcbQueued = True }) thread
The following function dequeues a thread, if it is queued.
@@ -515,7 +569,9 @@ The following function dequeues a thread, if it is queued.
> tdom <- threadGet tcbDomain thread
> prio <- threadGet tcbPriority thread
> queue <- getQueue tdom prio
-> setQueue tdom prio $ filter (/=thread) queue
+> let queue' = filter (/=thread) queue
+> setQueue tdom prio queue'
+> when (null queue') $ removeFromBitmap tdom prio
> threadSet (\t -> t { tcbQueued = False }) thread
\subsubsection{Timer Ticks}
diff --git a/haskell/src/SEL4/Model/StateData.lhs b/haskell/src/SEL4/Model/StateData.lhs
index e98baa35a..77ceadb23 100644
--- a/haskell/src/SEL4/Model/StateData.lhs
+++ b/haskell/src/SEL4/Model/StateData.lhs
@@ -77,6 +77,11 @@ The top-level kernel state structure is called "KernelState". It contains:
> ksReadyQueues :: Array (Domain, Priority) ReadyQueue,
+\item a bitmap for each domain; each bit represents the presence of a runnable thread for a specific priority
+
+> ksReadyQueuesL1Bitmap :: Array (Domain) Word,
+> ksReadyQueuesL2Bitmap :: Array (Domain, Int) Word,
+
\item a pointer to the current thread's control block;
> ksCurThread :: PPtr TCB,
@@ -105,6 +110,8 @@ The top-level kernel state structure is called "KernelState". It contains:
Note that this definition of "KernelState" assumes a single processor. The behaviour of the kernel on multi-processor systems is not specified by this document.
+Note that the priority bitmap is split up into two levels. In order to check to see whether a priority has a runnable thread on a 32-bit system with a maximum priority of 255, we use the high 3 bits of the priority as an index into the level 1 bitmap. If the bit at that index is set, we use those same three bits to obtain a word from the level 2 bitmap. We then use the remaining 5 bits to index into that word. If the bit is set, the queue for that priority is non-empty.
+
\subsubsection{Monads}
Kernel functions are sequences of operations that transform a "KernelState" object. They are encapsulated in the monad "Kernel", which uses "StateT" to add a "KernelState" data structure to the monad that encapsulates the simulated machine, "MachineMonad". This allows functions to read and modify the kernel state.
@@ -219,6 +226,10 @@ A new kernel state structure contains an empty physical address space, a set of
> ksReadyQueues =
> funPartialArray (const [])
> ((0, 0), (fromIntegral numDomains, fromIntegral numPriorities)),
+> ksReadyQueuesL1Bitmap = funPartialArray (const 0) (0, fromIntegral numDomains),
+> ksReadyQueuesL2Bitmap =
+> funPartialArray (const 0)
+> ((0, 0), (fromIntegral numDomains, numPriorities `div` wordBits + 1)),
> ksCurThread = error "No initial thread",
> ksIdleThread = error "Idle thread has not been created",
> ksSchedulerAction = error "scheduler action has not been set",
diff --git a/haskell/src/SEL4/Object/AsyncEndpoint.lhs b/haskell/src/SEL4/Object/AsyncEndpoint.lhs
index 2220a527a..35b9bb790 100644
--- a/haskell/src/SEL4/Object/AsyncEndpoint.lhs
+++ b/haskell/src/SEL4/Object/AsyncEndpoint.lhs
@@ -14,7 +14,7 @@ This module specify the behavior of a asynchronous IPC endpoints.
> sendAsyncIPC, receiveAsyncIPC,
> aepCancelAll, asyncIPCCancel, completeAsyncIPC,
> getAsyncEP, setAsyncEP, doUnbindAEP, unbindAsyncEndpoint,
-> unbindMaybeAEP, bindAsyncEndpoint
+> unbindMaybeAEP, bindAsyncEndpoint, doNBWaitFailedTransfer
> ) where
\begin{impdetails}
@@ -88,11 +88,17 @@ If the endpoint is active, new values are calculated and stored in the endpoint.
\subsection{Receiving Messages}
-This function performs an asynchronous IPC receive operation, given a thread pointer and a capability to an asynchronous endpoint. The receive is blocking -- the thread will be blocked on the endpoint till a message arrives.
+This function performs an asynchronous IPC receive operation, given a thread pointer and a capability to an asynchronous endpoint.
+The receive can be either blocking (the thread will be blocked on the endpoint till a message arrives) or non-blocking
+depending on the isBlocking flag.
-> receiveAsyncIPC :: PPtr TCB -> Capability -> Kernel ()
+> doNBWaitFailedTransfer :: PPtr TCB -> Kernel ()
+> doNBWaitFailedTransfer thread = asUser thread $ setRegister badgeRegister 0
-> receiveAsyncIPC thread cap = do
+
+> receiveAsyncIPC :: PPtr TCB -> Capability -> Bool -> Kernel ()
+
+> receiveAsyncIPC thread cap isBlocking = do
Fetch the asynchronous endpoint, and select the operation based on its state.
@@ -102,17 +108,22 @@ Fetch the asynchronous endpoint, and select the operation based on its state.
If the asynchronous endpoint is idle, then it becomes a waiting asynchronous endpoint, with the current thread in its queue. The thread is blocked.
-> IdleAEP -> do
-> setThreadState (BlockedOnAsyncEvent {
-> waitingOnAsyncEP = aepptr } ) thread
-> setAsyncEP aepptr $ aep {aepObj = WaitingAEP [thread] }
+> IdleAEP -> case isBlocking of
+> True -> do
+> setThreadState (BlockedOnAsyncEvent {
+> waitingOnAsyncEP = aepptr } ) thread
+> setAsyncEP aepptr $ aep {aepObj = WaitingAEP ([thread]) }
+> False -> doNBWaitFailedTransfer thread
-If the asynchronous endpoint is already waiting, the current thread is blocked and added to the queue. Note that this case cannot occur when the asynchronous endpoint is bound, as only the associated thread can wait on it.
+If the asynchronous endpoint is already waiting, the current thread is blocked and added to the queue. Note that this case cannot occur when the asynchronous endpoint is bound,
+as only the associated thread can wait on it.
-> WaitingAEP queue -> do
-> setThreadState (BlockedOnAsyncEvent {
-> waitingOnAsyncEP = aepptr } ) thread
-> setAsyncEP aepptr $ aep {aepObj = WaitingAEP (queue ++ [thread]) }
+> WaitingAEP queue -> case isBlocking of
+> True -> do
+> setThreadState (BlockedOnAsyncEvent {
+> waitingOnAsyncEP = aepptr } ) thread
+> setAsyncEP aepptr $ aep {aepObj = WaitingAEP (queue ++ [thread]) }
+> False -> doNBWaitFailedTransfer thread
If the asynchronous endpoint is active, the message will be loaded to the MRs of the thread and the endpoint will be marked as idle.
diff --git a/haskell/src/SEL4/Object/CNode.lhs b/haskell/src/SEL4/Object/CNode.lhs
index 47ffdefb3..2af4f5a4a 100644
--- a/haskell/src/SEL4/Object/CNode.lhs
+++ b/haskell/src/SEL4/Object/CNode.lhs
@@ -780,13 +780,13 @@ This helper function is used to load the capability transfer data from an IPC bu
> loadCapTransfer :: PPtr Word -> Kernel CapTransfer
> loadCapTransfer buffer = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> let offset = msgMaxLength + msgMaxExtraCaps + 2
> capTransferFromWords (buffer + PPtr (offset*intSize))
> capTransferFromWords :: PPtr Word -> Kernel CapTransfer
> capTransferFromWords ptr = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> w0 <- loadWordUser ptr
> w1 <- loadWordUser $ ptr + PPtr intSize
> w2 <- loadWordUser $ ptr + PPtr (2 * intSize)
diff --git a/haskell/src/SEL4/Object/Endpoint.lhs b/haskell/src/SEL4/Object/Endpoint.lhs
index c0073b8a8..986be4173 100644
--- a/haskell/src/SEL4/Object/Endpoint.lhs
+++ b/haskell/src/SEL4/Object/Endpoint.lhs
@@ -113,8 +113,8 @@ The IPC receive operation is essentially the same as the send operation, but wit
> isActive (AEP (ActiveAEP _) _) = True
> isActive _ = False
-> receiveIPC :: PPtr TCB -> Capability -> Kernel ()
-> receiveIPC thread cap@(EndpointCap {}) = do
+> receiveIPC :: PPtr TCB -> Capability -> Bool -> Kernel ()
+> receiveIPC thread cap@(EndpointCap {}) isBlocking = do
> let epptr = capEPPtr cap
> ep <- getEndpoint epptr
> let diminish = not $ capEPCanSend cap
@@ -124,16 +124,20 @@ The IPC receive operation is essentially the same as the send operation, but wit
> if (isJust aepptr && isActive aep)
> then completeAsyncIPC (fromJust aepptr) thread
> else case ep of
-> IdleEP -> do
-> setThreadState (BlockedOnReceive {
-> blockingIPCEndpoint = epptr,
-> blockingIPCDiminishCaps = diminish }) thread
-> setEndpoint epptr $ RecvEP [thread]
-> RecvEP queue -> do
-> setThreadState (BlockedOnReceive {
-> blockingIPCEndpoint = epptr,
-> blockingIPCDiminishCaps = diminish }) thread
-> setEndpoint epptr $ RecvEP $ queue ++ [thread]
+> IdleEP -> case isBlocking of
+> True -> do
+> setThreadState (BlockedOnReceive {
+> blockingIPCEndpoint = epptr,
+> blockingIPCDiminishCaps = diminish }) thread
+> setEndpoint epptr $ RecvEP [thread]
+> False -> doNBWaitFailedTransfer thread
+> RecvEP queue -> case isBlocking of
+> True -> do
+> setThreadState (BlockedOnReceive {
+> blockingIPCEndpoint = epptr,
+> blockingIPCDiminishCaps = diminish }) thread
+> setEndpoint epptr $ RecvEP $ queue ++ [thread]
+> False -> doNBWaitFailedTransfer thread
> SendEP (sender:queue) -> do
> setEndpoint epptr $ case queue of
> [] -> IdleEP
@@ -155,7 +159,7 @@ The IPC receive operation is essentially the same as the send operation, but wit
> _ -> setThreadState Inactive sender
> SendEP [] -> fail "Send endpoint queue must not be empty"
-> receiveIPC _ _ = fail "receiveIPC: invalid cap"
+> receiveIPC _ _ _ = fail "receiveIPC: invalid cap"
\subsection{Kernel Invocation Replies}
diff --git a/haskell/src/SEL4/Object/Structures.lhs b/haskell/src/SEL4/Object/Structures.lhs
index 36be8dacb..0ac49b627 100644
--- a/haskell/src/SEL4/Object/Structures.lhs
+++ b/haskell/src/SEL4/Object/Structures.lhs
@@ -410,10 +410,26 @@ Each entry in the domain schedule specifies a domain and a length (a number of t
> dschLength :: (Domain, Word) -> Word
> dschLength = snd
-The following function selects one of two alternatives depending on the size of the machine word (32 or 64 bits).
+Convenience functions dealing with properties of the machine word:
+\begin{itemize}
+\item Number of bits in a word
+\item Radix $n$ such that $2^n$ is the number of bits in the word
+\item Bytes required to store a word
+\item Selecting one of two alternatives depending on the size of the machine word
+ (32 or 64 bits)
+\end{itemize}
+
+> wordBits :: Int
+> wordBits = finiteBitSize (undefined::Word)
+
+> wordRadix :: Int
+> wordRadix = wordSizeCase 5 6
+
+> wordSize :: Int
+> wordSize = wordBits `div` 8
> wordSizeCase :: a -> a -> a
-> wordSizeCase a b = case finiteBitSize (undefined::Word) of
+> wordSizeCase a b = case wordBits of
> 32 -> a
> 64 -> b
> _ -> error "Unknown word size"
diff --git a/haskell/src/SEL4/Object/TCB.lhs b/haskell/src/SEL4/Object/TCB.lhs
index b98908d1e..85ad05517 100644
--- a/haskell/src/SEL4/Object/TCB.lhs
+++ b/haskell/src/SEL4/Object/TCB.lhs
@@ -516,7 +516,7 @@ The "setMRs" function returns the number of words of message data successfully t
> setMRs :: PPtr TCB -> Maybe (PPtr Word) -> [Word] -> Kernel Word
> setMRs thread buffer messageData = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> let hardwareMRs = msgRegisters
> let bufferMRs = case buffer of
> Just bufferPtr ->
@@ -535,7 +535,7 @@ The "setMRs" function returns the number of words of message data successfully t
> getMRs :: PPtr TCB -> Maybe (PPtr Word) -> MessageInfo ->
> Kernel [Word]
> getMRs thread buffer info = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> let hardwareMRs = msgRegisters
> hardwareMRValues <- asUser thread $ mapM getRegister hardwareMRs
> bufferMRValues <- case buffer of
@@ -556,7 +556,7 @@ This function's first argument is the maximum number of message registers to cop
> PPtr TCB -> Maybe (PPtr Word) ->
> Word -> Kernel Word
> copyMRs sender sendBuf receiver recvBuf n = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> let hardwareMRs = take (fromIntegral n) msgRegisters
> forM hardwareMRs $ \r -> do
> v <- asUser sender $ getRegister r
@@ -577,7 +577,7 @@ The following functions read and set the extra capability fields of the IPC buff
> getExtraCPtrs :: Maybe (PPtr Word) -> MessageInfo ->
> Kernel [CPtr]
> getExtraCPtrs buffer (MI { msgExtraCaps = count }) = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> case buffer of
> Just bufferPtr -> do
> let offset = msgMaxLength+1
@@ -600,7 +600,7 @@ mapM (getExtraCPtr buffer) [0..count-1]
> getExtraCPtr :: PPtr Word -> Int -> Kernel CPtr
> getExtraCPtr buffer n = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> let ptr = buffer + bufferCPtrOffset +
> PPtr ((fromIntegral n) * intSize)
> cptr <- loadWordUser ptr
@@ -610,14 +610,14 @@ Write the unwrapped badge into the IPC buffer for cap n.
> setExtraBadge :: PPtr Word -> Word -> Int -> Kernel ()
> setExtraBadge buffer badge n = do
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> let badgePtr = buffer + bufferCPtrOffset +
> PPtr ((fromIntegral n) * intSize)
> storeWordUser badgePtr badge
> bufferCPtrOffset :: PPtr Word
> bufferCPtrOffset =
-> let intSize = fromIntegral $ finiteBitSize (undefined::Word) `div` 8
+> let intSize = fromIntegral wordSize
> in PPtr ((msgMaxLength+2)*intSize)
\subsection{Creating and Destroying the Caller Capability}
diff --git a/include/api/syscall.xml b/include/api/syscall.xml
index 1c17e9c31..1439680c3 100644
--- a/include/api/syscall.xml
+++ b/include/api/syscall.xml
@@ -20,6 +20,7 @@
+
diff --git a/include/arch/x86/arch/machine.h b/include/arch/x86/arch/machine.h
index eba9f5f70..a7c9c83fe 100644
--- a/include/arch/x86/arch/machine.h
+++ b/include/arch/x86/arch/machine.h
@@ -18,7 +18,8 @@
#include
#include
-#define wordBits 32
+#define wordRadix 5
+#define wordBits (1 << wordRadix)
#define IA32_APIC_BASE_MSR 0x01B
#define IA32_SYSENTER_CS_MSR 0x174
diff --git a/include/kernel/thread.h b/include/kernel/thread.h
index e8b773f08..3b62e4817 100644
--- a/include/kernel/thread.h
+++ b/include/kernel/thread.h
@@ -14,6 +14,30 @@
#include
#include
#include