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::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        $(#[$attrs])*
60        #[unsafe(no_mangle)]
61        #[unsafe(link_section = ".data")]
62        static $symbol: ImmutableCell<$ty> = ImmutableCell::new($default);
63
64        $symbol.get()
65    }}
66}
67
68/// Declares a symbol via which the `microkit` tool can inject a memory region's address, and
69/// returns the memory region's address at runtime.
70///
71/// The patching mechanism used by the `microkit` tool requires that the symbol be allocated space
72/// in the protection domain's ELF file, so we declare the symbol as part of the `.data` section.
73///
74/// For more detail, see this macro's definition.
75///
76/// # Examples
77///
78/// ```rust
79/// let region_1 = unsafe {
80///     SharedMemoryRef::<'static, Foo>::new(
81///         memory_region_symbol!(region_1_addr: *mut Foo),
82///     )
83/// };
84///
85/// let region_2 = unsafe {
86///     SharedMemoryRef::<'static, [u8]>::new_read_only(
87///         memory_region_symbol!(region_2_addr: *mut [u8], n = REGION_2_SIZE),
88///     )
89/// };
90/// ```
91///
92/// # Note
93///
94/// The `microkit` tool requires memory region address symbols to be present in protection domain
95/// binaries. To prevent Rust from optimizing them out in cases where it is not used, add the
96/// unstable `#[used(linker)]` attribute. For example:
97///
98/// ```rust
99/// #![feature(used_with_arg)]
100///
101/// // might be optimized away if not used
102/// memory_region_symbol!(region_addr: *mut Foo)
103///
104/// // won't be optimized away
105/// memory_region_symbol! {
106///     #[used(linker)]
107///     region_addr: *mut Foo
108/// }
109/// ```
110#[macro_export]
111macro_rules! memory_region_symbol {
112    ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr, bytes = $bytes:expr $(,)?) => {{
113        assert!($bytes == $n * core::mem::size_of::<$ty>());
114        $crate::memory_region_symbol!($(#[$attrs])* $symbol: *mut $ty, n = $n)
115    }};
116    ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty, bytes = $bytes:expr $(,)?) => {{
117        assert!($bytes == core::mem::size_of::<$ty>());
118        $crate::memory_region_symbol!($(#[$attrs])* $symbol: *mut $ty)
119    }};
120    ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr $(,)?) => {{
121        core::ptr::NonNull::slice_from_raw_parts(
122            $crate::memory_region_symbol!(
123                $(#[$attrs])* $symbol: *mut $ty
124            ),
125            $n,
126        )
127    }};
128    ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty $(,)?) => {{
129        core::ptr::NonNull::new(
130            *$crate::var!($(#[$attrs])* $symbol: usize = 0) as *mut $ty
131        ).unwrap_or_else(|| {
132            panic!("{} is null", stringify!($symbol))
133        })
134    }};
135}
136
137#[cfg(not(feature = "extern-symbols"))]
138macro_rules! maybe_extern_var {
139    ($symbol:ident: $ty:ty = $default:expr) => {{
140        var! {
141            #[used(linker)]
142            $symbol: $ty = $default
143        }
144    }};
145}
146
147#[cfg(feature = "extern-symbols")]
148macro_rules! maybe_extern_var {
149    ($symbol:ident: $ty:ty = $default:expr) => {{
150        unsafe extern "C" {
151            static $symbol: $ty;
152        }
153
154        unsafe { &$symbol }
155    }};
156}
157
158/// Returns whether this protection domain is a passive server.
159pub fn pd_is_passive() -> bool {
160    *maybe_extern_var!(microkit_passive: bool = false)
161}
162
163pub(crate) fn pd_irqs() -> usize {
164    *maybe_extern_var!(microkit_irqs: usize = 0)
165}
166
167pub(crate) fn pd_notifications() -> usize {
168    *maybe_extern_var!(microkit_notifications: usize = 0)
169}
170
171pub(crate) fn pd_pps() -> usize {
172    *maybe_extern_var!(microkit_pps: usize = 0)
173}
174
175#[allow(dead_code)]
176pub(crate) fn pd_ioports() -> usize {
177    *maybe_extern_var!(microkit_ioports: 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    unsafe 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}