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::{cap_type, init_thread::SlotRegion, newtype_methods, sys, FrameObjectType, IpcBuffer};
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    Fdt,
171}
172
173impl BootInfoExtraId {
174    pub fn from_sys(id: sys::seL4_BootInfoID::Type) -> Option<Self> {
175        match id {
176            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_PADDING => Some(BootInfoExtraId::Padding),
177            sys::seL4_BootInfoID::SEL4_BOOTINFO_HEADER_FDT => Some(BootInfoExtraId::Fdt),
178            _ => None,
179        }
180    }
181}
182
183/// An iterator for accessing the [`BootInfoExtra`] entires associated with a [`BootInfoPtr`].
184pub struct BootInfoExtraIter<'a> {
185    bootinfo: &'a BootInfoPtr,
186    cursor: usize,
187}
188
189impl<'a> BootInfoExtraIter<'a> {
190    fn new(bootinfo: &'a BootInfoPtr) -> Self {
191        Self {
192            bootinfo,
193            cursor: 0,
194        }
195    }
196}
197
198impl<'a> Iterator for BootInfoExtraIter<'a> {
199    type Item = BootInfoExtra<'a>;
200
201    fn next(&mut self) -> Option<Self::Item> {
202        while self.cursor < self.bootinfo.extra_slice().len() {
203            let header = {
204                let mut it = self.bootinfo.extra_slice()[self.cursor..]
205                    .chunks(mem::size_of::<sys::seL4_Word>());
206                let mut munch_word =
207                    || sys::seL4_Word::from_ne_bytes(it.next().unwrap().try_into().unwrap());
208                let id = munch_word();
209                let len = munch_word();
210                sys::seL4_BootInfoHeader { id, len }
211            };
212            let id = BootInfoExtraId::from_sys(header.id);
213            let len = usize::try_from(header.len).unwrap();
214            let content_with_header_start = self.cursor;
215            let content_with_header_end = content_with_header_start + len;
216            self.cursor = content_with_header_end;
217            if let Some(id) = id {
218                return Some(BootInfoExtra {
219                    id,
220                    content_with_header: &self.bootinfo.extra_slice()
221                        [content_with_header_start..content_with_header_end],
222                });
223            }
224        }
225        None
226    }
227}