lh-l4v/spec/abstract/ARM_HYP/Arch_Structs_A.thy

426 lines
13 KiB
Plaintext

(*
* Copyright 2014, General Dynamics C4 Systems
*
* SPDX-License-Identifier: GPL-2.0-only
*)
(*
ARM specific data types
*)
chapter "ARM-Specific Data Types"
theory Arch_Structs_A
imports
"ExecSpec.Arch_Structs_B"
ExceptionTypes_A
VMRights_A
ExecSpec.Arch_Kernel_Config_Lemmas
begin
context Arch begin global_naming ARM_A
text \<open>
This theory provides architecture-specific definitions and datatypes
including architecture-specific capabilities and objects.
\<close>
section \<open>Architecture-specific virtual memory\<close>
text \<open>An ASID is simply a word.\<close>
type_synonym asid = "word32"
datatype vm_attribute = PageCacheable | XNever
type_synonym vm_attributes = "vm_attribute set"
section \<open>Architecture-specific capabilities\<close>
text \<open>The ARM kernel supports capabilities for ASID pools and an ASID controller capability,
along with capabilities for page directories, page tables, and page mappings.\<close>
datatype arch_cap =
ASIDPoolCap obj_ref asid
| ASIDControlCap
| PageCap bool obj_ref cap_rights vmpage_size "(asid * vspace_ref) option"
| PageTableCap obj_ref "(asid * vspace_ref) option"
| PageDirectoryCap obj_ref "asid option"
| VCPUCap obj_ref
lemmas arch_cap_cases =
arch_cap.induct[where arch_cap=x and P="\<lambda>x'. x = x' \<longrightarrow> P x'" for x P, simplified, rule_format]
lemmas arch_cap_cases_asm =
arch_cap.induct[where arch_cap=x and P="\<lambda>x'. x = x' \<longrightarrow> P x' \<longrightarrow> R" for P R x,
simplified, rule_format, rotated -1]
definition
is_page_cap :: "arch_cap \<Rightarrow> bool" where
"is_page_cap c \<equiv> \<exists>x0 x1 x2 x3 x4. c = PageCap x0 x1 x2 x3 x4"
definition
asid_high_bits :: nat where
"asid_high_bits \<equiv> 7"
definition
asid_low_bits :: nat where
"asid_low_bits \<equiv> 10 :: nat"
definition
asid_bits :: nat where
"asid_bits \<equiv> 17 :: nat"
section \<open>Architecture-specific objects\<close>
text \<open>This section gives the types and auxiliary definitions for the
architecture-specific objects: a page directory entry (@{text "pde"})
contains either an invalid entry, a page table reference, a section
reference, or a super-section reference; a page table entry contains
either an invalid entry, a large page, or a small page mapping;
finally, an architecture-specific object is either an ASID pool, a
page table, a page directory, or a data page used to model user
memory.
\<close>
text \<open>
Hypervisor extensions use long page table descriptors (64-bit) for the stage 2
translation (host-to-hypervisor). This is a three-level table system, but the
hardware can be configured to omit the first level entirely if all second
levels are stored contiguously. We use this configuration to preserve the usual
page table/directory nomenclature.
seL4 does not use hardware domains or parity on ARM hypervisor systems.
\<close>
datatype pde =
InvalidPDE
| PageTablePDE obj_ref
| SectionPDE obj_ref vm_attributes cap_rights
| SuperSectionPDE obj_ref vm_attributes cap_rights
datatype pte =
InvalidPTE
| LargePagePTE obj_ref vm_attributes cap_rights
| SmallPagePTE obj_ref vm_attributes cap_rights
type_synonym hyper_reg_context = machine_word
text \<open>With hypervisor extensions enabled, page table and page directory entries occupy
8 bytes. Page directories occupy four frames, and page tables occupy a frame.\<close>
definition
pde_bits :: "nat" where
"pde_bits \<equiv> 3"
definition
pte_bits :: "nat" where
"pte_bits \<equiv> 3"
definition
pd_bits :: "nat" where
"pd_bits \<equiv> 11 + pde_bits"
definition
pt_bits :: "nat" where
"pt_bits \<equiv> 9 + pte_bits"
definition
vcpu_bits :: "nat" where
"vcpu_bits \<equiv> pageBits"
text \<open>vcpu\<close>
type_synonym virq = machine_word
end
qualify ARM_A (in Arch)
record gic_vcpu_interface =
vgic_hcr :: machine_word
vgic_vmcr :: machine_word
vgic_apr :: machine_word
vgic_lr :: "nat \<Rightarrow> ARM_A.virq"
record vcpu =
vcpu_tcb :: "obj_ref option"
vcpu_vgic :: gic_vcpu_interface
vcpu_regs :: "vcpureg \<Rightarrow> machine_word"
vcpu_vppi_masked :: "vppievent_irq \<Rightarrow> bool"
vcpu_vtimer :: virt_timer
end_qualify
context Arch begin global_naming ARM_A
definition "vcpu_sctlr vcpu \<equiv> vcpu_regs vcpu VCPURegSCTLR"
definition
default_gic_vcpu_interface :: gic_vcpu_interface
where
"default_gic_vcpu_interface \<equiv> \<lparr>
vgic_hcr = vgicHCREN,
vgic_vmcr = 0,
vgic_apr = 0,
vgic_lr = \<lambda>_. 0 \<rparr>"
definition
default_vcpu :: vcpu where
"default_vcpu \<equiv> \<lparr>
vcpu_tcb = None,
vcpu_vgic = default_gic_vcpu_interface,
vcpu_regs = (\<lambda>_. 0) (VCPURegSCTLR := sctlrDefault
, VCPURegACTLR := actlrDefault),
vcpu_vppi_masked = (\<lambda>_. False),
vcpu_vtimer = VirtTimer 0
\<rparr>"
text \<open>
ASID pools translate 10 bits, VCPUs store a potential association to a TCB as well as
an extended register context. Page tables have 512 entries (cf B3.6.5, pg 1348). For data pages,
we record their size.
\<close>
datatype arch_kernel_obj =
ASIDPool "10 word \<rightharpoonup> obj_ref"
| PageTable "9 word \<Rightarrow> pte" (* ARMHYP *)
| PageDirectory "11 word \<Rightarrow> pde" (* ARMHYP *)
| DataPage bool vmpage_size
| VCPU vcpu
lemmas arch_kernel_obj_cases =
arch_kernel_obj.induct[where arch_kernel_obj=x and P="\<lambda>x'. x = x' \<longrightarrow> P x'" for x P,
simplified, rule_format]
lemmas arch_kernel_obj_cases_asm =
arch_kernel_obj.induct[where arch_kernel_obj=x and P="\<lambda>x'. x = x' \<longrightarrow> P x' \<longrightarrow> R" for P R x,
simplified, rule_format, rotated -1]
definition cte_level_bits :: nat where
"cte_level_bits \<equiv> 4"
primrec
arch_obj_size :: "arch_cap \<Rightarrow> nat"
where
"arch_obj_size (ASIDPoolCap p as) = pageBits"
| "arch_obj_size ASIDControlCap = 0"
| "arch_obj_size (PageCap dev x rs sz as4) = pageBitsForSize sz"
| "arch_obj_size (PageDirectoryCap x as2) = pd_bits"
| "arch_obj_size (PageTableCap x as3) = pt_bits"
| "arch_obj_size (VCPUCap _) = vcpu_bits"
primrec
arch_cap_is_device :: "arch_cap \<Rightarrow> bool"
where
"arch_cap_is_device (PageCap dev x rs sz as4) = dev"
| "arch_cap_is_device ASIDControlCap = False"
| "arch_cap_is_device (ASIDPoolCap p as) = False"
| "arch_cap_is_device (PageTableCap x as3) = False"
| "arch_cap_is_device (PageDirectoryCap x as2) = False"
| "arch_cap_is_device (VCPUCap _) = False"
definition tcb_bits :: nat where
"tcb_bits \<equiv> 9"
definition endpoint_bits :: nat where
"endpoint_bits \<equiv> 4"
definition ntfn_bits :: nat where
"ntfn_bits \<equiv> 4"
definition untyped_min_bits :: nat where
"untyped_min_bits \<equiv> 4"
definition untyped_max_bits :: nat where
"untyped_max_bits \<equiv> 29"
primrec
arch_kobj_size :: "arch_kernel_obj \<Rightarrow> nat"
where
"arch_kobj_size (ASIDPool p) = pageBits"
| "arch_kobj_size (PageTable pte) = pt_bits"
| "arch_kobj_size (PageDirectory pde) = pd_bits"
| "arch_kobj_size (DataPage dev sz) = pageBitsForSize sz"
| "arch_kobj_size (VCPU _) = vcpu_bits"
primrec
aobj_ref :: "arch_cap \<rightharpoonup> obj_ref"
where
"aobj_ref (ASIDPoolCap p as) = Some p"
| "aobj_ref ASIDControlCap = None"
| "aobj_ref (PageCap dev x rs sz as4) = Some x"
| "aobj_ref (PageDirectoryCap x as2) = Some x"
| "aobj_ref (PageTableCap x as3) = Some x"
| "aobj_ref (VCPUCap x) = Some x"
primrec (nonexhaustive)
acap_rights :: "arch_cap \<Rightarrow> cap_rights"
where
"acap_rights (PageCap dev x rs sz as) = rs"
definition
acap_rights_update :: "cap_rights \<Rightarrow> arch_cap \<Rightarrow> arch_cap" where
"acap_rights_update rs ac \<equiv> case ac of
PageCap dev x rs' sz as \<Rightarrow> PageCap dev x (validate_vm_rights rs) sz as
| _ \<Rightarrow> ac"
section \<open>Architecture-specific object types and default objects\<close>
datatype
aobject_type =
SmallPageObj
| LargePageObj
| SectionObj
| SuperSectionObj
| PageTableObj
| PageDirectoryObj
| ASIDPoolObj
| VCPUObj
definition
arch_is_frame_type :: "aobject_type \<Rightarrow> bool"
where
"arch_is_frame_type aobj \<equiv> case aobj of
SmallPageObj \<Rightarrow> True
| LargePageObj \<Rightarrow> True
| SectionObj \<Rightarrow> True
| SuperSectionObj \<Rightarrow> True
| _ \<Rightarrow> False"
definition arch_default_cap :: "aobject_type \<Rightarrow> obj_ref \<Rightarrow> nat \<Rightarrow> bool \<Rightarrow> arch_cap" where
"arch_default_cap tp r n dev \<equiv> case tp of
SmallPageObj \<Rightarrow> PageCap dev r vm_read_write ARMSmallPage None
| LargePageObj \<Rightarrow> PageCap dev r vm_read_write ARMLargePage None
| SectionObj \<Rightarrow> PageCap dev r vm_read_write ARMSection None
| SuperSectionObj \<Rightarrow> PageCap dev r vm_read_write ARMSuperSection None
| PageTableObj \<Rightarrow> PageTableCap r None
| PageDirectoryObj \<Rightarrow> PageDirectoryCap r None
| VCPUObj \<Rightarrow> VCPUCap r
| ASIDPoolObj \<Rightarrow> ASIDPoolCap r 0" (* unused *)
definition
default_arch_object :: "aobject_type \<Rightarrow> bool \<Rightarrow> nat \<Rightarrow> arch_kernel_obj" where
"default_arch_object tp dev n \<equiv> case tp of
SmallPageObj \<Rightarrow> DataPage dev ARMSmallPage
| LargePageObj \<Rightarrow> DataPage dev ARMLargePage
| SectionObj \<Rightarrow> DataPage dev ARMSection
| SuperSectionObj \<Rightarrow> DataPage dev ARMSuperSection
| PageTableObj \<Rightarrow> PageTable (\<lambda>x. InvalidPTE)
| PageDirectoryObj \<Rightarrow> PageDirectory (\<lambda>x. InvalidPDE)
| VCPUObj \<Rightarrow> VCPU default_vcpu
| ASIDPoolObj \<Rightarrow> ASIDPool (\<lambda>_. None)"
type_synonym hw_asid = word8
type_synonym arm_vspace_region_uses = "vspace_ref \<Rightarrow> arm_vspace_region_use"
section \<open>Architecture-specific state\<close>
text \<open>The architecture-specific state for the ARM model
consists of the first level of the ASID table (@{text "arm_asid_table"}), a
map from hardware ASIDs to seL4 ASIDs (@{text "arm_hwasid_table"}),
the next hardware ASID to preempt (@{text "arm_next_asid"}), the
inverse map from seL4 ASIDs to hardware ASIDs (first component of
@{text "arm_asid_map"}), and the address of the page directory and
page tables mapping the shared address space, along with a description
of this space (@{text "arm_global_pd"}, @{text "arm_global_pts"}, and
@{text "arm_kernel_vspace"} respectively).
Hardware ASIDs are only ever associated with seL4 ASIDs that have a
currently active page directory. The second component of
@{text "arm_asid_map"} values is the address of that page directory.
\<close>
end
qualify ARM_A (in Arch)
text \<open>arch\_state\<close>
record arch_state =
arm_asid_table :: "7 word \<rightharpoonup> obj_ref"
arm_hwasid_table :: "ARM_A.hw_asid \<rightharpoonup> ARM_A.asid"
arm_next_asid :: ARM_A.hw_asid
arm_asid_map :: "ARM_A.asid \<rightharpoonup> (ARM_A.hw_asid \<times> obj_ref)"
arm_current_vcpu :: "(obj_ref \<times> bool) option"
arm_gicvcpu_numlistregs :: nat
arm_kernel_vspace :: ARM_A.arm_vspace_region_uses
arm_us_global_pd :: obj_ref
end_qualify
context Arch begin global_naming ARM_A
section "Type declarations for invariant definitions"
datatype aa_type =
AASIDPool
| APageTable
| APageDirectory
| AVCPU
| AUserData vmpage_size
| ADeviceData vmpage_size
definition aa_type :: "arch_kernel_obj \<Rightarrow> aa_type"
where
"aa_type ao \<equiv> (case ao of
PageTable pt \<Rightarrow> APageTable
| PageDirectory pd \<Rightarrow> APageDirectory
| DataPage dev sz \<Rightarrow> if dev then ADeviceData sz else AUserData sz
| ASIDPool f \<Rightarrow> AASIDPool
| VCPU v \<Rightarrow> AVCPU)"
text \<open>For implementation reasons the badge word has differing amounts of bits\<close>
definition
badge_bits :: nat where
badge_bits_def [simp]: "badge_bits \<equiv> 28"
end
section "Arch-specific tcb"
qualify ARM_A (in Arch)
(* arch specific part of tcb: this must have a field for user context *)
record arch_tcb =
tcb_context :: user_context
tcb_vcpu :: "obj_ref option"
end_qualify
context Arch begin global_naming ARM_A
definition
default_arch_tcb :: arch_tcb where
"default_arch_tcb \<equiv> \<lparr>
tcb_context = new_context,
tcb_vcpu = None \<rparr>"
text \<open>accesors for @{text "tcb_context"} inside @{text "arch_tcb"}\<close>
definition
arch_tcb_context_set :: "user_context \<Rightarrow> arch_tcb \<Rightarrow> arch_tcb"
where
"arch_tcb_context_set uc a_tcb \<equiv> a_tcb \<lparr> tcb_context := uc \<rparr>"
definition
arch_tcb_context_get :: "arch_tcb \<Rightarrow> user_context"
where
"arch_tcb_context_get a_tcb \<equiv> tcb_context a_tcb"
definition
arch_tcb_set_registers :: "(register \<Rightarrow> machine_word) \<Rightarrow> arch_tcb \<Rightarrow> arch_tcb"
where
"arch_tcb_set_registers \<equiv> arch_tcb_context_set"
definition
arch_tcb_get_registers :: "arch_tcb \<Rightarrow> register \<Rightarrow> machine_word"
where
"arch_tcb_get_registers \<equiv> arch_tcb_context_get"
end
end