Professional Documents
Culture Documents
Germán Rivera
jgrivera67@gmail.com
1 Introduction 1
2 HiRTOS Overview 3
2.1 RTOS Major Design Decisions . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Separation Kernel Major Design Decisions . . . . . . . . . . . . . . . . 4
2.3 HiRTOS Code Architecture . . . . . . . . . . . . . . . . . . . . . . . . 5
3 HiRTOS Z Specification 9
3.1 HiRTOS Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.1.1 Z Naming Conventions . . . . . . . . . . . . . . . . . . . . . . . 9
3.1.2 HiRTOS Configuration Parameters . . . . . . . . . . . . . . . . 9
3.1.3 HiRTOS Target Platform Parameters . . . . . . . . . . . . . . 10
3.1.4 HiRTOS Primitive Types . . . . . . . . . . . . . . . . . . . . . 10
3.1.5 HiRTOS Axiomatic Definitions . . . . . . . . . . . . . . . . . . 12
3.1.6 HiRTOS State Variables . . . . . . . . . . . . . . . . . . . . . . 12
3.2 HiRTOS Boot-time Initialization . . . . . . . . . . . . . . . . . . . . . 18
3.3 HiRTOS Callable Services . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.3.1 HiRTOS Threads Operations . . . . . . . . . . . . . . . . . . . 21
3.3.2 HiRTOS Mutex Operations . . . . . . . . . . . . . . . . . . . . 22
3.3.3 HiRTOS Condition Variable Operations . . . . . . . . . . . . . 26
3.3.4 HiRTOS Software Timer Operations . . . . . . . . . . . . . . . 29
i
ii
Chapter 1
Introduction
This document describes the design of HiRTOS (“High Integrity” RTOS), a real-
time operating system kernel (RTOS) written in SPARK Ada. HiRTOS targets
safety-critical and security-sensitive embedded software applications that run in small
multi-core microcontrollers. HiRTOS was designed using the Z notation, as a method-
ical way to capture correctness assumptions that can be expressed as programming
contracts in SPARK Ada. Z is a software modeling notation based on discrete math-
ematics structures (such as sets, relations and functions) and predicate logic.
Although there are several popular RTOSes for embedded applications that run on
small multi-core microcontrollers, most of them are not designed with high-integrity
applications in mind, and as such are written in C, a notoriously unsafe language.
So, it would be desirable to have an RTOS specifically designed for high-integrity
applications, and written in a safer language, like Ada or its subset SPARK Ada, even
if application code is written in C/C++. Modern versions of the Ada and SPARK
languages have programming-by-contract constructs built-in in the language, which
allows the programmer to express correctness assumptions as part of the code. One
challenge when doing programming-by-contract is to be aware of all the correctness
assumptions that can be checked in programming contracts. Describing software
design in a formal notation, such as the Z notation [1, 2, 3], can help identify/elicit
correctness assumptions in a more thorough and methodical way than just writing
code.
Z is a software modeling notation based on discrete mathematics structures (such
as sets, relations and functions) and predicate logic. With Z, data structures can be
specified in terms of mathematical structures and their state invariants can be spec-
ified using mathematical predicates. The pre-conditions and post-conditions of the
operations that manipulate the data structures can also be specified using predicates.
Using Z for this purpose encourages a rigorous and methodical thought process to
elicit correctness properties, in a systematic way. The HiRTOS Z model described
here was checked with the fuzz tool [4], a Z type-checker, that catches Z type mis-
matches in predicates.
The code of HiRTOS is written in SPARK Ada [5], a high integrity subset of
1
2 Design of the HiRTOS Multi-core Real-Time Operating System
the Ada programming language. HiRTOS data types were modeled in Z at a level
of abstraction that can be mapped directly to corresponding data types in SPARK
Ada.
Chapter 2
HiRTOS Overview
• Unlike C11 mutexes, HiRTOS mutexes can change the priority of the thread
owning the mutex. HiRTOS mutexes support both priority inheritance and
priority ceiling [10].
• Unlike C11 condition variables, HiRTOS condition variables can also be waited
on while having interrupts disabled, not just while holding a mutex.
• HiRTOS atomic levels can be used to disable the thread scheduler or to disable
interrupts at and below a given priority or to disable all interrupts.
• In a multi-core platform, there is one HiRTOS instance per CPU Core. Each
HiRTOS instance is independent of each other. No resources are shared between
HiRTOS instances. No communication between CPU cores is supported by
HiRTOS, so that the HiRTOS API can stay the same for both single-core and
multi-core platforms. Inter-core communication would need to be provided
outside of HiRTOS, using doorbell interrupts and mailboxes or shared memory,
for example.
• Threads are bound to the CPU core in which they were created, for the lifetime
of the thread. That is, no thread migration between CPU cores is supported.
• All RTOS objects such as threads, mutexes and condition variables are allo-
cated internally by HiRTOS from statically allocated internal object pools.
These object pools are just RTOS-private global arrays of the corresponding
3
4 Design of the HiRTOS Multi-core Real-Time Operating System
RTOS object types, sized at compile time via configuration parameters, whose
values are application-specific. RTOS object handles provided to application
code are just indices into these internal object arrays. No actual RTOS object
pointers exposed to application code. No dynamic allocation/deallocation of
RTOS objects is supported and no static allocation of RTOS objects in mem-
ory owned by application code is supported either.
• All application threads run in unprivileged mode. For each thread, the only
writable memory, by default, is its own stack and global variables. Stacks of
other threads are not accessible. MMIO space is only accessible to privileged
code, by default. Application driver code, other than ISRs, must request access
(read-only or read-write permission) to HiRTOS via a system call.
• In a multi-core platform, there is one separation kernel instance per CPU Core.
Each instance is independent of each other. No resources are shared between
separation kernel instances. No communication between CPU cores is sup-
ported, so that the separation kernel API can stay the same for both single-core
and multi-core platforms. Inter-core communication would need to be provided
outside of HiRTOS, using doorbell interrupts and mailboxes or shared memory,
for example.
• Partitions are bound to the CPU core in which they were created. That is, no
partition migration between CPU cores is supported.
Design of the HiRTOS Real-Time Operating System 5
• Partitions are created at boot time before starting the partition scheduler on
the corresponding CPU core. Partitions cannot be destroyed or terminated.
• The separation kernel code itself runs in hypervisor privilege mode. All parti-
tions run at a privilege lower than hypervisor mode. Partitions can communi-
cate with the separation kernel via hypervisor calls and via traps to hypervisor
mode triggered from special machine instructions such as WFI . The separation
kernel can communicate with partitions, by forwarding interrupts targeted to
the corresponding partition.
C Interface Skin
HiRTOS
HiRTOS
HiRTOS
HiRTOS API
HiRTOS
HiRTOS.Thread HiRTOS.Timer
HiRTOS.Condvar HiRTOS.Mutex
HiRTOS internals
RTOS Private
HiRTOS.CondvarPrivate HiRTOS.MutexPrivate
HiRTOS Z Specification
• Identifiers that start with the z prefix are meant to be modeling-only entities
that do not physically correspond to code-level entities.
maxNumThreads : N1
maxNumMutexes : N1
maxNumCondvars : N1
maxNumTimers : N1
numThreadPriorities : N1
numTimerWheelSpokes : N1
maxNumThreads ≥ 2 ∗ numCpus
maxNumCondvars ≥ maxNumThreads
maxNumTimers ≥ maxNumThreads
The minimum number of threads that can be configured per CPU core is 2, which
corresponds to the HiRTOS pre-defined threads: the idle thread and the tick timer
9
10 Design of the HiRTOS Multi-core Real-Time Operating System
thread. Each thread has a builtin timer, so the minimum number of timers that
can be configured is maxNumThreads. Also, each thread has a builtin condition
variable, so the minimum number of condition variables that can be configured is
maxNumThreads as well.
numCpus : N1
minMemoryAddress : N
maxMemoryAddress : N1
numInterruptPriorities : N1
maxNumInterrupts : N1
minMemoryAddress < maxMemoryAddress
[CpuIdType]
#CpuIdType = numCpus + 1
[ThreadIdType]
#ThreadIdType = maxNumThreads + 1
[MutexIdType]
#MutexIdType = maxNumMutexes + 1
[CondvarIdType]
#CondvarIdType = maxNumCondvars + 1
[TimerIdType]
#TimerIdType = maxNumTimers + 1
[InterruptIdType]
#InterruptIdType = maxNumInterrupts + 1
invalidCpuId : CpuIdType
invalidThreadId : ThreadIdType
invalidMutexId : MutexIdType
invalidCondvarId : CondvarIdType
invalidTimerId : TimerIdType
invalidInterruptId : InterruptIdType
Design of the HiRTOS Real-Time Operating System 11
[CpuRegistersType]
ValidCpuIdType == CpuIdType \ {invalidCpuId }
MemoryAddressType ==
minMemoryAddress . . maxMemoryAddress
nullAddress == 0
ValidThreadIdType ==
ThreadIdType \ {invalidThreadId }
ValidMutexIdType == MutexIdType \ {invalidMutexId }
ValidCondvarIdType ==
CondvarIdType \ {invalidCondvarId }
ValidTimerIdType == TimerIdType \ {invalidTimerId }
ValidInterruptIdType ==
InterruptIdType \ {invalidInterruptId }
ThreadPriorityType == 0 . . numThreadPriorities
invalidThreadPriority == numThreadPriorities
ValidThreadPriorityType ==
ThreadPriorityType \ {invalidThreadPriority}
InterruptPriorityType == 0 . . numInterruptPriorities
invalidInterruptPriority == numInterruptPriorities
ValidInterruptPriorityType ==
InterruptPriorityType \ {invalidInterruptPriority}
AtomicLevelType == 0 . . numInterruptPriorities + 1
atomicLevelNoInterrupts == min AtomicLevelType
atomicLevelSingleThread == max AtomicLevelType − 1
atomicLevelNone == max AtomicLevelType
InterruptNestingCounterType ==
0 . . numInterruptPriorities
ActiveInterruptNestingCounterType ==
InterruptNestingCounterType \ { 0 }
CpuInterruptMaskingStateType ::=
cpuInterruptsEnabled |
cpuInterruptsDisabled
CpuPrivilegeType ::= cpuPrivileged | cpuUnprivileged
MemoryProtectionStateType ::=
memoryProtectionOn | memoryProtectionOff
CpuExecutionModeType ::=
cpuExecutingResetHandler |
cpuExecutingInterruptHandler |
cpuExecutingThread
ThreadStateType ::= threadNotCreated | threadSuspended |
threadRunnable | threadRunning |
threadBlockedOnCondvar | threadBlockedOnMutex
ThreadSchedulerStateType ::=
threadSchedulerStopped | threadSchedulerRunning
12 Design of the HiRTOS Multi-core Real-Time Operating System
For interrupts, lower priority values represent higher priorities. For threads, lower
priority values represent lower priorities.
zCpuToISRstackAddressRange :
ValidCpuIdType
(MemoryAddressType × MemoryAddressType)
{ i : ValidCpuIdType •
T
zAddressRange(zCpuToISRstackAddressRange(i )) } = ∅
∀ i : dom zCpuToISRstackAddressRange •
#(zAddressRange(zCpuToISRstackAddressRange(i ))) ≥ 2
interruptPriorities :
InterruptIdType → InterruptPriorityType
HiRtos
rtosCpuInstances :
ValidCpuIdType 7 7 HiRtosCpuInstanceType
zAllCreatedThreadInstances : F ThreadType
#rtosCpuInstances ≥ 1
∀ i : dom rtosCpuInstances •
(rtosCpuInstances(i )).cpuId = i
zAllCreatedThreadInstances =
{ i : ValidCpuIdType •
S
ran(rtosCpuInstances(i )).threads }
{ i : ValidCpuIdType •
T
ran(rtosCpuInstances(i )).threads } = ∅
{ thread : zAllCreatedThreadInstances •
T
zAddressRange(thread .stack ) } = ∅
{ i : ValidCpuIdType •
T
ran(rtosCpuInstances(i )).mutexes } = ∅
{ i : ValidCpuIdType •
T
ran(rtosCpuInstances(i )).condvars } = ∅
{ i : ValidCpuIdType •
T
ran(rtosCpuInstances(i )).timers } = ∅
{t : zAllCreatedThreadInstances • zAddressRange(t.stack ) } = ∅
T
HiRtosCpuInstanceType
cpuId : CpuIdType
currentCpuContext : CpuRegistersType
threadSchedulerState : ThreadSchedulerStateType
currentAtomicLevel : AtomicLevelType
currentCpuExecutionMode : CpuExecutionModeType
currentThreadId : ThreadIdType
timerTicksSinceBoot : N
idleThreadId : ValidThreadIdType
tickTimerThreadId : ValidThreadIdType
interruptNestingLevelStack : InterruptNestingLevelStackType
threads : ValidThreadIdType 7 7 ThreadType
mutexes : ValidMutexIdType 7 7 MutexType
condvars : ValidCondvarIdType 7 7 CondvarType
timers : ValidTimerIdType 7 7 TimerType
runnableThreadsQueue : ThreadPriorityQueueType
timerWheel : TimerWheelType
zCpuInterruptMaskingState : CpuInterruptMaskingStateType
zCpuPrivilege : CpuPrivilegeType
zMemoryProtectionState : MemoryProtectionStateType
{ idleThreadId , tickTimerThreadId } ⊆ dom threads
tickTimerThreadId 6= idleThreadId
threadSchedulerState = threadSchedulerRunning ⇒
(∀ t : ran({ currentThreadId } −
C threads) •
t.currentPriority < (threads(currentThreadId )).currentPriority)
zCpuInterruptMaskingState = cpuInterruptsEnabled ⇔
currentAtomicLevel > atomicLevelNoInterrupts
zCpuInterruptMaskingState = cpuInterruptsDisabled ⇒ zCpuPrivilege = cpuPrivileged
currentAtomicLevel < atomicLevelNone ⇒ zCpuPrivilege = cpuPrivileged
{ t : ran threads • { t.builtinCondvarId } } = ∅
T
ThreadPriorityQueueType
threadQueues :
ValidThreadPriorityType ThreadQueueType
waitingThreadsCount : N
waitingThreadsCount =
#( { p : ValidThreadPriorityType • threadQueues(p) })
S
InterruptNestingLevelStackType
interruptNestingLevels :
ActiveInterruptNestingCounterType
InterruptNestingLevelType
currentInterruptNestingCounter :
InterruptNestingCounterType
zCpuId : ValidCpuIdType
∀ x : dom interruptNestingLevels •
(interruptNestingLevels(x )).interruptNestingCounter = x
∧
(interruptNestingLevels(x )).savedStackPointer ∈
zAddressRange(zCpuToISRstackAddressRange(zCpuId ))
dom interruptNestingLevels =
1 . . currentInterruptNestingCounter
InterruptNestingLevelType
interruptId : InterruptIdType
interruptNestingCounter : ActiveInterruptNestingCounterType
savedStackPointer : MemoryAddressType
atomicLevel : AtomicLevelType
atomicLevel ≤ interruptPriorities(interruptId )
TimerWheelType
wheelSpokesHashTable :
ValidTimerWheelSpokeIndexType → F ValidTimerIdType
currentWheelSpokeIndex : ValidTimerWheelSpokeIndexType
∀ i , j : ValidTimerWheelSpokeIndexType | i 6= j •
wheelSpokesHashTable(i ) ∩ wheelSpokesHashTable(j ) = ∅
16 Design of the HiRTOS Multi-core Real-Time Operating System
TimerType
id : TimerIdType
timerKind : TimerKindType
timerState : TimerStateType
timerWheelRevolutions : N
timerWheelRevolutionsLeft : N
expirationCallbackAddr : MemoryAddressType
wheelSpokeIndex : TimerWheelSpokeIndexType
timerWheelRevolutionsLeft ≤ timerWheelRevolutions
timerState = timerRunning ⇒ expirationCallbackAddr 6= nullAddress
Design of the HiRTOS Real-Time Operating System 17
ThreadType
id : ThreadIdType
state : ThreadStateType
currentPriority : ThreadPriorityType
basePriority : ThreadPriorityType
atomicLevel : AtomicLevelType
builtinTimerId : TimerIdType
builtinCondvarId : CondvarIdType
waitingOnCondvarId : CondvarIdType
waitingOnMutexId : MutexIdType
ownedMutexes : iseq ValidMutexIdType
savedStackPointer : MemoryAddressType
stack : AddressRangeType
stackSavedCpuContext : CpuRegistersType
privilegedNestingCounter : N
timeSliceLeftUs : N
state 6= threadNotCreated ⇒
(id 6= invalidThreadId ∧
builtinTimerId 6= invalidTimerId ∧
builtinCondvarId 6= invalidCondvarId ∧
basePriority 6= invalidThreadPriority ∧
currentPriority 6= invalidThreadPriority ∧
savedStackPointer ∈ zAddressRange(stack ))
currentPriority ≥ basePriority
state = threadBlockedOnCondvar ⇔
waitingOnCondvarId 6= invalidCondvarId
state = threadBlockedOnMutex ⇔
waitingOnMutexId 6= invalidMutexId
waitingOnCondvarId 6= invalidCondvarId ⇒
waitingOnMutexId = invalidMutexId
waitingOnMutexId 6= invalidMutexId ⇒
waitingOnCondvarId = invalidCondvarId
waitingOnMutexId ∈
/ ran ownedMutexes
18 Design of the HiRTOS Multi-core Real-Time Operating System
CondvarType
id : CondvarIdType
wakeupAtomicLevel : AtomicLevelType
wakeupMutexId : MutexIdType
waitingThreadsQueue : ThreadPriorityQueueType
wakeupAtomicLevel 6= atomicLevelNone ⇒ wakeupMutexId = invalidMutexId
MutexType
id : MutexIdType
ownerThreadId : ThreadIdType
recursiveCount : N
ceilingPriority : ThreadPriorityType
waitingThreadsQueue : ThreadPriorityQueueType
waitingThreadsQueue.waitingThreadsCount 6= 0 ⇒
ownerThreadId 6= invalidThreadId
ceilingPriority 6= invalidThreadPriority ⇒
(∀ p : ValidThreadPriorityType |
waitingThreadsQueue.threadQueues(p) 6= ∅ •
p ≤ ceilingPriority)
HiRtosInitialize
HiRtos 0
HiRtosCpuInstanceInitialize
cpuId ? : CpuIdType
cpuId 0 = cpuId ?
θHiRtosCpuInstanceType 0 = rtosCpuInstances 0 (cpuId ?)
interruptNestingLevelStack 0 .zCpuId = cpuId ?
Design of the HiRTOS Real-Time Operating System 19
HiRtosCpuInstanceInitialize
HiRtosCpuInstanceElaboration
idleThreadId 0 6= invalidThreadId
tickTimerThreadId 0 6= invalidThreadId
tickTimerThreadId 0 6= idleThreadId 0
dom threads 0 = { idleThreadId 0 , tickTimerThreadId 0 }
dom condvars 0 =
{ (threads 0 (idleThreadId 0 )).builtinCondvarId ,
(threads 0 (tickTimerThreadId 0 )).builtinCondvarId }
dom timers 0 =
{ (threads 0 (idleThreadId 0 )).builtinTimerId ,
(threads 0 (tickTimerThreadId 0 )).builtinTimerId }
zCpuInterruptMaskingState 0 = cpuInterruptsEnabled
zCpuPrivilege 0 = cpuUnprivileged
zMemoryProtectionState 0 = memoryProtectionOn
runnableThreadsQueue 0 .threadQueues(min ValidThreadPriorityType)
= hidleThreadId 0 i
runnableThreadsQueue 0 .threadQueues(max ValidThreadPriorityType)
= htickTimerThreadId 0 i
∀ p : ValidThreadPriorityType\
{ min ValidThreadPriorityType, max ValidThreadPriorityType } •
runnableThreadsQueue 0 .threadQueues(p) = ∅
20 Design of the HiRTOS Multi-core Real-Time Operating System
HiRtosCpuInstanceElaboration
HiRtosCpuInstanceType 0
InterruptNestingLevelStackElaboration
threadSchedulerState 0 = threadSchedulerStopped
currentThreadId 0 = invalidThreadId
currentAtomicLevel 0 = atomicLevelNone
currentCpuExecutionMode 0 = cpuExecutingResetHandler
idleThreadId 0 = invalidThreadId
tickTimerThreadId 0 = invalidThreadId
threads 0 = ∅
condvars 0 = ∅
timers 0 = ∅
timerTicksSinceBoot 0 = 0
InterruptNestingLevelStackElaboration
InterruptNestingLevelStackType 0
InterruptNestingLevelElaboration
currentInterruptNestingCounter 0 = 1
∀ x : ActiveInterruptNestingCounterType •
interruptNestingLevels 0 (x ) = θInterruptNestingLevelType 0
InterruptNestingLevelElaboration
InterruptNestingLevelType 0
interruptId 0 = invalidInterruptId
interruptNestingCounter 0 = 0
savedStackPointer 0 = nullAddress
atomicLevel 0 = atomicLevelNone
Design of the HiRTOS Real-Time Operating System 21
TimerWheelElaboration
TimerWheelType 0
ran wheelSpokesHashTable 0 = { ∅ }
currentWheelSpokeIndex 0 =
min ValidTimerWheelSpokeIndexType
CreateThread
∆HiRtosCpuInstanceType
InitializeNewThread
priority? : ValidThreadPriorityType
threadId ! ∈
/ dom threads
condvarId ! ∈
/ dom condvars
timerId ! ∈
/ dom timers
threadId ! ∈ dom threads 0
condvarId ! ∈ dom condvars 0
timerId ! ∈ dom timers 0
threads 0 (threadId !) = θThreadType 0
runnableThreadsQueue 0 .threadQueues(priority?) =
runnableThreadsQueue.threadQueues(priority?) a hthreadId !i
22 Design of the HiRTOS Multi-core Real-Time Operating System
InitializeNewThread
ThreadType 0
condvarId ! : ValidCondvarIdType
timerId ! : ValidTimerIdType
threadId ! : ValidThreadIdType
threadId ! 6= invalidThreadId
id 0 = threadId !
builtinTimerId 0 = timerId !
builtinCondvarId 0 = condvarId !
state 0 = threadRunnable
atomicLevel 0 = atomicLevelNone
ThreadPriorityQueueInitialize
ThreadPriorityQueueType 0
∀ p : ValidThreadPriorityType •
threadQueues 0 (p) = ∅
DequeueHighestPriorityThread
∆ThreadPriorityQueueType
highestPriorityThreadId ! : ValidThreadIdType
(let highestPrio ==
max (dom(threadQueues − B ∅)) •
highestPriorityThreadId ! = head (threadQueues(highestPrio)) ∧
threadQueues 0 (highestPrio) = tail (threadQueues(highestPrio)))
CreateMutex
∆HiRtosCpuInstanceType
InitializeNewMutex
mutexId ! ∈
/ dom mutexes
mutexId ! ∈ dom mutexes 0
θMutexType 0 = mutexes 0 (mutexId !)
InitializeNewMutex
MutexType 0
ceilingPriority? : ThreadPriorityType
mutexId ! : ValidMutexIdType
mutexId ! 6= invalidMutexId
id 0 = mutexId !
ownerThreadId 0 = invalidThreadId
recursiveCount 0 = 0
ceilingPriority 0 = ceilingPriority?
∀ p : ValidThreadPriorityType •
waitingThreadsQueue 0 .threadQueues(p) = ∅
CreatedMutexMutableOperation
∆HiRtos
∆HiRtosCpuInstanceType
∆MutexType
cpuId ? : CpuIdType
mutexId ? : ValidMutexIdType
θHiRtosCpuInstanceType = rtosCpuInstances(cpuId ?)
θHiRtosCpuInstanceType 0 = rtosCpuInstances 0 (cpuId ?)
θMutexType = mutexes(mutexId ?)
θMutexType 0 = mutexes 0 (mutexId ?)
Acquire a mutex
A thread acquires a mutex by calling HiRTOS.Mutex.Acquire, according to the con-
tract specified by the AcquireMutex schema:
AcquireAvailableMutex
CreatedMutexMutableOperation
ownerThreadId = invalidThreadId ∨
(ownerThreadId = currentThreadId ⇒
recursiveCount 0 = recursiveCount + 1)
ownerThreadId 0 = currentThreadId
(ceilingPriority 6= invalidThreadPriority ∧
(threads(currentThreadId )).currentPriority <
ceilingPriority) ⇒
(threads 0 (currentThreadId )).currentPriority =
ceilingPriority
(threads 0 (currentThreadId )).ownedMutexes =
(threads(currentThreadId )).ownedMutexes a hmutexId ?i
Design of the HiRTOS Real-Time Operating System 25
WaitOnUnavailableMutex
CreatedMutexMutableOperation
DequeueHighestPriorityThread
runnableThreadsQueue = θThreadPriorityQueueType
runnableThreadsQueue 0 = θThreadPriorityQueueType 0
ownerThreadId 6= invalidThreadId
currentThreadId 6= ownerThreadId
currentThreadId 0 6= currentThreadId
(let oldCurrentPriority ==
(threads(currentThreadId )).currentPriority •
(ceilingPriority = invalidThreadPriority ∧
oldCurrentPriority >
(threads(ownerThreadId )).currentPriority) ⇒
(threads 0 (ownerThreadId )).currentPriority =
oldCurrentPriority
∧
currentThreadId 0 6= ownerThreadId ⇒
((threads 0 (currentThreadId 0 )).currentPriority ≥
(threads 0 (ownerThreadId )).currentPriority ∨
(threads 0 (ownerThreadId )).state ∈ {threadBlockedOnMutex , threadBlockedOnCondvar })
∧
(threads 0 (currentThreadId )).state = threadBlockedOnMutex
∧
currentThreadId ∈
ran(waitingThreadsQueue 0 .threadQueues(oldCurrentPriority)))
ceilingPriority 6= invalidThreadPriority ⇒
((threads(currentThreadId )).currentPriority ≤
(threads 0 (ownerThreadId )).currentPriority ∧
(threads 0 (ownerThreadId )).state ∈ {threadBlockedOnMutex , threadBlockedOnCondvar })
currentThreadId 0 6= currentThreadId
currentThreadId 0 = highestPriorityThreadId !
AcquireMutex =
b
AcquireAvailableMutex ∨ WaitOnUnavailableMutex
26 Design of the HiRTOS Multi-core Real-Time Operating System
Release a mutex
A thread releases a mutex by calling HiRTOS.Mutex.Release, according to the con-
tract specified by the ReleaseMutex schema:
ReleaseMutex
CreatedMutexMutableOperation
DequeueHighestPriorityThread
waitingThreadsQueue = θThreadPriorityQueueType
waitingThreadsQueue 0 = θThreadPriorityQueueType 0
mutexId ? = head (threads(currentThreadId )).ownedMutexes
(threads 0 (currentThreadId )).ownedMutexes = tail (threads(currentThreadId )).ownedMute
(let p == (threads(highestPriorityThreadId !)).currentPriority •
runnableThreadsQueue 0 .threadQueues(p) =
runnableThreadsQueue.threadQueues(p) a hhighestPriorityThreadId !i)
CreateCondvar
∆HiRtosCpuInstanceType
InitializeNewCondvar
condvarId ! ∈
/ dom condvars
condvarId ! ∈ dom condvars 0
condvars 0 (condvarId !) = θCondvarType 0
Design of the HiRTOS Real-Time Operating System 27
InitializeNewCondvar
CondvarType 0
ThreadPriorityQueueInitialize
condvarId ! : ValidCondvarIdType
waitingThreadsQueue 0 = θThreadPriorityQueueType 0
condvarId ! 6= invalidCondvarId
id 0 = condvarId !
wakeupAtomicLevel 0 = atomicLevelNone
wakeupMutexId 0 = invalidMutexId
CreatedCondvarMutableOperation
∆HiRtos
∆HiRtosCpuInstanceType
∆CondvarType
cpuId ? : CpuIdType
condvarId ? : ValidCondvarIdType
rtosCpuInstances(cpuId ?) = θHiRtosCpuInstanceType
rtosCpuInstances 0 (cpuId ?) = θHiRtosCpuInstanceType 0
condvars(condvarId ?) = θCondvarType
condvars 0 (condvarId ?) = θCondvarType 0
WaitOnCondvar
CreatedCondvarMutableOperation
DequeueHighestPriorityThread
mutexId ? : ValidMutexIdType
runnableThreadsQueue = θThreadPriorityQueueType
runnableThreadsQueue 0 = θThreadPriorityQueueType 0
mutexId ? ∈ ran(threads(currentThreadId )).ownedMutexes
/ ran(threads 0 (currentThreadId )).ownedMutexes
mutexId ? ∈
wakeupMutexId 0 = mutexId ?
(let p == (threads(currentThreadId )).currentPriority •
waitingThreadsQueue 0 .threadQueues(p) =
waitingThreadsQueue.threadQueues(p) a hcurrentThreadId i)
currentThreadId 0 6= currentThreadId
currentThreadId 0 = highestPriorityThreadId !
SignalCondvar
CreatedCondvarMutableOperation
DequeueHighestPriorityThread
waitingThreadsQueue = θThreadPriorityQueueType
waitingThreadsQueue 0 = θThreadPriorityQueueType 0
wakeupMutexId ∈ ran(threads 0 (highestPriorityThreadId !)).ownedMutexes
(let p == (threads(highestPriorityThreadId !)).currentPriority •
runnableThreadsQueue 0 .threadQueues(p) =
runnableThreadsQueue.threadQueues(p) a hhighestPriorityThreadId !i)
BroadcastCondvar
CreatedCondvarMutableOperation
(∀ p : ValidThreadPriorityType |
waitingThreadsQueue.threadQueues(p) 6= ∅ •
waitingThreadsQueue 0 .threadQueues(p) = ∅ ∧
runnableThreadsQueue 0 .threadQueues(p) =
runnableThreadsQueue.threadQueues(p)a
waitingThreadsQueue.threadQueues(p))
CreateTimer
∆HiRtosCpuInstanceType
InitializeNewTimer
timerId ! ∈
/ dom timers
timerId ! ∈ dom timers 0
timers 0 (timerId !) = θTimerType 0
InitializeNewTimer
TimerType 0
timerId ! : ValidTimerIdType
timerId ! 6= invalidTimerId
id 0 = timerId !
timerKind 0 = oneShotTimer
timerState 0 = timerStopped
timerWheelRevolutions 0 = 0
timerWheelRevolutionsLeft 0 = 0
expirationCallbackAddr 0 = nullAddress
wheelSpokeIndex 0 = invalidTimerWheelSpokeIndex
of all the mutable operations that can be performed on software timers that were
previously created by a call to HiRTOS.Timer.Create:
CreatedTimerMutableOperation
∆HiRtos
∆HiRtosCpuInstanceType
∆TimerType
cpuId ? : CpuIdType
timerId ? : ValidTimerIdType
rtosCpuInstances(cpuId ?) = θHiRtosCpuInstanceType
rtosCpuInstances 0 (cpuId ?) = θHiRtosCpuInstanceType 0
timers(timerId ?) = θTimerType
timers 0 (timerId ?) = θTimerType 0
StartTimer
CreatedTimerMutableOperation
expirationTimeUs? : N
expirationCallbackAddr ? : MemoryAddressType
timerKind ? : TimerKindType
expirationCallbackAddr ? 6= nullAddress
expirationCallbackAddr 0 = expirationCallbackAddr ?
timerKind 0 = timerKind ?
(let expirationTimeTicks == expirationTimeUs? div TickTimerPeriodUs •
wheelSpokeIndex 0 =
(timerWheel .currentWheelSpokeIndex + expirationTimeTicks) mod numTimerW
timerWheelRevolutions 0 = expirationTimeTicks div numTimerWheelSpokes ∧
timerWheelRevolutionsLeft 0 = timerWheelRevolutions 0 ∧
timerWheel 0 .wheelSpokesHashTable(wheelSpokeIndex 0 ) =
timerWheel .wheelSpokesHashTable(wheelSpokeIndex 0 ) ∪ { timerId ? })
StopTimer
CreatedTimerMutableOperation
expirationCallbackAddr 0 = nullAddress
timerWheel 0 .wheelSpokesHashTable(wheelSpokeIndex ) =
timerWheel .wheelSpokesHashTable(wheelSpokeIndex ) \ { timerId ? }
Chapter 4
invalidPartitionId : PartitionIdType
ValidPartitionIdType ==
PartitionIdType \ {invalidPartitionId }
PartitionQueueType == iseq ValidPartitionIdType
PartitionStateType ::= partitionNotCreated |
partitionRunnable | partitionRunning |
partitionSuspended
PartitionSchedulerStateType ::=
partitionSchedulerStopped | partitionSchedulerRunning
AddressRangeType == MemoryAddressType × MemoryAddressType
32
Design of the HiRTOS Real-Time Operating System 33
HiRtosSeparationKernel
separationKernelCpuInstances :
ValidCpuIdType 7 7 SeparationKernelCpuInstanceType
zAllCreatedPartitionInstances : F PartitionType
#separationKernelCpuInstances ≥ 1
∀ i : dom separationKernelCpuInstances •
(separationKernelCpuInstances(i )).cpuId = i
zAllCreatedPartitionInstances =
{ i : ValidCpuIdType •
S
zAddressRange(r ) } = ∅
SeparationKernelCpuInstanceType
cpuId : ValidCpuIdType
interruptStack : AddressRangeType
partitionSchedulerState : PartitionSchedulerStateType
currentPartitionId : PartitionIdType
timerTicksSinceBoot : N
runnablePartitionsQueue : PartitionQueueType
partitions : ValidPartitionIdType 7 7 PartitionType
zCurrentCpuContext : CpuRegistersType
zCurrentHypervisorLevelMpuRegions : F1 AddressRangeType
zCurrentSupervisorLevelMpuRegions : F AddressRangeType
zCurrentSupervisorLevelInterruptVectorTableAddr : MemoryAddressType
zCurrentSupervisorLevelInterruptsEnabled : F ValidInterruptIdType
zCurrentHighestInterruptPriorityDisabled : InterruptPriorityType
zAddressRange(interruptStack ) 6= ∅
currentPartitionId 6= invalidPartitionId ⇒
currentPartitionId ∈ dom partitions ∧
zCurrentHypervisorLevelMpuRegions =
(partitions(currentPartitionId )).savedHypervisorLevelMpuRegions ∧
zCurrentSupervisorLevelInterruptVectorTableAddr =
(partitions(currentPartitionId )).savedInterruptVectorTableAddr
∀ p : ran partitions •
{ i : p.savedHypervisorLevelMpuRegions • zAddressRange(i ) } = ∅
T
∀ i : zCurrentSupervisorLevelMpuRegions •
∃1 j : zCurrentHypervisorLevelMpuRegions •
zAddressRange(i ) ⊆ zAddressRange(j )
Design of the HiRTOS Real-Time Operating System 35
PartitionType
id : PartitionIdType
failoverPartitionId : PartitionIdType
state : PartitionStateType
timeSliceLeftUs : N
savedCpuContext : CpuRegistersType
savedHypervisorLevelMpuRegions : F1 AddressRangeType
savedSupervisorLevelMpuRegions : F AddressRangeType
savedInterruptVectorTableAddr : MemoryAddressType
savedInterruptsEnabled : F InterruptIdType
savedHighestInterruptPriorityDisabled : InterruptPriorityType
state 6= partitionNotCreated ⇒
id 6= invalidPartitionId
failoverPartitionId 6= invalidPartitionId ⇒
failoverPartitionId 6= id
{ i : savedHypervisorLevelMpuRegions • zAddressRange(i ) } = ∅
T
∅∈
/ { i : savedHypervisorLevelMpuRegions • zAddressRange(i ) }
∀ i : savedSupervisorLevelMpuRegions •
∃1 j : savedHypervisorLevelMpuRegions •
zAddressRange(i ) ⊆ zAddressRange(j )
HiRtosSeparationKernelInitialize
HiRtosSeparationKernel 0
SeparationKernelCpuInstanceInitialize
cpuId ? : CpuIdType
cpuId 0 = cpuId ?
θSeparationKernelCpuInstanceType 0 = separationKernelCpuInstances 0 (cpuId ?)
SeparationKernelCpuInstanceInitialize
SeparationKernelCpuInstanceElaboration
36 Design of the HiRTOS Multi-core Real-Time Operating System
SeparationKernelCpuInstanceElaboration
SeparationKernelCpuInstanceType 0
zAddressRange(interruptStack 0 ) 6= ∅
partitionSchedulerState 0 = partitionSchedulerStopped
currentPartitionId 0 = invalidPartitionId
timerTicksSinceBoot 0 = 0
runnablePartitionsQueue 0 = hi
partitions 0 = ∅
CreatePartition
∆SeparationKernelCpuInstanceType
InitializeNewPartition
partitionId ! ∈
/ dom partitions
partitionId ! ∈ dom partitions 0
partitions 0 (partitionId !) = partitions 0 (partitionId !)
InitializeNewPartition
PartitionType 0
partitionId ! : ValidPartitionIdType
id 0 = partitionId !
failoverPartitionId 0 = invalidPartitionId
state 0 = partitionRunnable
savedHypervisorLevelMpuRegions 0 6= ∅
savedSupervisorLevelMpuRegions 0 = ∅
savedInterruptsEnabled 0 = ∅
Bibliography
38
Design of the HiRTOS Real-Time Operating System 39
[11] John Rushby, “Design and Verification of Secure Systems”, ACM SIGOPS Op-
erating Systems Review, 1981
https://www.csl.sri.com/users/rushby/papers/sosp81.pdf
[12] FreeRTOS
https://www.freertos.org/