<?xml version="1.0" encoding="UTF-8"?>
<TEI xml:space="preserve" xmlns="http://www.tei-c.org/ns/1.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.tei-c.org/ns/1.0 https://raw.githubusercontent.com/kermitt2/grobid/master/grobid-home/schemas/xsd/Grobid.xsd"
 xmlns:xlink="http://www.w3.org/1999/xlink">
	<teiHeader xml:lang="en">
		<fileDesc>
			<titleStmt>
				<title level="a" type="main">Model Stack for the Pervasive Verification of a Microkernel-based Operating System</title>
			</titleStmt>
			<publicationStmt>
				<publisher/>
				<availability status="unknown"><licence/></availability>
			</publicationStmt>
			<sourceDesc>
				<biblStruct>
					<analytic>
						<author>
							<persName><forename type="first">Matthias</forename><surname>Daum</surname></persName>
							<affiliation key="aff0">
								<orgName type="department">Computer Science Dept</orgName>
								<orgName type="institution">Saarland University</orgName>
								<address>
									<postCode>66123</postCode>
									<settlement>Saarbrücken</settlement>
									<country key="DE">Germany</country>
								</address>
							</affiliation>
						</author>
						<author>
							<persName><forename type="first">Jan</forename><surname>Dörrenbächer</surname></persName>
							<affiliation key="aff0">
								<orgName type="department">Computer Science Dept</orgName>
								<orgName type="institution">Saarland University</orgName>
								<address>
									<postCode>66123</postCode>
									<settlement>Saarbrücken</settlement>
									<country key="DE">Germany</country>
								</address>
							</affiliation>
						</author>
						<author role="corresp">
							<persName><forename type="first">Sebastian</forename><surname>Bogan</surname></persName>
							<email>sebastian@wjpserver.cs.uni-sb.de</email>
							<affiliation key="aff0">
								<orgName type="department">Computer Science Dept</orgName>
								<orgName type="institution">Saarland University</orgName>
								<address>
									<postCode>66123</postCode>
									<settlement>Saarbrücken</settlement>
									<country key="DE">Germany</country>
								</address>
							</affiliation>
						</author>
						<title level="a" type="main">Model Stack for the Pervasive Verification of a Microkernel-based Operating System</title>
					</analytic>
					<monogr>
						<imprint>
							<date/>
						</imprint>
					</monogr>
					<idno type="MD5">D58DB9DFE15CE1195B86269F67D44914</idno>
				</biblStruct>
			</sourceDesc>
		</fileDesc>
		<encodingDesc>
			<appInfo>
				<application version="0.7.2" ident="GROBID" when="2023-03-24T19:49+0000">
					<desc>GROBID - A machine learning software for extracting information from scholarly documents</desc>
					<ref target="https://github.com/kermitt2/grobid"/>
				</application>
			</appInfo>
		</encodingDesc>
		<profileDesc>
			<abstract>
