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}