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

452 lines
14 KiB
Plaintext

(*
* Copyright 2014, General Dynamics C4 Systems
*
* SPDX-License-Identifier: GPL-2.0-only
*)
chapter "x64-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 X64_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>
type_synonym io_port = "16 word"
type_synonym io_asid = "16 word"
section \<open>Architecture-specific capabilities\<close>
text \<open>The x64 kernel supports capabilities for ASID pools and an ASID controller capability,
along with capabilities for IO ports and spaces, as well as virtual memory mappings.\<close>
datatype arch_cap =
ASIDPoolCap (acap_asid_pool : obj_ref) (acap_asid_base : asid)
| ASIDControlCap
| IOPortCap (acap_io_port_first_port : io_port) (acap_io_port_last_port : io_port)
| IOPortControlCap
(* FIXME x64-vtd:
| IOSpaceCap (cap_io_domain_id : "16 word") (cap_io_pci_device : "io_asid option")
| IOPageTableCap (cap_iopt_base_ptr : obj_ref) (cap_io_pt_level : nat) (cap_iopt_mapped_address : "(io_asid * vspace_ref) option")
*)
| PageCap bool obj_ref (acap_rights : cap_rights) vmmap_type vmpage_size "(asid * vspace_ref) option"
| PageTableCap obj_ref "(asid * vspace_ref) option"
| PageDirectoryCap obj_ref "(asid * vspace_ref) option"
| PDPointerTableCap obj_ref "(asid * vspace_ref) option"
| PML4Cap obj_ref "asid option"
(* cr3 Stuff *)
datatype cr3 = cr3 obj_ref asid
primrec
cr3_base_address :: "cr3 \<Rightarrow> obj_ref"
where
"cr3_base_address (cr3 addr _) = addr"
primrec
cr3_pcid :: "cr3 \<Rightarrow> asid"
where
"cr3_pcid (cr3 _ pcid) = pcid"
section \<open>Architecture-specific objects\<close>
datatype table_attr = Accessed | CacheDisabled | WriteThrough | ExecuteDisable
type_synonym table_attrs = "table_attr set"
datatype frame_attr = PTAttr table_attr | Global | PAT | Dirty
type_synonym frame_attrs = "frame_attr set"
datatype pml4e
= InvalidPML4E
| PDPointerTablePML4E
(pml4_table : obj_ref)
(pml4e_attrs : table_attrs)
(pml4e_rights : vm_rights)
datatype pdpte
= InvalidPDPTE
| PageDirectoryPDPTE
(pdpt_table : obj_ref)
(pdpt_table_attrs : table_attrs)
(pdpt_rights : vm_rights)
| HugePagePDPTE
(pdpt_frame : obj_ref)
(pdpt_frame_attrs : frame_attrs)
(pdpt_rights : vm_rights)
datatype pde
= InvalidPDE
| PageTablePDE
obj_ref
(pt_attrs : table_attrs)
(pde_rights : cap_rights)
| LargePagePDE
obj_ref
(pde_page_attrs : frame_attrs)
(pde_rights: cap_rights)
datatype pte
= InvalidPTE
| SmallPagePTE
(pte_frame: obj_ref)
(pte_frame_attrs : frame_attrs)
(pte_rights : cap_rights)
datatype vm_page_entry = VMPTE pte | VMPDE pde | VMPDPTE pdpte
datatype translation_type = NotTranslated | Translated
datatype iocte =
InvalidIOCTE
| VTDCTE
(domain_id : word16)
(res_mem_reg: bool)
(address_width: nat)
(next_level_ptr: obj_ref)
(translation_type: translation_type)
(iocte_present : bool)
datatype iopte =
InvalidIOPTE
| VTDPTE
(frame_ptr : obj_ref)
(io_pte_rights : vm_rights)
datatype iorte =
InvalidIORTE
| VTDRTE
(context_table : obj_ref)
(iorte_present : bool)
datatype arch_kernel_obj =
ASIDPool "9 word \<rightharpoonup> obj_ref"
| PageTable "9 word \<Rightarrow> pte"
| PageDirectory "9 word \<Rightarrow> pde"
| PDPointerTable "9 word \<Rightarrow> pdpte"
| PageMapL4 "9 word \<Rightarrow> pml4e"
| DataPage bool vmpage_size
(* FIXME x64-vtd:
| IORootTable "16 word \<Rightarrow> iorte"
| IOContextTable "16 word \<Rightarrow> iocte"
| IOPageTable "16 word \<Rightarrow> iopte" *)
definition table_size :: nat where
"table_size = ptTranslationBits + word_size_bits"
definition iotable_size :: nat where
"iotable_size = ptTranslationBits + 2*word_size_bits"
definition cte_level_bits :: nat where
"cte_level_bits \<equiv> 5"
primrec
arch_obj_size :: "arch_cap \<Rightarrow> nat"
where
"arch_obj_size (ASIDPoolCap _ _) = pageBits"
| "arch_obj_size ASIDControlCap = 0"
| "arch_obj_size (IOPortCap _ _) = 0"
| "arch_obj_size IOPortControlCap = 0"
(* FIXME x64-vtd:
| "arch_obj_size (IOSpaceCap _ _) = 0"
| "arch_obj_size (IOPageTableCap _ _ _) = iotable_size" *)
| "arch_obj_size (PageCap _ _ _ _ sz _) = pageBitsForSize sz"
| "arch_obj_size (PageTableCap _ _) = table_size"
| "arch_obj_size (PageDirectoryCap _ _) = table_size"
| "arch_obj_size (PDPointerTableCap _ _) = table_size"
| "arch_obj_size (PML4Cap _ _) = table_size"
primrec
arch_cap_is_device :: "arch_cap \<Rightarrow> bool"
where
"arch_cap_is_device (ASIDPoolCap _ _) = False"
| "arch_cap_is_device ASIDControlCap = False"
| "arch_cap_is_device (IOPortCap _ _) = False"
| "arch_cap_is_device IOPortControlCap = False"
(* FIXME x64-vtd:
| "arch_cap_is_device (IOSpaceCap _ _) = False"
| "arch_cap_is_device (IOPageTableCap _ _ _) = False" *)
| "arch_cap_is_device (PageCap is_dev _ _ _ _ _) = is_dev"
| "arch_cap_is_device (PageTableCap _ _) = False"
| "arch_cap_is_device (PageDirectoryCap _ _) = False"
| "arch_cap_is_device (PDPointerTableCap _ _) = False"
| "arch_cap_is_device (PML4Cap _ _) = False"
definition tcb_bits :: nat where
"tcb_bits \<equiv> 11"
definition endpoint_bits :: nat where
"endpoint_bits \<equiv> 4"
definition ntfn_bits :: nat where
"ntfn_bits \<equiv> 5"
definition untyped_min_bits :: nat where
"untyped_min_bits \<equiv> 4"
definition untyped_max_bits :: nat where
"untyped_max_bits \<equiv> 47"
primrec
arch_kobj_size :: "arch_kernel_obj \<Rightarrow> nat"
where
"arch_kobj_size (ASIDPool _) = pageBits"
| "arch_kobj_size (PageTable _) = table_size"
| "arch_kobj_size (PageDirectory _) = table_size"
| "arch_kobj_size (PDPointerTable _) = table_size"
| "arch_kobj_size (PageMapL4 _) = table_size"
| "arch_kobj_size (DataPage _ sz) = pageBitsForSize sz"
primrec
aobj_ref :: "arch_cap \<rightharpoonup> obj_ref"
where
"aobj_ref (ASIDPoolCap x _) = Some x"
| "aobj_ref ASIDControlCap = None"
| "aobj_ref (IOPortCap _ _) = None"
| "aobj_ref IOPortControlCap = None"
(* FIXME x64-vtd:
| "aobj_ref (IOSpaceCap _ _) = None"
| "aobj_ref (IOPageTableCap x _ _) = Some x" *)
| "aobj_ref (PageCap _ x _ _ _ _) = Some x"
| "aobj_ref (PageDirectoryCap x _) = Some x"
| "aobj_ref (PageTableCap x _) = Some x"
| "aobj_ref (PDPointerTableCap x _) = Some x"
| "aobj_ref (PML4Cap x _) = Some x"
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' m sz as \<Rightarrow> PageCap dev x (validate_vm_rights rs) m sz as
| _ \<Rightarrow> ac"
section \<open>Architecture-specific object types and default objects\<close>
datatype
aobject_type =
SmallPageObj
| LargePageObj
| HugePageObj
| PageTableObj
| PageDirectoryObj
| PDPTObj
| PML4Obj
| ASIDPoolObj
datatype X64IRQState =
IRQFree
| IRQReserved
| IRQMSI
(MSIBus : machine_word)
(MSIDev : machine_word)
(MSIFunc : machine_word)
(MSIHandle : machine_word)
| IRQIOAPIC
(IRQioapic : machine_word)
(IRQPin : machine_word)
(IRQLevel : machine_word)
(IRQPolarity : machine_word)
(IRQMasked : bool)
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
| HugePageObj \<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 VMNoMap X64SmallPage None
| LargePageObj \<Rightarrow> PageCap dev r vm_read_write VMNoMap X64LargePage None
| HugePageObj \<Rightarrow> PageCap dev r vm_read_write VMNoMap X64HugePage None
| PageTableObj \<Rightarrow> PageTableCap r None
| PageDirectoryObj \<Rightarrow> PageDirectoryCap r None
| PDPTObj \<Rightarrow> PDPointerTableCap r None
| PML4Obj \<Rightarrow> PML4Cap r None
| 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 X64SmallPage
| LargePageObj \<Rightarrow> DataPage dev X64LargePage
| HugePageObj \<Rightarrow> DataPage dev X64HugePage
| PageTableObj \<Rightarrow> PageTable (\<lambda>x. InvalidPTE)
| PageDirectoryObj \<Rightarrow> PageDirectory (\<lambda>x. InvalidPDE)
| PDPTObj \<Rightarrow> PDPointerTable (\<lambda>x. InvalidPDPTE)
| PML4Obj \<Rightarrow> PageMapL4 (\<lambda>x. InvalidPML4E)
| ASIDPoolObj \<Rightarrow> ASIDPool (\<lambda>_. None)"
type_synonym x64_vspace_region_uses = "vspace_ref \<Rightarrow> x64vspace_region_use"
end
qualify X64_A (in Arch)
section \<open>Architecture-specific state\<close>
record arch_state =
x64_asid_table :: "3 word \<rightharpoonup> obj_ref"
x64_global_pml4 :: obj_ref
x64_kernel_vspace :: X64_A.x64_vspace_region_uses
x64_global_pts :: "obj_ref list"
x64_global_pdpts :: "obj_ref list"
x64_global_pds :: "obj_ref list"
x64_current_cr3 :: "X64_A.cr3"
x64_allocated_io_ports :: "X64_A.io_port \<Rightarrow> bool"
x64_num_ioapics :: "64 word"
x64_irq_state :: "8 word \<Rightarrow> X64_A.X64IRQState"
(* FIXME x64-vtd:
x64_num_io_domain_bits :: "16 word"
x64_first_valid_io_domain :: "16 word"
x64_num_io_domain_id_bits :: "32 word"
x64_io_root_table :: obj_ref *)
end_qualify
context Arch begin global_naming X64_A
definition
pd_shift_bits :: "nat" where
"pd_shift_bits \<equiv> pageBits + ptTranslationBits"
definition
pt_shift_bits :: "nat" where
"pt_shift_bits \<equiv> pageBits"
definition
pdpt_shift_bits :: "nat" where
"pdpt_shift_bits \<equiv> pageBits + ptTranslationBits + ptTranslationBits"
definition
pml4_shift_bits :: "nat" where
"pml4_shift_bits \<equiv> pageBits + ptTranslationBits + ptTranslationBits + ptTranslationBits"
definition
pt_bits :: "nat" where
"pt_bits \<equiv> table_size"
definition
pd_bits :: "nat" where
"pd_bits \<equiv> table_size"
definition
pdpt_bits :: "nat" where
"pdpt_bits \<equiv> table_size"
definition
pml4_bits :: "nat" where
"pml4_bits \<equiv> table_size"
definition
iopt_bits :: "nat" where
"iopt_bits \<equiv> iotable_size"
definition
vtd_cte_size_bits :: "nat" where
"vtd_cte_size_bits \<equiv> 8"
definition
vtd_pt_bits :: "nat" where
"vtd_pt_bits \<equiv> iotable_size"
definition
x64_num_io_pt_levels :: "nat" where
"x64_num_io_pt_levels \<equiv> 4"
section "Type declarations for invariant definitions"
(* FIXME x64-vtd: add *)
datatype aa_type =
AASIDPool
| APageTable
| APageDirectory
| APDPointerTable
| APageMapL4
| AUserData vmpage_size
| ADeviceData vmpage_size
(* FIXME x64-vtd: add *)
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
| PDPointerTable pdpt \<Rightarrow> APDPointerTable
| PageMapL4 pm \<Rightarrow> APageMapL4)"
text \<open>For implementation reasons the badge word has differing amounts of bits\<close>
definition
badge_bits :: nat where
"badge_bits \<equiv> 64"
end
section "Arch-specific TCB"
qualify X64_A (in Arch)
text \<open> Arch-specific part of a TCB: this must have at least a field for user context. \<close>
record arch_tcb =
tcb_context :: user_context
end_qualify
context Arch begin global_naming X64_A
definition
default_arch_tcb :: arch_tcb where
"default_arch_tcb \<equiv> \<lparr>tcb_context = new_context\<rparr>"
text \<open> Accessors for @{text "tcb_context"} inside @{text "arch_tcb"}.
These are later used to implement @{text as_user}, i.e.\ need to be
compatible with @{text user_monad}.\<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"
(* FIXME: the following means that we break the set/getRegister abstraction
and should move some of this into the machine interface *)
text \<open>
Accessors for the user register part of the @{text "arch_tcb"}.
(Because @{typ "register \<Rightarrow> machine_word"} may not be equal to @{typ user_context}).
\<close>
definition
arch_tcb_set_registers :: "(register \<Rightarrow> machine_word) \<Rightarrow> arch_tcb \<Rightarrow> arch_tcb"
where
"arch_tcb_set_registers regs a_tcb \<equiv>
a_tcb \<lparr> tcb_context := UserContext (fpu_state (tcb_context a_tcb)) regs \<rparr>"
definition
arch_tcb_get_registers :: "arch_tcb \<Rightarrow> register \<Rightarrow> machine_word"
where
"arch_tcb_get_registers a_tcb \<equiv> user_regs (tcb_context a_tcb)"
end
end