<div xmlns="http://www.tei-c.org/ns/1.0"><p>Operating-system verification gains increasing research interest. The complexity of such systems is, however, challenging and many endeavors are limited in some respect: Some projects focus on a particular aspect like memory safety, not pursuing functional correctness. Others restrict their verification efforts to a single layer of software, assuming correctness of those below. Only few projects aim at pervasive formal verification of a computer system over several software layers. In our paper, we present an approach to the formal specification of a microkernel-based operating system at several layers and glance on our verification experience with this model stack. From our experience, we conclude that pervasiveness entails more than just cumulative verification efforts on several layers. In fact, it is a challenging task to integrate models and proofs into a uniform, coherent theory.</p></div>
			</abstract>
		</profileDesc>
	</teiHeader>
	<text xml:lang="en">
		<body>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="1">Introduction</head><p>Software-verification tools have greatly improved in recent years. As a consequence, the verification of low-level software gains increasing research interest as a touch-stone for the industrial applicability of software verification in general. While many aspects of operating-system verification are currently studied, they are not integrated into a uniform, coherent theory. In our paper, we concentrate on the integration of several operating-system models in order to form a pervasive verification stack. We point out the integration problems and describe the specific design decisions that we made in order to support integration.</p><p>A characteristic problem of operating-system software is that hardware components become visible and the program functionality cannot be expressed in the pure semantics of a high-level language like C. Usually, this functionality is implemented in assembly and encapsulated in a small number of C functions, or primitives. Thus, only a small part of low-level code is indeed implemented in assembly while larger code portions are written in C and just use these primitives. From a model-theoretic point of view, such primitives extend the original C semantics. Another important problem related to operating systems regards the atomicity of operations in a concurrent setting. The processor might be interrupted in its current computation after each assembly instruction but a single C statement is usually compiled into several instructions. Consequently, we need an assembly semantics, a C semantics and a simulation theorem between both semantics. Leinenbach and Petrova <ref type="bibr" target="#b0">[1]</ref> provide exactly that: a proven correct compiler that translates programs from the perfectly type-safe C variant C0 into the assembly language of our risc processor. An important feature of C0 is the inline-assembly statement, which permits the language extensions via primitives. Using this mechanism, we have implemented our operating system in C0. The correct C0 compiler is an elementary prerequisite for our model stack.</p><p>Outline. In Sect. 2, we explain the fundamentals of our operating system. This section comprises a sketch of the correct compiler, a survey of the features of our microkernel, and an outline of the system's implementation design. With these prerequisites in place, we give an overview of our model stack in Sect. <ref type="bibr" target="#b2">3</ref>. Certainly, we cannot descend into all details of the stack in this paper. <ref type="foot" target="#foot_0">1</ref> Hence, we confine ourselves to aspects of encapsulation and state partitioning. In Sect. 4, we describe our formal specification of the generic interface between the user processes and the kernel. Moreover, we sketch our formal model for assembly and C0 processes. This process abstraction is an elementary prerequisite for the model of communicating user processes as well as for the top-level specification of the operating system. We illustrate in Sect. 5, why we use the process abstraction already in the Vamos specification and how we have constructed the latter model in order to support the abstraction towards Coup and the top-level specification. We conclude in Sect. 6.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2">Background 2.1 A Correct Compiler for an Extensible Language</head><p>In this section, we summarize work of Leinenbach and Petrova <ref type="bibr" target="#b0">[1,</ref><ref type="bibr" target="#b1">2]</ref>. They provide a formally verified compiler that translates programs from the perfectly typesafe C variant C0 into the assembly language of a risc processor. Restrictions of C0 in comparison to C are that expressions must be side-effect-free, all type conversions have to be made explicitly, and there is no pointer arithmetic. In spite of that, C0 still features dynamic memory allocation and inlined assembly.</p><p>The inline-assembly statement is an important feature for language extensions. Though the effect of this statement cannot be expressed in the formal C0 semantics, the compiler literally embeds the given assembly code into the compilation. Using this hook, we can implement C0 functions that use inline assembly in order to extend C0 by a functionality that cannot be expressed by other C0 statements.</p><p>For C0 and for the assembly language, two small-step transition semantics have been formalized in Isabelle/HOL. Leinenbach has formally proven compiler correctness by a stepwise simulation between both semantics. Below, we describe the semantics in detail. We often deal with structured values, which we define by enumerating the components in prose, e. g., "a value x consisting of two components this and that". We refer to a single component with a dot, e. g., x.this refers to component this of value In the following sections, we assume an evaluation function get-val for the lookup, and an update function set-val for the manipulation of a certain variable in the memory. We refer to the value of expression e in state s C0 by get-val (s C0 , e). If we update the left-value l in state s C0 with some expression u, we denote the resulting configuration by set-val (s C0 , l, u).</p><p>The transition relation δ seq C0 of this semantics is a partial function.</p><p>The Target Assembly Language. The assembly semantics was developed for the risc processor Vamp <ref type="bibr" target="#b2">[3]</ref>. The assembly semantics abstracts from the paging mechanism of the processor and employs a linear memory model. An assembly state s asm consists of the following components:</p><p>the normal and the delayed program counters, s asm .pc and s asm .dpc, respectively, implementing the delayed branch mechanism. the general-purpose register file s asm .gpr ∈ {0, . . . , 31} → {0, 1} 32 .</p><p>the memory size s asm .V measured in pages of 4096 bytes. It defines the set of available memory addresses: VA(s asm ) = {a | a &lt; s asm .V • 4096} the byte-addressable linear memory s asm .vm ∈ VA(s asm ) → {0, 1} 8   We denote the state space of the assembly semantics by S asm . Assembly computations are modeled by the partial function δ seq asm ∈ S asm S asm . Note that the effects of exceptions like illegal page faults cannot be fully determined from the assembly-machine state. In that case, δ seq asm gets stuck. But with sufficient resources, a compiled C0 program does not generate exceptions during normal execution. Moreover, the memory size s asm .V can neither be read nor changed by the assembly machine itself but depends on the operating-system kernel. We extend the semantics accordingly in Sect. 4.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.2">Fundamentals of our Microkernel</head><p>In this section, we sketch the features of Vamos and explain the fundamental access-control mechanism that establishes the process roles "privileged process" and "device driver".</p><p>Our microkernel Vamos performs the following tasks: (a) enforcement of a minimal access control, (b) process management, (c) memory management, (d) priority-based round-robin scheduling, (e) support for user-mode device drivers, and (f) inter-process communication (IPC). Processes can control these tasks via the kernel's application binary interface (ABI). Table <ref type="table" target="#tab_1">1</ref> lists the kernel calls that constitute the ABI.</p><p>Most kernel calls are reserved for so-called privileged processes. Thus, only a privileged process can bring up new processes or kill existing ones, alter the memory consumption of processes, change their scheduling parameters, or control the registration of device drivers. Any process, however, might use the IPC mechanism. Thus, the privileging serves as a minimal access control. We presume that the privileged processes constitute the user-mode parts of the operating system and implement a more sophisticated access-control mechanism. Non-privileged processes may then communicate with the privileged processes in order to request kernel services on their behalf. When Vamos boots, it launches one single process, the init process. This process is privileged and has to set up the required servers of the operating system, start and register the device drivers, and possibly run initial applications.</p><p>A device driver is a user process, which is designated for the communication with certain devices. Only if a process is registered as a driver for a particular device, it may place read or write requests from or to that device, respectively. Moreover, the device driver is notified of interrupts from that device.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.3">Implementation Design</head><p>Fig. <ref type="figure">1</ref> depicts the implementation structure of Vamos. The lowest software layer is called communicating virtual machines (CVM). This layer encapsulates all hardware-specific low-level functionality, which is possibly using inline assembly. CVM has two major tasks: memory virtualization and switching between different threads of execution. Hence, CVM includes a page-fault handler with a simple memory swapping facility <ref type="bibr" target="#b3">[4]</ref>. Moreover, it exports an interface of so-called primitives for the access and manipulation of user machines to the hardware-independent part. We have thereby established a solid framework for microkernel construction.</p><p>Using this framework, we have implemented our microkernel Vamos in C0 without extra portions of inline assembly. On every kernel entry, CVM preserves the old context, establishes a suitable C0 environment and calls the function kdispatch of Vamos. For the manipulation of the user memory or registers, Vamos may call the primitives of CVM. The return value of kdispatch determines, which user machine resumes when the kernel execution finishes. While CVM and Vamos run in the privileged system mode of the processor, user machines run in the unprivileged user mode. In the figure, we labelled one user machine "SOS" for simple operating system and the others "App" as abbreviation for application. The SOS constitutes the highest layer of our operating system. It features an advanced rights management with different users, implements a sophisticated access control to kernel services like process creation and provides further services like file-system and network access. All user machines interact with the kernel via kernel calls. The special instruction trap causes an exception, which is handled in Vamos. Vamos can examine and alter the state of the user machine using CVM primitives, thus identifying the user machine's specific request and storing the kernel's corresponding response.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3">Model-Stack Overview</head><p>In analogy to the software stack, we have developed a model stack. For each software layer, this stack contains a specification that fully describes the observable behavior of this layer. The specification describes the full functionality of the software layer, on the one hand, and forms the foundation for the simulation proofs for the more abstract layers, on the other hand. We build the model stack as a means of verifying statements about the real system on a convenient, abstract layer. Such statements include safety and liveness properties.</p><p>Fig. <ref type="figure" target="#fig_0">2</ref> shows our model stack. The lowest model describes CVM. This model comprises a kernel machine, given in the C0 semantics, and a number of user machines with virtual memory, given in the assembly semantics. The kernel runs in system mode with disabled interrupts. The user machines, in contrast, may be interrupted after each assembly instruction, thus we model them on assembly level. We will not descend into the details of this model in the present publication because it has been described earlier <ref type="bibr" target="#b4">[5]</ref>.</p><p>We can instantiate the kernel of CVM with the Vamos implementation, i. e., the C0 program that implements (the hardware-independent part of) our microkernel is executed as CVM's kernel machine. The Vamos model specifies the behaviour of the resulting system. In short, this model establishes assembly processes that communicate with the kernel via a well-defined interface, the kernel ABI. A code-correctness proof for the Vamos implementation establishes the simulation theorem between the instantiated CVM model and the Vamos specification.</p><p>While the Vamos processes use the assembly semantics, the SOS and the applications are written in C0. The kernel ABI is encapsulated in a few library functions. Except for the library functions, the verification of these programs should certainly employ the more abstract C0 semantics. For this purpose, we designed the model communicating user processes (Coup). This model simulates Vamos but it abstracts from the scheduler and establishes C0 processes.</p><p>We need to abstract from the particular Vamos scheduler because of the different granularity of the program semantics: The execution of a process might be suspended and resumed on every assembly instruction but a C0 statement usually contains several assembly instructions. The simulation proof has three parts: <ref type="bibr" target="#b0">(1)</ref> The execution traces of Coup should contain all traces of Vamos.</p><p>(2) There is a confluent reordering of any execution trace such that there is no scheduling event during a single C0 statement. (3) The kernel library is correctly implemented.</p><p>We can instantiate one of the C0 processes with the implementation of SOS. The SOS model specifies the behaviour of the resulting system. The simulation between both models can be shown by the functional correctness of the SOS implementation.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4">Process Abstraction</head><p>In this section, we formalize the interface between the processes and the kernel. Both kernel models, the Vamos specification and the Coup model, use this process abstraction in order to access and manipulate processes. Our abstraction is based on the observation that Vamos interacts with processes only via a well-defined interface, the kernel ABI. Hence, we can encapsulate processes in a self-contained input-output automaton, thereby hiding the internal state and just exposing the generic interface.</p><p>We define a process as input-output automaton described by a tuple (S proc , Σ proc , Ω proc , ω proc , vm-size proc , init proc , δ proc )</p><p>with state space S proc , input alphabet Σ proc , output alphabet Ω proc , output functions ω proc and vm-size proc , initialization function init proc , and transition function δ proc . While the state space S proc depends on the individual process abstraction, the interface between the kernel and the processes is naturally shared by all process abstractions. This interface is entirely defined by Σ proc and Ω proc .</p><p>The output alphabet Ω proc enumerates all possible kernel calls. Additionally, we have to treat a few error cases. As the kernel calls are internally identified by a number, a process might specify an invalid number. This condition is represented by the special output value undefined trap. Moreover, a process might generate exceptions like an arithmetic overflow or an illegal page fault. These exceptions are collectively represented as value runtime error. Finally, the output ε denotes the intention to perform a local computation.</p><p>The input alphabet Σ proc reflects all kernel-initiated changes of a process. These comprise all possible responses to kernel calls, on the one hand, and the demand to change the amount of virtual memory, on the other hand. While the former are the synchronous reaction to a kernel call, the latter may be issued asynchronously at any stage of a process. In order to perform a local transition, we pass the input ε to the transition function δ proc .</p><p>In addition to the usual functions δ proc ∈ Σ proc × S proc → S proc for transitions and ω proc ∈ S proc → Ω proc for the output, we use two more functions in our process abstraction. In order to compute the overall memory consumption of the process system, Vamos needs to know the amount of virtual memory that is currently occupied by every process. The function vm-size proc ∈ S proc → N provides the necessary information. When a new process is created, Vamos has to translate a representation of a given binary executable file into the corresponding, initial process state. We specify this translation in the function init proc ∈ N → S proc .</p><p>For the kernel specification, the generic abstraction of processes as selfcontained input-output automata is rather a matter of taste than necessity. However, this generic process abstraction is a cornerstone of the Coup model. Moreover, it is crucial for the simulation theorem between Vamos and Coup because both models mainly differ in the process abstraction. Hence, it proved to be beneficial that many definitions of the specification are parametrized over the process abstraction and can thus be reused in Coup as well. Finally, the introduction of this parameter on the whole Coup model is just a logical consequence because it paves the way for the integration of other language semantics.</p><p>In the following, we refine the generic abstraction with specific process models for assembly and C0.</p><p>Assembly Processes. We reuse the state space S asm of the assembly semantics for our assembly processes. Based on this state space, we now define the output functions ω asm and vm-size asm , the transition function δ asm , and the initialization function init asm . The function vm-size asm simply returns the value of the component V of the current state: vm-size asm (s asm ) = s asm .V . However, the definitions for other functions are too complex to fully present them here. We constrain ourselves to an exemplary excerpt.</p><p>Fig. <ref type="figure">3</ref> depicts the formal definition of the output function ω asm and the transition function δ asm for the call process clone. We assume that s asm is the state of an assembly process. The predicate trap holds iff the current instruction is a trap, and the function simm extracts the sign-extended immediate constant from the current instruction. If there is a trap with immediate constant 2, the output function will return the pair of value process clone and the content of register 11. Let us now assume that the kernel recognizes this output from the current process but the process is not privileged. In this case, the kernel signals this error condition by passing value err unprivileged via the transition function to the current process. Then, the transition function updates the register 22 with the corresponding error code and increases the program counters. (S C0 , Σ proc , Ω proc , ω C0 , vm-size C0 , init C0 , δ C0 ) Any state s C0 ∈ S C0 comprises the static program environment as well as the dynamic program state of the C0 machine as described in Sect. 2.1. We store the program environment because processes might dynamically be created and killed, hence the program might change. The output functions ω C0 and vm-size C0 , the transition function δ C0 , and the initialization function init C0 are defined in analogy to their assembly-process counterparts.</p><p>For example, the formal definition of the output function and the transition function for the call process clone is given in Fig. <ref type="figure">4</ref>. We assume that s C0 is the current state of a C0 process. The component s C0 .prog denotes the remaining program of the process. We consider the first statement of the program. If this statement is a call to the function vc process clone, we define the output of ω C0 as the pair of process clone and the value of the first argument to the function call. Let us now assume that the kernel recognizes this output from the current process, clones the given process, and computes the value hn new as new identifier for the clone. It would then pass this value via the transition function to the current process, thus signalling the success of the clone operation. In this case, the transition function updates the memory s C0 .mem at the address designated by the left-value e with value hn new and removes the function call from the remaining program.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5">Formal Kernel Models</head><p>In the previous section, we described our process model. Now, we embed the processes into the two concurrent kernel models, the Vamos specification, and the Coup model. The former specifies the exact behaviour of our microkernel with a particular scheduler. This model is used for code verification. The latter abstracts the scheduler and focusses on the interaction of the processes with the sC0.prog = "e = vc process clone(e0); r" =⇒ ωC0(sC0) = (process clone, get-val (sC0.mem, e0)) sC0.prog = "e = vc process clone(e0); r" =⇒ δC0((succ new process, hnnew), sC0) = sC0 » mem := set-val (sC0.mem, e, hnnew) prog := r -Fig. <ref type="figure">4</ref>. Formal definition of the output function and the transition function of C0 processes for the call process clone microkernel.We need this more abstract model in order to describe the reordering of interleaved sequences and to introduce C0 processes.</p><p>Both models are Moore machines. We describe the kernel specification with the tuple (S v , s 0 v , Σ, Ω, ω v , δ v ) and the Coup model with (S vc , s 0 vc , Σ, Ω, ω vc , δ vc ). The state spaces S v , S vc contain the initial states s 0 v and s 0 vc , respectively. For device communication, we use the input alphabet Σ and the output alphabet Ω. The functions ω v and ω vc determine the output in a current state. Finally, δ v and δ vc describe the transitions of the models. The notable difference between these machines regards the determinism: While the Vamos specification is fully deterministic, Coup features a non-determinism in its scheduling decisions. Consequently, the transition relation δ v is functional while δ vc is not.</p><p>Below, we introduce the different components of the models side by side.</p><p>Device Communication. Our kernel uses memory-mapped I/O for device communication. Hence, the output alphabet Ω comprises read and write accesses to device addresses. The input alphabet Σ consists of interrupt lines and optionally incoming data. Hillebrand et al. <ref type="bibr" target="#b5">[6]</ref> have described our device interface in detail.</p><p>State Spaces. A state s v ∈ S v comprises the following components:</p><p>-The partial function s v .procs maps the process identifiers (PIDs) of the currently active processes to their assembly states s asm ∈ S asm . For inactive processes, this function is undefined. -Priorities are assigned to each PID of the active processes with the partial function s v .priodb. -All other scheduling information is kept in the component s v .schedds.</p><p>-The partial function s v .rightsdb maps PIDs to a data structure for the management of IPC rights and the set of privileged processes. -Finally, the component s v .devds contains data for device communication.</p><p>At first sight, the separation of priorities from the remaining scheduling data might surprise, here. The reason for this unintuitive partitioning is that Coup abstracts from the particular scheduling algorithm but the priorities remain visible. We modularized the states and the corresponding transition functions in order to share the definition of similar parts between the Vamos specification, Coup, and the SOS model.</p><p>A central part of the Vamos specification are the scheduling data structures. The component s v .schedds is divided into sub components. The current time time ∈ N is a counter for clock ticks. Process-specific scheduling information for active processes is collected in the partial function procdb that maps PIDs to a record of (a) the time slice tsl , (b) the amount of consumed time ctsl , and (c) the absolute timeout to. If a process is found to be computing when a timer interrupt raises, the component ctsl is increased until the process has finally run for tsl ticks. In this case, another process is scheduled. If a process calls the kernel for IPC and no partner is ready for communication, the absolute timeout to is computed from the current time and the relative timeout that has been specified with the call.</p><p>Moreover, the scheduler maintains different queues for scheduling. They are represented as finite sequences in the Vamos specification. Namely, there is a ready queue ready(prio) of schedulable processes for each priority prio ∈ {0, 1, 2}. The processes that cannot currently be scheduled (because they are waiting for an IPC partner) are held in a queue named wait.</p><p>In Vamos, the current process is the first process in the highest, non-empty ready queue. If all ready queues are empty, the current process is undefined. Formally, we define the function cup as: cup(s v .schedds) = p ⇐⇒ ∃i : s v .schedds.ready(i) = (p, . . . ) ∧ ∀ j &gt; i : s v .schedds.ready(j) = ()</p><p>The corresponding Coup state s vc inherits most components of s v . Only two components change: The process abstraction becomes a model parameter, i. e., component s vc .procs of a Coup state s vc is a partial function from PIDs to a generic state space S proc for processes. Moreover, the scheduling data structures are replaced by a current-process indicator. We retain the current process in the state in order to compute the output from the current state. The output function ω vc signals the demand for device communication. In order to determine this demand, we need to employ the output function ω proc of the current process. Consequently, we fix this process beforehand instead of including transitions for all ready processes in the transition relation.</p><p>Transitions. A transition δ v (σ, s v ) of the Vamos specification under the device input σ ∈ Σ has up to three phases:</p><p>1. If the current process cp = cup(s v .schedds) is defined, we consult its output ω proc (s v .procs(cp)) and compute the response according to the current Vamos state. For instance, if a process calls process clone, we check for sufficient privileges and resources and choose the corresponding response σ ∈ Σ proc for success or failure. With this response, we advance the current process: s v [procs(cp) := δ proc (σ, s v .procs(cp))]. 2. If the timer-interrupt line is raised, the scheduler increases the clock-tick counter s v .schedds.time and the consumed time s v .schedds.procdb(cp).ctsl of the current process. Moreover, the scheduler wakes up all processes p with elapsed timeouts. 3. Finally, Vamos delivers interrupts to waiting drivers and saves the remaining interrupts for later delivery in s v .devds.</p><p>The Coup transitions behave very similarly. However, a transition s vc σ ←→ s vc ∈ δ vc , obtains cp directly from s vc .cup. Moreover, the only visible effect of the second phase is the wake-up of certain waiting processes. This effect is simulated non-deterministically and independently from the timer interrupt.</p><p>Reusability. As mentioned earlier, we worked hard to reuse as much definitions as possible in the different layers of abstraction. For example, in contrast to the Coup model, the kernel specification does not actually rely on the encapsulation of processes as self-contained input-output automata. Since Vamos only considers assembly processes, it would be easier to directly manipulate the state of these processes. However, in order to literally reuse update functions and definitions, we invested the extra work and already introduced the input-output automata at this level of our model stack.</p><p>Consider the formal definition of the function v clone updt procs in Fig. <ref type="figure">5</ref>. This function describes the necessary updates in case of a successful call to process clone. Without going into detail, depending on the relation between the calling process (p subj ) and the process that was cloned (p obj ), this function updates the state of the calling process, the state of the cloned process, and the state of the new process. The important thing about this definition is that the updates are presented in a process-abstraction independent manner. Rather than updating particular registers, as it would suffice for assembly processes, we feed the generic transition function δ proc with generic input, e.g. (succ new process, hn new ). Now, this generic interface between kernel and processes allows us to use v clone updt procs in both models, i.e. Vamos and Coup. Proceeding in a similar way with all kernel calls keeps the models clear and maintainable. Furthermore, tedious equivalence proofs between Vamos and Coup are avoided.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6">Conclusion</head><p>Related Work. With the CLI stack <ref type="bibr" target="#b6">[7]</ref>, a pioneering approach started out for pervasive verification of a complete system with rigorous formalizations of specifications and proofs. Most notably, the simple kernel KIT <ref type="bibr" target="#b7">[8]</ref> was developed v clone updt procs(procs, p subj , p obj , pnew, hnnew) = λx. if x = p subj then δproc((succ new process, hnnew), procs(p subj )) else if x = pnew ∧ p subj = p obj then δproc((succ new process, 0), procs(p subj )) else if x = pnew then procs(p obj ) else procs(x) Fig. <ref type="figure">5</ref>. Formal definition of the function v clone updt procs that computes the component procs after a call to process clone and its machine code implementation was proven to be correct. However, this kernel is fairly simple compared to modern microkernels. Many recent projects undertake verification efforts on modern microkernels. Among them are L4.verified <ref type="bibr" target="#b8">[9]</ref>, VFiasco <ref type="bibr" target="#b9">[10]</ref>, Eros <ref type="bibr" target="#b10">[11]</ref>, and the Flint project <ref type="bibr" target="#b11">[12]</ref>. Though these projects may have achieved some advances, they all discard pervasiveness but focus on the verification of a single software layer. The Flint project has developed a verification framework for an assembly language and has formally proven the correctness for context-switching code. The other three projects have established semantics for C variants and have verified different properties on source code level. As far as we can see, inlined assembly portions are just postulated to be correct and solely described by their semantical effects. Moreover, these projects rely on compiler correctness.</p><p>Traditionally, concurrent systems are described by the Calculus of Communicating Systems <ref type="bibr" target="#b12">[13]</ref> or as Communicating Sequential Processes (CSP) <ref type="bibr" target="#b13">[14]</ref>. Both approaches, however, argue on a very abstract level and are mainly used to specify system requirements at an early stage in the system design. Basin, Olderog and Sevinç <ref type="bibr" target="#b14">[15]</ref>, for instance, describe the combination of CSP and Object-Z in order to specify and analyze security automata. Unfortunately, a link to the actual code is missing.</p><p>Discussion. We presented an approach to a pervasive, formal specification of a microkernel-based operating system. The formal models of our microkernel Vamos and the SOS occupy almost 400 kB and comprise about 8,000 lines of specification. The formalization took us about 48 person months. The different specification layers resemble essentially the implementation layers.</p><p>A recurring problem was the semantic gap between the high-level implementation language C0 and certain hardware details that were manipulated by the considered programs. Such details concerned hidden hardware components like devices, on the one hand, and the granularity of atomic operations on the hardware level, on the other hand. Both problems arose simultaneously when we argued about C0 processes: In pure C0, we cannot express kernel calls. Hence, we extended the original C0 semantics by a library of functions that implement the kernel calls using inlined assembly. Moreover, user machines may be interrupted after the execution of any assembly instruction. Consequently, we had to justify that we may confluently shift all rescheduling events to statement boundaries before we could argue about C0 processes. In non-pervasive approaches, these challenges are likely to be skipped.</p><p>When we began to specify the different layers of our operating system, we started with independent models. As expected, many parts of the formal models overlapped because we specified the same operating system at several layers of abstraction. After a short period of evaluation for each abstraction layer, we coupled the models as tight as possible in order to minimize the proof efforts for the simulation theorems between adjacent models.</p><p>This ambivalent approach was very successful. In the very beginning, the specifications change very often, such that maintaining dependencies between them would be very tedious and distracting from the individual problems. As soon as the models stabilized, however, there was a common ground for a tight meshing. The synergies between the layers could easily be identified and utilized.</p><p>The key to shared definitions between the Vamos specification and the Coup model was twofold: On the one hand, we unitized the state space in a way that permits easy abstraction between the different abstraction layers. On the other hand, we established the process abstraction already at the Vamos specification. Both arrangements together enabled a very tight mesh, which could even be reused in the SOS specification.</p><p>Of course, this tight mesh of the models has drawbacks: The specification of an abstract layer depends massively on the underlying layers, which impedes the understanding of this model. Moreover, even the lower layers became more complicated, so for instance, when the process abstraction was already introduced in the Vamos specification. Finally, several layers were affected whenever the abstraction at one level turned out to be wrong.</p><p>From our experience, however, we conclude that the advantages outweigh the drawbacks. We saved valuable time by reusing the definitions, which we otherwise had spent in distracting equivalence proofs. For instance, we succeeded with the step-wise simulation proof between the Vamos specification and the Coup model within two months. We have proven this simulation for most kernel calls within days. Most of the time, however, we spend with the verification of IPC. This effort was caused by a considerably simpler modelling of IPC in Coup, which became possible after the scheduler was abstracted. In this particular case, the simpler modelling was desirable and hence, we invested the additional time for the proof. Independent models, however, would possibly have caused such an overhead for every kernel call.</p><p>In the code-correctness proof for Vamos, there is only a minimal overhead (hours) induced by the use of the process abstraction in the specification. All in all, we invested about 18 person months to show the correctness of the IPC send call. Including all auxiliary functions, the implementation of this call accounts for nearly half the code size and comprises the most complex parts. Again 18 person month had been spent on the functional verification of the file system and the hard disk driver code in the SOS. This code covers 20% of the SOS implementation.</p><p>Summary. The fundamental difference of our "pervasive" approach compared to "incremental" approaches that focus on a single layer at a time regards the design of specifications: At first, models are usually adapted to the actual verification goal. If it is the only goal, to show that the formal specification precisely describes the implementation, the specification tends to move closely towards the implementation. If a model is used as fundament of an underlying component without a proof, there is a likelihood that the model over-abstracts the actual implementation. At second, regarding one single layer at a time necessarily leads to self-contained, independent models. When combining those different layers later on, there is a tremendous proof effort necessary to establish simulation theorems between the adjacent layers. Our approach prevents this effort by the specification design.</p></div><figure xmlns="http://www.tei-c.org/ns/1.0" xml:id="fig_0"><head>Fig. 2 .</head><label>2</label><figDesc>Fig. 1. Implementation scheme</figDesc></figure>
