sel4_microkit_base/
symbols.rs

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