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}