<figure xmlns="http://www.tei-c.org/ns/1.0" xml:id="fig_1"><head>4 gpr 5 Fig. 3 .</head><label>453</label><figDesc>Fig. 3. Formal definition of the output function and the transition function of assembly processes for the call process clone</figDesc></figure>
<figure xmlns="http://www.tei-c.org/ns/1.0" type="table" xml:id="tab_0"><head></head><label></label><figDesc>x. An update of this component is denoted by x [this := q]. C0 Semantics. For lack of space, we can only glance at the C0 semantics. C0 programs are statically represented by the program environment Γ , which comprises a symbol table of global variables, a type-name environment, and a function table. The dynamically changing state s C0 of a C0 program in execution is composed of the remaining program s C0 .prog, and the current state of the program variables s C0 .mem.</figDesc><table /></figure>
<figure xmlns="http://www.tei-c.org/ns/1.0" type="table" xml:id="tab_1"><head>Table 1 .</head><label>1</label><figDesc>Application binary interface of the Vamos kernel</figDesc><table><row><cell>Kernel Call</cell><cell>Description</cell></row><row><cell>Access Control</cell><cell></cell></row><row><cell>set privileged p</cell><cell cols="2">add a process to the set of privileged processes</cell></row><row><cell>Process Management</cell><cell></cell></row><row><cell>process create p</cell><cell cols="2">create a new process from a memory image</cell></row><row><cell>process clone p</cell><cell cols="2">copy an already existing process</cell></row><row><cell>process kill p</cell><cell>kill a process</cell></row><row><cell>Memory Management</cell><cell></cell></row><row><cell>memory add p</cell><cell cols="2">increase the amount of virtual memory for a process</cell></row><row><cell>memory free p</cell><cell cols="2">decrease the amount of virtual memory for a process</cell></row><row><cell>Scheduling Mechanism</cell><cell></cell></row><row><cell>chg sched params p</cell><cell cols="2">change scheduling parameters</cell></row><row><cell>Device Driver Support</cell><cell></cell></row><row><cell>change driver p</cell><cell cols="2">(un)register a process as a driver for a set of devices</cell></row><row><cell>enable interrupts d</cell><cell cols="2">re-enable a set of interrupts after their successful handling</cell></row><row><cell cols="3">dev read d / dev write d communicate with a certain device</cell></row><row><cell cols="2">Inter-Process Communication</cell></row><row><cell>ipc send</cell><cell cols="2">send a message to another process</cell></row><row><cell>ipc receive</cell><cell cols="2">receive a message from another process</cell></row><row><cell>ipc request</cell><cell cols="2">send a message and immediately wait for a reply</cell></row><row><cell>change rights</cell><cell cols="2">manipulate IPC rights</cell></row><row><cell>read kernel info</cell><cell cols="2">receive information from the kernel</cell></row><row><cell cols="2">p call is reserved for privileged processes</cell><cell>d call is reserved for device drivers</cell></row></table></figure>
			<note xmlns="http://www.tei-c.org/ns/1.0" place="foot" n="1" xml:id="foot_0">The complete Isabelle/HOL theories of the models as well as detailed documentation are made available at the Verisoft repository, see &lt;http://www.verisoft.de/VerisoftRepository.html&gt;</note>
		</body>
		<back>

			<div type="funding">
