Skip to main content

sel4/arch/x86/
vspace.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: MIT
5//
6
7use sel4_config::{sel4_cfg, sel4_cfg_enum, sel4_cfg_if, sel4_cfg_wrap_match};
8
9use crate::{
10    CapTypeForFrameObject, CapTypeForFrameObjectOfFixedSize, CapTypeForTranslationTableObject,
11    ObjectBlueprint, ObjectBlueprintX64, ObjectBlueprintX86, cap_type,
12    const_helpers::u32_into_usize, sys,
13};
14
15/// Frame object types for this kernel configuration.
16#[sel4_cfg_enum]
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub enum FrameObjectType {
19    _4k,
20    LargePage,
21    #[sel4_cfg(HUGE_PAGE)]
22    HugePage,
23}
24
25impl FrameObjectType {
26    pub const GRANULE: Self = Self::_4k;
27
28    pub const fn blueprint(self) -> ObjectBlueprint {
29        sel4_cfg_wrap_match! {
30            match self {
31                Self::_4k => ObjectBlueprint::Arch(ObjectBlueprintX86::_4k),
32                Self::LargePage => ObjectBlueprint::Arch(ObjectBlueprintX86::LargePage),
33                #[sel4_cfg(HUGE_PAGE)]
34                Self::HugePage => {
35                    ObjectBlueprint::Arch(ObjectBlueprintX86::SeL4Arch(ObjectBlueprintX64::HugePage))
36                }
37            }
38        }
39    }
40
41    pub const fn from_bits(bits: usize) -> Option<Self> {
42        Some(sel4_cfg_wrap_match! {
43            match bits {
44                Self::_4K_BITS => Self::_4k,
45                Self::LARGE_PAGE_BITS => Self::LargePage,
46                #[sel4_cfg(HUGE_PAGE)]
47                Self::HUGE_PAGE_BITS => Self::HugePage,
48                _ => return None,
49            }
50        })
51    }
52
53    // For match arm LHS's, as we can't call const fn's
54    pub const _4K_BITS: usize = Self::_4k.bits();
55    pub const LARGE_PAGE_BITS: usize = Self::LargePage.bits();
56
57    #[sel4_cfg(HUGE_PAGE)]
58    pub const HUGE_PAGE_BITS: usize = Self::HugePage.bits();
59}
60
61impl CapTypeForFrameObject for cap_type::_4k {}
62
63impl CapTypeForFrameObjectOfFixedSize for cap_type::_4k {
64    const FRAME_OBJECT_TYPE: FrameObjectType = FrameObjectType::_4k;
65}
66
67impl CapTypeForFrameObject for cap_type::LargePage {}
68
69impl CapTypeForFrameObjectOfFixedSize for cap_type::LargePage {
70    const FRAME_OBJECT_TYPE: FrameObjectType = FrameObjectType::LargePage;
71}
72
73sel4_cfg_if! {
74    if #[sel4_cfg(HUGE_PAGE)] {
75        impl CapTypeForFrameObject for cap_type::HugePage {}
76
77        impl CapTypeForFrameObjectOfFixedSize for cap_type::HugePage {
78            const FRAME_OBJECT_TYPE: FrameObjectType = FrameObjectType::HugePage;
79        }
80    }
81}
82
83// // //
84
85/// Translation table object types for this kernel configuration.
86#[sel4_cfg_enum]
87#[derive(Copy, Clone, Debug, PartialEq, Eq)]
88pub enum TranslationTableObjectType {
89    PML4,
90    PDPT,
91    PageDirectory,
92    PageTable,
93    #[sel4_cfg(VTX)]
94    EPTPML4,
95    #[sel4_cfg(VTX)]
96    EPTPDPT,
97    #[sel4_cfg(VTX)]
98    EPTPageDirectory,
99    #[sel4_cfg(VTX)]
100    EPTPageTable,
101    #[sel4_cfg(IOMMU)]
102    IOPageTable,
103}
104
105impl TranslationTableObjectType {
106    pub const fn blueprint(&self) -> ObjectBlueprint {
107        sel4_cfg_wrap_match! {
108            match self {
109                Self::PML4 => {
110                    ObjectBlueprint::Arch(ObjectBlueprintX86::SeL4Arch(ObjectBlueprintX64::PML4))
111                }
112                Self::PDPT => {
113                    ObjectBlueprint::Arch(ObjectBlueprintX86::SeL4Arch(ObjectBlueprintX64::PDPT))
114                }
115                Self::PageDirectory => ObjectBlueprint::Arch(ObjectBlueprintX86::PageDirectory),
116                Self::PageTable => ObjectBlueprint::Arch(ObjectBlueprintX86::PageTable),
117                #[sel4_cfg(VTX)]
118                Self::EPTPML4 => {
119                    ObjectBlueprint::Arch(ObjectBlueprintX86::SeL4Arch(ObjectBlueprintX64::EPTPML4))
120                }
121                #[sel4_cfg(VTX)]
122                Self::EPTPDPT => {
123                    ObjectBlueprint::Arch(ObjectBlueprintX86::SeL4Arch(ObjectBlueprintX64::EPTPDPT))
124                }
125                #[sel4_cfg(VTX)]
126                Self::EPTPageDirectory => ObjectBlueprint::Arch(ObjectBlueprintX86::EPTPageDirectory),
127                #[sel4_cfg(VTX)]
128                Self::EPTPageTable => ObjectBlueprint::Arch(ObjectBlueprintX86::EPTPageTable),
129                #[sel4_cfg(IOMMU)]
130                Self::IOPageTable => ObjectBlueprint::Arch(ObjectBlueprintX86::IOPageTable),
131            }
132        }
133    }
134
135    pub const fn index_bits(&self) -> usize {
136        sel4_cfg_wrap_match! {
137            match self {
138                Self::PML4 => u32_into_usize(sys::seL4_PML4IndexBits),
139                Self::PDPT => u32_into_usize(sys::seL4_PDPTIndexBits),
140                Self::PageDirectory => u32_into_usize(sys::seL4_PageDirIndexBits),
141                Self::PageTable => u32_into_usize(sys::seL4_PageTableIndexBits),
142                #[sel4_cfg(VTX)]
143                Self::EPTPML4 => u32_into_usize(sys::seL4_X86_EPTPML4IndexBits),
144                #[sel4_cfg(VTX)]
145                Self::EPTPDPT => u32_into_usize(sys::seL4_X86_EPTPDPTIndexBits),
146                #[sel4_cfg(VTX)]
147                Self::EPTPageDirectory => u32_into_usize(sys::seL4_X86_EPTPDIndexBits),
148                #[sel4_cfg(VTX)]
149                Self::EPTPageTable => u32_into_usize(sys::seL4_X86_EPTPTIndexBits),
150                #[sel4_cfg(IOMMU)]
151                Self::IOPageTable => u32_into_usize(sys::seL4_IOPageTableIndexBits),
152            }
153        }
154    }
155
156    pub const fn from_level(level: usize) -> Option<Self> {
157        Some(match level {
158            0 => Self::PML4,
159            1 => Self::PDPT,
160            2 => Self::PageDirectory,
161            3 => Self::PageTable,
162            _ => return None,
163        })
164    }
165
166    #[sel4_cfg(VTX)]
167    pub const fn from_level_ept(level: usize) -> Option<Self> {
168        Some(match level {
169            0 => Self::EPTPML4,
170            1 => Self::EPTPDPT,
171            2 => Self::EPTPageDirectory,
172            3 => Self::EPTPageTable,
173            _ => return None,
174        })
175    }
176
177    #[sel4_cfg(IOMMU)]
178    pub const fn from_level_io_page_table(_level: usize) -> Option<Self> {
179        Some(Self::IOPageTable)
180    }
181}
182
183impl CapTypeForTranslationTableObject for cap_type::PML4 {
184    const TRANSLATION_TABLE_OBJECT_TYPE: TranslationTableObjectType =
185        TranslationTableObjectType::PML4;
186}
187
188impl CapTypeForTranslationTableObject for cap_type::PDPT {
189    const TRANSLATION_TABLE_OBJECT_TYPE: TranslationTableObjectType =
190        TranslationTableObjectType::PDPT;
191}
192
193impl CapTypeForTranslationTableObject for cap_type::PageDirectory {
194    const TRANSLATION_TABLE_OBJECT_TYPE: TranslationTableObjectType =
195        TranslationTableObjectType::PageDirectory;
196}
197
198impl CapTypeForTranslationTableObject for cap_type::PageTable {
199    const TRANSLATION_TABLE_OBJECT_TYPE: TranslationTableObjectType =
200        TranslationTableObjectType::PageTable;
201}
202
203#[sel4_cfg(IOMMU)]
204impl CapTypeForTranslationTableObject for cap_type::IOPageTable {
205    const TRANSLATION_TABLE_OBJECT_TYPE: TranslationTableObjectType =
206        TranslationTableObjectType::IOPageTable;
207}
208
209pub mod vspace_levels {
210    pub const NUM_LEVELS: usize = 4;
211
212    pub const HIGHEST_LEVEL_WITH_PAGE_ENTRIES: usize = NUM_LEVELS - 3;
213}
214
215#[sel4_cfg(all(ARCH_X86_64, IOMMU))]
216pub mod io_space {
217    use super::sys;
218    use crate::{Word, newtype_methods};
219
220    use sel4_sys::seL4_X86_IOSpace_CapData;
221    /// Corresponds to `seL4_IOSpace_CapData`.
222    #[derive(Debug, Clone, PartialEq, Eq)]
223    pub struct IOSpaceCapData(sys::seL4_X86_IOSpace_CapData);
224
225    impl IOSpaceCapData {
226        newtype_methods!(pub sys::seL4_X86_IOSpace_CapData);
227
228        pub fn new(domain_id: u64, pci_bus: u64, pci_dev: u64, pci_fun: u64) -> Self {
229            Self::from_inner(seL4_X86_IOSpace_CapData::new(
230                domain_id, pci_bus, pci_dev, pci_fun,
231            ))
232        }
233
234        pub fn into_word(self) -> Word {
235            let [word] = self.into_inner().0.into_inner();
236            word
237        }
238    }
239
240    impl From<IOSpaceCapData> for Word {
241        fn from(cap_data: IOSpaceCapData) -> Self {
242            cap_data.into_word()
243        }
244    }
245
246    pub mod levels {
247        use super::super::{FrameObjectType, TranslationTableObjectType};
248
249        // On x86 the leaf entries are normal frame objects, not IOMMU specific
250        fn span_bits(num_levels: usize, level: usize) -> usize {
251            assert!(level < num_levels);
252            (level..num_levels)
253                .map(|level| {
254                    TranslationTableObjectType::from_level_io_page_table(level)
255                        .unwrap()
256                        .index_bits()
257                })
258                .sum::<usize>()
259                + FrameObjectType::GRANULE.bits()
260        }
261
262        pub fn step_bits(num_levels: usize, level: usize) -> usize {
263            span_bits(num_levels, level)
264                - TranslationTableObjectType::from_level_io_page_table(level)
265                    .unwrap()
266                    .index_bits()
267        }
268    }
269}