Skip to main content

sel4_microkit_base/
symbols.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7use core::str::{self, Utf8Error};
8
9/// Declares a symbol via which the `microkit` tool can inject a variable declared by e.g.
10/// `setvar_vaddr`, and returns the variable's value at runtime.
11///
12/// This macro is represents a lower-level interface than
13/// [`memory_region_symbol`](crate::memory_region_symbol).
14///
15/// The following fragment demonstrates its usage:
16///
17/// ```rust
18/// let my_var: &'static T = var!(my_var_symbol_name: T = MY_DEFAULT_VALUE)
19/// ```
20///
21/// where `MY_DEFAULT_VALUE` is the value that the variable will be given at compile-time, before
22/// the protection domain image is passed to the `microkit` tool.
23///
24/// The patching mechanism used by the `microkit` tool requires that the symbol be allocated space
25/// in the protection domain's ELF file, so we declare the symbol as part of the `.data` section.
26///
27/// For more detail, see this macro's definition.
28///
29/// # Examples
30///
31/// ```rust
32/// let foo = bar + *var!(baz: usize = 0);
33/// ```
34///
35/// # Note
36///
37/// The `microkit` tool requires memory region address symbols to be present in protection domain
38/// binaries. To prevent Rust from optimizing them out in cases where it is not used, add the
39/// unstable `#[used(linker)]` attribute. For example:
40///
41/// ```rust
42/// #![feature(used_with_arg)]
43///
44/// // might be optimized away if not used
45/// memory_region_symbol!(foo: usize = 0)
46///
47/// // won't be optimized away
48/// memory_region_symbol! {
49///     #[used(linker)]
50///     foo: usize = 0
51/// }
52/// ```
53#[macro_export]
54macro_rules! var {
55    ($(#[$attrs:meta])* $symbol:ident: $ty:ty = $default:expr) => {{
56        use $crate::_private::ImmutableCell;
57
58        $(#[$attrs])*
59        #[unsafe(no_mangle)]
60        #[unsafe(link_section = ".data")]
61        static $symbol: ImmutableCell<$ty> = ImmutableCell::new($default);
62
63        $symbol.get()
64    }}
65}
66
67/// Declares a symbol via which the `microkit` tool can inject a memory region's address, and
68/// returns the memory region's address at runtime.
69///
70/// The patching mechanism used by the `microkit` tool requires that the symbol be allocated space
71/// in the protection domain's ELF file, so we declare the symbol as part of the `.data` section.
72///
73/// For more detail, see this macro's definition.
74///
75/// # Examples
76///
77/// ```rust
78/// let region_1 = unsafe {
79///     SharedMemoryRef::<'static, Foo>::new(
80///         memory_region_symbol!(region_1_addr: *mut Foo),
81///     )
82/// };
83///
84/// let region_2 = unsafe {
85///     SharedMemoryRef::<'static, [u8]>::new_read_only(
86///         memory_region_symbol!(region_2_addr: *mut [u8], n = REGION_2_SIZE),
87///     )
88/// };
89/// ```
90///
91/// # Note
92///
93/// The `microkit` tool requires memory region address symbols to be present in protection domain
94/// binaries. To prevent Rust from optimizing them out in cases where it is not used, add the
95/// unstable `#[used(linker)]` attribute. For example:
96///
97/// ```rust
98/// #![feature(used_with_arg)]
99///
100/// // might be optimized away if not used
101/// memory_region_symbol!(region_addr: *mut Foo)
102///
103/// // won't be optimized away
104/// memory_region_symbol! {
105///     #[used(linker)]
106///     region_addr: *mut Foo
107/// }
108/// ```
109#[macro_export]
110macro_rules! memory_region_symbol {
111    ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr, bytes = $bytes:expr $(,)?) => {{
112        assert!($bytes == $n * core::mem::size_of::<$ty>());
113        $crate::memory_region_symbol!($(#[$attrs])* $symbol: *mut $ty, n = $n)
114    }};
115    ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty, bytes = $bytes:expr $(,)?) => {{
116        assert!($bytes == core::mem::size_of::<$ty>());
117        $crate::memory_region_symbol!($(#[$attrs])* $symbol: *mut $ty)
118    }};
119    ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr $(,)?) => {{
120        core::ptr::NonNull::slice_from_raw_parts(
121            $crate::memory_region_symbol!(
122                $(#[$attrs])* $symbol: *mut $ty
123            ),
124            $n,
125        )
126    }};
127    ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty $(,)?) => {{
128        core::ptr::NonNull::new(
129            *$crate::var!($(#[$attrs])* $symbol: usize = 0) as *mut $ty
130        ).unwrap_or_else(|| {
131            panic!("{} is null", stringify!($symbol))
132        })
133    }};
134}
135
136#[cfg(not(feature = "extern-symbols"))]
137macro_rules! maybe_extern_var {
138    ($symbol:ident: $ty:ty = $default:expr) => {{
139        var! {
140            #[used(linker)]
141            $symbol: $ty = $default
142        }
143    }};
144}
145
146#[cfg(feature = "extern-symbols")]
147macro_rules! maybe_extern_var {
148    ($symbol:ident: $ty:ty = $default:expr) => {{
149        unsafe extern "C" {
150            static $symbol: $ty;
151        }
152
153        unsafe { &$symbol }
154    }};
155}
156
157/// Returns whether this protection domain is a passive server.
158pub fn pd_is_passive() -> bool {
159    *maybe_extern_var!(microkit_passive: bool = false)
160}
161
162pub(crate) fn pd_irqs() -> usize {
163    *maybe_extern_var!(microkit_irqs: usize = 0)
164}
165
166pub(crate) fn pd_notifications() -> usize {
167    *maybe_extern_var!(microkit_notifications: usize = 0)
168}
169
170pub(crate) fn pd_pps() -> usize {
171    *maybe_extern_var!(microkit_pps: usize = 0)
172}
173
174#[allow(dead_code)]
175pub(crate) fn pd_ioports() -> usize {
176    *maybe_extern_var!(microkit_ioports: usize = 0)
177}
178
179const PD_NAME_LENGTH: usize = 64;
180
181/// Returns the name of this protection domain without converting to unicode.
182pub fn pd_name_bytes() -> &'static [u8] {
183    let all_bytes = maybe_extern_var!(microkit_name: [u8; PD_NAME_LENGTH] = [0; PD_NAME_LENGTH]);
184    let n = all_bytes.iter().take_while(|b| **b != 0).count();
185    &all_bytes[..n]
186}
187
188/// Returns the name of this protection domain.
189pub fn pd_name() -> Result<&'static str, Utf8Error> {
190    str::from_utf8(pd_name_bytes())
191}