<div xmlns="http://www.tei-c.org/ns/1.0"><p>Work partially funded by the German Federal Ministry of Education and Research (BMBF) in the framework of the Verisoft project under grant 01 IS C38.</p></div>
			</div>

			<div type="references">

				<listBibl>

<biblStruct xml:id="b0">
	<analytic>
		<title level="a" type="main">Pervasive compiler verification: From verified programs to verified systems</title>
		<author>
			<persName><forename type="first">D</forename><surname>Leinenbach</surname></persName>
		</author>
		<author>
			<persName><forename type="first">E</forename><surname>Petrova</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="m">Workshop on Systems Software Verification</title>
				<imprint>
			<publisher>Elsevier</publisher>
			<date type="published" when="2008">2008</date>
		</imprint>
	</monogr>
	<note>to appear</note>
</biblStruct>

<biblStruct xml:id="b1">
	<analytic>
		<title level="a" type="main">Towards the formal verification of a C0 compiler: Code generation and implementation correctness</title>
		<author>
			<persName><forename type="first">D</forename><surname>Leinenbach</surname></persName>
		</author>
		<author>
			<persName><forename type="first">W</forename><surname>Paul</surname></persName>
		</author>
		<author>
			<persName><forename type="first">E</forename><surname>Petrova</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="m">SEFM</title>
				<imprint>
			<date type="published" when="2005-09">September 2005</date>
			<biblScope unit="page" from="2" to="11" />
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b2">
	<analytic>
		<title level="a" type="main">Putting it all together: Formal verification of the VAMP</title>
		<author>
			<persName><forename type="first">S</forename><surname>Beyer</surname></persName>
		</author>
		<author>
			<persName><forename type="first">C</forename><surname>Jacobi</surname></persName>
		</author>
		<author>
			<persName><forename type="first">D</forename><surname>Kröning</surname></persName>
		</author>
		<author>
			<persName><forename type="first">D</forename><surname>Leinenbach</surname></persName>
		</author>
		<author>
			<persName><forename type="first">W</forename><forename type="middle">J</forename><surname>Paul</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="j">STTT</title>
		<imprint>
			<biblScope unit="volume">8</biblScope>
			<biblScope unit="issue">4-5</biblScope>
			<biblScope unit="page" from="411" to="430" />
			<date type="published" when="2006">2006</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b3">
	<analytic>
		<title level="a" type="main">Formal pervasive verification of a paging mechanism</title>
		<author>
			<persName><forename type="first">E</forename><surname>Alkassar</surname></persName>
		</author>
		<author>
			<persName><forename type="first">A</forename><surname>Starostin</surname></persName>
		</author>
		<author>
			<persName><forename type="first">N</forename><surname>Schirmer</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="j">TACAS</title>
		<imprint>
			<date type="published" when="2007">2007</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b4">
	<analytic>
		<title level="a" type="main">On the correctness of operating system kernels</title>
		<author>
			<persName><forename type="first">M</forename><surname>Gargano</surname></persName>
		</author>
		<author>
			<persName><forename type="first">M</forename><surname>Hillebrand</surname></persName>
		</author>
		<author>
			<persName><forename type="first">D</forename><surname>Leinenbach</surname></persName>
		</author>
		<author>
			<persName><forename type="first">W</forename><surname>Paul</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="m">TPHOLs</title>
				<imprint>
			<publisher>Springer</publisher>
			<date type="published" when="2005">2005</date>
			<biblScope unit="volume">3603</biblScope>
			<biblScope unit="page" from="1" to="16" />
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b5">
	<analytic>
		<title level="a" type="main">Dealing with I/O devices in the context of pervasive system verification</title>
		<author>
			<persName><forename type="first">M</forename><surname>Hillebrand</surname></persName>
		</author>
		<author>
			<persName><forename type="first">T</forename><surname>In Der Rieden</surname></persName>
		</author>
		<author>
			<persName><forename type="first">W</forename><surname>Paul</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="j">ICCD, IEEE Computer Society</title>
		<imprint>
			<biblScope unit="page" from="309" to="316" />
			<date type="published" when="2005">2005</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b6">
	<analytic>
		<title level="a" type="main">An approach to systems verification</title>
		<author>
			<persName><forename type="first">W</forename><forename type="middle">R</forename><surname>Bevier</surname></persName>
		</author>
		<author>
			<persName><forename type="first">W</forename><forename type="middle">A</forename><surname>Hunt</surname><genName>Jr</genName></persName>
		</author>
		<author>
			<persName><forename type="first">J</forename><forename type="middle">S</forename><surname>Moore</surname></persName>
		</author>
		<author>
			<persName><forename type="first">W</forename><forename type="middle">D</forename><surname>Young</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="j">J. Autom. Reasoning</title>
		<imprint>
			<biblScope unit="volume">5</biblScope>
			<biblScope unit="issue">4</biblScope>
			<biblScope unit="page" from="411" to="428" />
			<date type="published" when="1989-12">December 1989</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b7">
	<analytic>
		<title level="a" type="main">Kit and the short stack</title>
		<author>
			<persName><forename type="first">W</forename><forename type="middle">R</forename><surname>Bevier</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="j">J. Autom. Reasoning</title>
		<imprint>
			<biblScope unit="volume">5</biblScope>
			<biblScope unit="issue">4</biblScope>
			<biblScope unit="page" from="519" to="530" />
			<date type="published" when="1989-12">December 1989</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b8">
	<analytic>
		<title level="a" type="main">Towards trustworthy computing systems: taking microkernels to the next level</title>
		<author>
			<persName><forename type="first">G</forename><surname>Heiser</surname></persName>
		</author>
		<author>
			<persName><forename type="first">K</forename><surname>Elphinstone</surname></persName>
		</author>
		<author>
			<persName><forename type="first">I</forename><surname>Kuz</surname></persName>
		</author>
		<author>
			<persName><forename type="first">G</forename><surname>Klein</surname></persName>
		</author>
		<author>
			<persName><forename type="first">S</forename><forename type="middle">M</forename><surname>Petters</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="j">Operating Systems Review</title>
		<imprint>
			<biblScope unit="volume">41</biblScope>
			<biblScope unit="issue">3</biblScope>
			<date type="published" when="2007-07">July 2007</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b9">
	<analytic>
		<title level="a" type="main">Applying source-code verification to a microkernel: the vfiasco project</title>
		<author>
			<persName><forename type="first">M</forename><surname>Hohmuth</surname></persName>
		</author>
		<author>
			<persName><forename type="first">H</forename><surname>Tews</surname></persName>
		</author>
		<author>
			<persName><forename type="first">S</forename><forename type="middle">G</forename><surname>Stephens</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="m">Operating Systems Review, European workshop: beyond the PC</title>
				<meeting><address><addrLine>New York, NY, USA</addrLine></address></meeting>
		<imprint>
			<publisher>ACM Press</publisher>
			<date type="published" when="2002">2002</date>
			<biblScope unit="page" from="165" to="169" />
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b10">
	<analytic>
		<title level="a" type="main">Verifying the EROS confinement mechanism</title>
		<author>
			<persName><forename type="first">J</forename><forename type="middle">S</forename><surname>Shapiro</surname></persName>
		</author>
		<author>
			<persName><forename type="first">S</forename><surname>Weber</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="m">Symposium on Security and Privacy, IEEE Computer Society</title>
				<imprint>
			<date type="published" when="2000">2000</date>
			<biblScope unit="page" from="166" to="176" />
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b11">
	<analytic>
		<title level="a" type="main">Using XCAP to certify realistic systems code: Machine context management</title>
		<author>
			<persName><forename type="first">Z</forename><surname>Ni</surname></persName>
		</author>
		<author>
			<persName><forename type="first">D</forename><surname>Yu</surname></persName>
		</author>
		<author>
			<persName><forename type="first">Z</forename><surname>Shao</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="s">TPHOLs, Lecture Notes in Computer Science</title>
		<imprint>
			<biblScope unit="page" from="189" to="206" />
			<date type="published" when="2007-09">September 2007</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b12">
	<monogr>
		<title level="m" type="main">A Calculus of Communicating Systems</title>
		<author>
			<persName><forename type="first">R</forename><surname>Milner</surname></persName>
		</author>
		<imprint>
			<date type="published" when="1982">1982</date>
			<publisher>Springer</publisher>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b13">
	<monogr>
		<title level="m" type="main">Communicating Sequential Processes</title>
		<author>
			<persName><forename type="first">C</forename><forename type="middle">A R</forename><surname>Hoare</surname></persName>
		</author>
		<imprint>
			<date type="published" when="1985">1985</date>
			<publisher>Prentice-Hall</publisher>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b14">
	<analytic>
		<title level="a" type="main">Specifying and analyzing security automata using CSP-OZ</title>
		<author>
			<persName><forename type="first">D</forename><forename type="middle">A</forename><surname>Basin</surname></persName>
		</author>
		<author>
			<persName><forename type="first">E</forename><forename type="middle">R</forename><surname>Olderog</surname></persName>
		</author>
		<author>
			<persName><forename type="first">P</forename><forename type="middle">E</forename><surname>Sevinç</surname></persName>
		</author>
	</analytic>
	<monogr>
		<title level="m">ASIACCS, ACM</title>
				<imprint>
			<date type="published" when="2007">2007</date>
			<biblScope unit="page" from="70" to="81" />
		</imprint>
	</monogr>
</biblStruct>

				</listBibl>
			</div>
		</back>
	</text>
</TEI>
