Skip to main content

sel4/
bootinfo.rs

1//
2// Copyright 2023, Colias Group, LLC
3// Copyright (c) 2020 Arm Limited
4//
5// SPDX-License-Identifier: MIT
6//
7
8#![allow(clippy::useless_conversion)]
9
10use core::mem;
11use core::ops::{Deref, Range};
12use core::slice;
13
14use sel4_config::sel4_cfg;
15
16use crate::{FrameObjectType, IpcBuffer, cap_type, init_thread::SlotRegion, newtype_methods, sys};
17
18/// A wrapped pointer to a [`BootInfo`] block.
19///
20/// Access [`BootInfo`] via `Deref`, and [`BootInfoExtraIter`] via [`extra`](BootInfoPtr::extra).
21#[repr(transparent)]
22#[derive(Debug)]
23pub struct BootInfoPtr {
24    ptr: *const BootInfo,
25}
26
27impl BootInfoPtr {
28    #[allow(clippy::missing_safety_doc)]
29    pub unsafe fn new(ptr: *const BootInfo) -> Self {
30        assert_eq!(
31            ptr.cast::<()>()
32                .align_offset(FrameObjectType::GRANULE.bytes()),
33            0
34        ); // sanity check
35        Self { ptr }
36    }
37
38    pub fn ptr(&self) -> *const BootInfo {
39        self.ptr
40    }
41
42    fn extra_ptr(&self) -> *const u8 {
43        self.ptr
44            .cast::<u8>()
45            .wrapping_offset(Self::EXTRA_OFFSET.try_into().unwrap())
46    }
47
48    fn extra_slice(&self) -> &[u8] {
49        unsafe { slice::from_raw_parts(self.extra_ptr(), self.extra_len()) }
50    }
51
52    pub fn extra(&self) -> BootInfoExtraIter<'_> {
53        BootInfoExtraIter::new(self)
54    }
55
56    pub fn footprint_size(&self) -> usize {
57        Self::EXTRA_OFFSET + self.extra_len()
58    }
59
60    const EXTRA_OFFSET: usize = FrameObjectType::GRANULE.bytes();
61}
62
63impl Deref for BootInfoPtr {
64    type Target = BootInfo;
65
66    fn deref(&self) -> &Self::Target {
67        unsafe { self.ptr().as_ref().unwrap() }
68    }
69}
70
71/// Corresponds to `seL4_BootInfo`.
72#[repr(transparent)]
73#[derive(Debug)]
74pub struct BootInfo(sys::seL4_BootInfo);
75
76impl BootInfo {
77    newtype_methods!(pub sys::seL4_BootInfo);
78
79    fn extra_len(&self) -> usize {
80        self.inner().extraLen.try_into().unwrap()
81    }
82
83    pub fn ipc_buffer(&self) -> *mut IpcBuffer {
84        self.inner().ipcBuffer.cast()
85    }
86
87    pub fn empty(&self) -> SlotRegion<cap_type::Null> {
88        SlotRegion::from_sys(self.inner().empty)
89    }
90
91    pub fn user_image_frames(&self) -> SlotRegion<cap_type::Granule> {
92        SlotRegion::from_sys(self.inner().userImageFrames)
93    }
94
95    #[sel4_cfg(KERNEL_MCS)]
96    pub fn sched_control(&self) -> SlotRegion<cap_type::SchedControl> {
97        SlotRegion::from_sys(self.inner().schedcontrol)
98    }
99
100    pub fn untyped(&self) -> SlotRegion<cap_type::Untyped> {
101        SlotRegion::from_sys(self.inner().untyped)
102    }
103
104    fn untyped_list_inner(&self) -> &[sys::seL4_UntypedDesc] {
105        &self.inner().untypedList[..self.untyped().len()]
106    }
107
108    pub fn untyped_list(&self) -> &[UntypedDesc] {
109        let inner = self.untyped_list_inner();
110        // safe because of #[repr(trasnparent)]
111        unsafe { slice::from_raw_parts(inner.as_ptr().cast(), inner.len()) }
112    }
113
114    fn untyped_list_partition_point(&self) -> usize {
115        self.untyped_list().partition_point(|ut| ut.is_device())
116    }
117
118    pub fn device_untyped_range(&self) -> Range<usize> {
119        0..self.untyped_list_partition_point()
120    }
121
122    pub fn kernel_untyped_range(&self) -> Range<usize> {
123        self.untyped_list_partition_point()..self.untyped_list().len()
124    }
125}
126
127/// Corresponds to `seL4_UntypedDesc`.
128#[repr(transparent)]
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct UntypedDesc(sys::seL4_UntypedDesc);
131
132impl UntypedDesc {
133    newtype_methods!(pub sys::seL4_UntypedDesc);
134
135    pub fn paddr(&self) -> usize {
136        self.inner().paddr.try_into().unwrap()
137    }
138
139    pub fn size_bits(&self) -> usize {
140        self.inner().sizeBits.into()
141    }
142
143    pub fn is_device(&self) -> bool {
144        self.inner().isDevice != 0
145    }
146}
147
148/// An extra bootinfo chunk along with its ID.
149#[derive(Clone, Debug, PartialEq, Eq)]
150pub struct BootInfoExtra<'a> {
151    pub id: BootInfoExtraId,
152    pub content_with_header: &'a [u8],
153}
154
155impl BootInfoExtra<'_> {
156    pub fn content_with_header(&self) -> &[u8] {
157        self.content_with_header
158    }
159
160    pub fn content(&self) -> &[u8] {
161        let content_with_header = self.content_with_header();
162        &content_with_header[mem::size_of::<sys::seL4_BootInfoHeader>()..]
163    }
164}
165
166/// Corresponds to `seL4_BootInfoID`.
167#[derive(Clone, Debug, PartialEq, Eq)]
168pub enum BootInfoExtraId {
169    Padding,
170    X86Vbe,
171    X86Mbmmap,
172    X86AcpiRsdp,
173    X86FrameBuffer,
174    X86TscFreq,
175    Fdt,
176}
177
178impl BootInfoExtraId {
179    pub fn from_sys(id: sys::seL4_BootInfoID::Type) -> Option<Self> {
180        match id {
181            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_PADDING => Some(BootInfoExtraId::Padding),
182            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_X86_VBE => Some(BootInfoExtraId::X86Vbe),
183            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_X86_MBMMAP => {
184                Some(BootInfoExtraId::X86Mbmmap)
185            }
186            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_X86_ACPI_RSDP => {
187                Some(BootInfoExtraId::X86AcpiRsdp)
188            }
189            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_X86_FRAMEBUFFER => {
190                Some(BootInfoExtraId::X86FrameBuffer)
191            }
192            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_X86_TSC_FREQ => {
193                Some(BootInfoExtraId::X86TscFreq)
194            }
195            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_FDT => Some(BootInfoExtraId::Fdt),
196            _ => None,
197        }
198    }
199}
200
201/// An iterator for accessing the [`BootInfoExtra`] entires associated with a [`BootInfoPtr`].
202pub struct BootInfoExtraIter<'a> {
203    bootinfo: &'a BootInfoPtr,
204    cursor: usize,
205}
206
207impl<'a> BootInfoExtraIter<'a> {
208    fn new(bootinfo: &'a BootInfoPtr) -> Self {
209        Self {
210            bootinfo,
211            cursor: 0,
212        }
213    }
214}
215
216impl<'a> Iterator for BootInfoExtraIter<'a> {
217    type Item = BootInfoExtra<'a>;
218
219    fn next(&mut self) -> Option<Self::Item> {
220        while self.cursor < self.bootinfo.extra_slice().len() {
221            let header = {
222                let mut it = self.bootinfo.extra_slice()[self.cursor..]
223                    .chunks(mem::size_of::<sys::seL4_Word>());
224                let mut munch_word =
225                    || sys::seL4_Word::from_ne_bytes(it.next().unwrap().try_into().unwrap());
226                let id = munch_word();
227                let len = munch_word();
228                sys::seL4_BootInfoHeader { id, len }
229            };
230            let id = BootInfoExtraId::from_sys(header.id);
231            let len = usize::try_from(header.len).unwrap();
232            let content_with_header_start = self.cursor;
233            let content_with_header_end = content_with_header_start + len;
234            self.cursor = content_with_header_end;
235            if let Some(id) = id {
236                return Some(BootInfoExtra {
237                    id,
238                    content_with_header: &self.bootinfo.extra_slice()
239                        [content_with_header_start..content_with_header_end],
240                });
241            }
242        }
243        None
244    }
245}