lh-l4v/spec/design/skel/PSpaceStorable_H.thy

244 lines
9.2 KiB
Plaintext

(*
* Copyright 2014, General Dynamics C4 Systems
*
* SPDX-License-Identifier: GPL-2.0-only
*)
theory PSpaceStorable_H
imports
Structures_H
KernelStateData_H
"Lib.DataMap"
begin
context begin interpretation Arch .
requalify_types
arch_kernel_object_type
requalify_consts
archTypeOf
end
lemma UserData_singleton [simp]:
"(v = UserData) = True" "(UserData = v) = True"
by (cases v, simp)+
lemma UserDataDevice_singleton [simp]:
"(v = UserDataDevice) = True" "(UserDataDevice = v) = True"
by (cases v, simp)+
datatype
kernel_object_type =
EndpointT
| NotificationT
| CTET
| TCBT
| UserDataT
| UserDataDeviceT
| KernelDataT
| ArchT arch_kernel_object_type
primrec
koTypeOf :: "kernel_object \<Rightarrow> kernel_object_type"
where
"koTypeOf (KOEndpoint e) = EndpointT"
| "koTypeOf (KONotification e) = NotificationT"
| "koTypeOf (KOCTE e) = CTET"
| "koTypeOf (KOTCB e) = TCBT"
| "koTypeOf (KOUserData) = UserDataT"
| "koTypeOf (KOUserDataDevice) = UserDataDeviceT"
| "koTypeOf (KOKernelData) = KernelDataT"
| "koTypeOf (KOArch e) = ArchT (archTypeOf e)"
definition
typeError :: "unit list \<Rightarrow> kernel_object \<Rightarrow> 'a kernel" where
"typeError t1 t2 \<equiv> fail"
definition
alignError :: "nat \<Rightarrow> 'a kernel" where
"alignError n \<equiv> fail"
definition
alignCheck :: "machine_word \<Rightarrow> nat \<Rightarrow> unit kernel" where
"alignCheck x n \<equiv> unless ((x && mask n) = 0) $ alignError n"
definition
magnitudeCheck :: "machine_word \<Rightarrow> machine_word option \<Rightarrow> nat \<Rightarrow> unit kernel"
where
"magnitudeCheck x y n \<equiv> case y of None \<Rightarrow> return ()
| Some z \<Rightarrow> when (z - x < 1 << n) fail"
class pre_storable =
fixes injectKO :: "'a \<Rightarrow> kernel_object"
fixes projectKO_opt :: "kernel_object \<Rightarrow> 'a option"
fixes koType :: "'a itself \<Rightarrow> kernel_object_type"
assumes project_inject: "(projectKO_opt ko = Some v) = (injectKO v = ko)"
assumes project_koType: "(\<exists>v. projectKO_opt ko = Some (v::'a)) = (koTypeOf ko = koType TYPE('a))"
begin
definition
projectKO :: "kernel_object \<Rightarrow> 'a kernel"
where
"projectKO e \<equiv>
case projectKO_opt e of None \<Rightarrow> fail | Some k \<Rightarrow> return k"
definition
objBits :: "'a \<Rightarrow> nat"
where
"objBits v \<equiv> objBitsKO (injectKO v)"
definition
loadObject_default :: "machine_word \<Rightarrow> machine_word \<Rightarrow> machine_word option \<Rightarrow> kernel_object \<Rightarrow> 'a kernel"
where
"loadObject_default ptr ptr' next obj \<equiv> do
assert (ptr = ptr');
val \<leftarrow> projectKO obj;
alignCheck ptr (objBits val);
magnitudeCheck ptr next (objBits val);
return val
od"
definition
updateObject_default :: "'a \<Rightarrow> kernel_object \<Rightarrow> machine_word \<Rightarrow> machine_word \<Rightarrow> machine_word option \<Rightarrow> kernel_object kernel"
where
"updateObject_default val oldObj ptr ptr' next \<equiv> do
assert (ptr = ptr');
(_ :: 'a) \<leftarrow> projectKO oldObj;
alignCheck ptr (objBits val);
magnitudeCheck ptr next (objBits val);
return (injectKO val)
od"
end
class pspace_storable = pre_storable +
fixes makeObject :: 'a
\<comment>\<open>
`loadObject` is only used in the generic definition of `getObject`. It
describes how to extract a value of type `'a` from memory.
If `(obj, _) \<in> loadObjext p before after ko` within `getObject`, then:
- @{term "p :: machine_word"} is the addres that we want to read an
instance of `'a` from.
- @{term "before :: machine_word"} is the address of the nearest
object at or before `p`.
- @{term "after :: machine_word option"} is the address of the nearest
object after `p`, if any (for checking overlap).
- @{term "ko :: kernel_object"} is the object currently at `before`.
- @{term "obj :: 'a"} is the value extracted from `ko`.
Graphically, the "memory" looks like this:
before p after
|-------|--+-----+-----|---|
| +~~+ <---+---------- The span of obj, the object we want to extract.
+~~~~~~~~~~~~~~~~+ <-------- The span of ko, the existing object that spans obj.
+~~~+ The span of whatever object comes after obj.
We don't care about this beyond making sure
it doesn't overlap with ko.
In almost every case, the object in memory (ko) is the same type of object
as the one being loaded (obj). For example, for a reply object our parameters
look like this:
p, before
|-----------|
+~~~~~~~~~~~+ <- The span of two objects:
- ko, the existing object (which should be a reply object).
- obj, the object that we want to load from memory. This will
just be ko projected through @{term projectKO}.
In these simple cases, @{term loadObject_default} is a good specification
for how to load an instance of `'a` from memory.
The only interesting case is when we're loading a CTE, which might be
inside a TCB. Then memory looks like this:
before p
|-------|--+-----+
| +~~+ <---+---- The span of obj, i.e. the CTE which we're reading from
| | memory.
+~~~~~~~~~~~~~~~~+ <-- The span of ko, i.e. the TCB surrounding and containing
obj.
In this case, the process for extracting the CTE from the surrounding TCB
is more involved. See `loadObject_cte` in `ObjectInstances_H`.
\<close>
fixes loadObject :: "machine_word \<Rightarrow> machine_word \<Rightarrow> machine_word option \<Rightarrow> kernel_object \<Rightarrow> 'a kernel"
\<comment>\<open>
`updateObject` is only used in the generic definition of `setObject`,
but it shows up in a few lemma statements as well. It describes how to update
the kernel object contents of memory depending on what's already in that
memory.
If `(ko', _) \<in> updateObject v ko p before after s` within `setObject`, then:
- @{term "v :: 'a"} is the new object you want to write at pointer
@{term "p :: machine_word"}.
- @{term "before :: machine_word"} is the address of the nearest
object at or before `p`.
- @{term "ko :: kernel_object"} is the object currently at `before`.
- @{term "after :: machine_word option"} should be the address of the nearest
object after `p`, if any (for checking overlap).
- The returned value @{term "ko' :: kernel_object"} is the old object `ko`,
updated as required by `v`. This value gets inserted by `setObject` into
memory at the address `before`.
Graphically, the "memory" looks like this:
before p after
|-------|--+-----+-----|---|
| +~~+ <---+---------- The span of v, the object we want to insert.
+~~~~~~~~~~~~~~~~+ <-------- The span of ko, the existing object that spans v.
This is also the span of ko', which will be what
gets put into memory after the update.
+~~~+ The span of whatever object comes after ko.
We don't care about this beyond making sure
it doesn't overlap with ko before or after it
gets updated with v.
In almost every case, the object in memory (ko) is the same type of object
as the one being inserted (v). For example, for a reply object our parameters
look like this:
p, before
|-----------|
+~~~~~~~~~~~+ <- The span of three objects:
- v, the new reply object we want to insert.
- ko, the existing object (which should be a reply object).
- ko', the new object (which should be a reply object if
the previous one was).
In these simple cases, @{term updateObject_default} is a good specification
for how to update the existing kernel object.
The only interesting case is when we're updating a CTE, which might be
inside a TCB. Then memory looks like this:
before p
|-------|--+-----+
| +~~+ <---+---- The span of v, i.e. the CTE which we're inserting into
| | memory.
+~~~~~~~~~~~~~~~~+ <-- The span of ko, i.e. the TCB surrounding and containing v.
This is also the span of ko', which is "just" a copy
of ko with the relevant CTE updated.
In this case, the process for updating the surrounding TCB is more involved.
See `updateObject_cte` in `ObjectInstances_H`.
\<close>
fixes updateObject :: "'a \<Rightarrow> kernel_object \<Rightarrow> machine_word \<Rightarrow> machine_word \<Rightarrow>
machine_word option \<Rightarrow> kernel_object kernel"
\<comment>\<open>
If updating an object succeeds, then the type of the updated object (ko')
should be the same as the original object (ko).
\<close>
assumes updateObject_type:
"(ko', s') \<in> fst (updateObject v ko p p' p'' s) \<Longrightarrow> koTypeOf ko' = koTypeOf ko"
end