hermit/
macros.rs

1/// Prints to the standard output.
2///
3/// Adapted from [`std::print`].
4///
5/// [`std::print`]: https://doc.rust-lang.org/stable/std/macro.print.html
6#[cfg(target_os = "none")]
7#[macro_export]
8macro_rules! print {
9    ($($arg:tt)*) => {{
10        $crate::console::_print(::core::format_args!($($arg)*));
11    }};
12}
13
14/// Prints to the standard output, with a newline.
15///
16/// Adapted from [`std::println`].
17///
18/// [`std::println`]: https://doc.rust-lang.org/stable/std/macro.println.html
19#[cfg(target_os = "none")]
20#[macro_export]
21macro_rules! println {
22    () => {
23        $crate::print!("\n")
24    };
25    ($($arg:tt)*) => {{
26        $crate::console::_print(::core::format_args!("{}\n", format_args!($($arg)*)));
27    }};
28}
29
30/// Emergency output.
31#[cfg(target_os = "none")]
32#[macro_export]
33macro_rules! panic_println {
34    () => {{
35        $crate::console::_panic_print(::core::format_args!("\n"));
36    }};
37    ($($arg:tt)*) => {{
38        $crate::console::_panic_print(::core::format_args!("{}\n", format_args!($($arg)*)));
39    }};
40}
41
42#[cfg(not(target_os = "none"))]
43#[macro_export]
44macro_rules! panic_println {
45    ($($arg:tt)*) => {
46        println!($($arg)*);
47    };
48}
49
50/// Prints and returns the value of a given expression for quick and dirty
51/// debugging.
52// Copied from std/macros.rs
53#[cfg(target_os = "none")]
54#[macro_export]
55macro_rules! dbg {
56    // NOTE: We cannot use `concat!` to make a static string as a format argument
57    // of `eprintln!` because `file!` could contain a `{` or
58    // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
59    // will be malformed.
60    () => {
61        $crate::println!("[{}:{}]", ::core::file!(), ::core::line!())
62    };
63    ($val:expr $(,)?) => {
64        // Use of `match` here is intentional because it affects the lifetimes
65        // of temporaries - https://stackoverflow.com/a/48732525/1063961
66        match $val {
67            tmp => {
68                $crate::println!("[{}:{}] {} = {:#?}",
69                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
70                tmp
71            }
72        }
73    };
74    ($($val:expr),+ $(,)?) => {
75        ($($crate::dbg!($val)),+,)
76    };
77}
78
79/// Runs `f` on the kernel stack.
80///
81/// All arguments and return values have to fit into registers:
82///
83/// ```
84/// assert!(mem::size_of::<T>() <= mem::size_of::<usize>());
85/// ```
86///
87/// When working with bigger types, manually route the data over pointers:
88///
89/// ```
90/// f(&arg1, &mut ret);
91/// // instead of
92/// let ret = f(arg);
93/// ```
94#[allow(unused_macro_rules)]
95#[cfg(not(any(
96	target_arch = "riscv64",
97	all(target_arch = "x86_64", feature = "newlib"),
98	feature = "common-os"
99)))]
100macro_rules! kernel_function {
101	($f:ident()) => {{
102		use $crate::errno::ToErrno;
103
104		// This propagates any unsafety requirements of `f` to the caller.
105		if false {
106			$f();
107		}
108
109		#[allow(unreachable_code)]
110		#[allow(unused_unsafe)]
111		unsafe {
112			$crate::arch::switch::kernel_function0($f).set_errno()
113		}
114	}};
115
116	($f:ident($arg1:expr)) => {{
117		use $crate::errno::ToErrno;
118
119		// This propagates any unsafety requirements of `f` to the caller.
120		if false {
121			$f($arg1);
122		}
123
124		#[allow(unreachable_code)]
125		#[allow(unused_unsafe)]
126		unsafe {
127			$crate::arch::switch::kernel_function1($f, $arg1).set_errno()
128		}
129	}};
130
131	($f:ident($arg1:expr, $arg2:expr)) => {{
132		use $crate::errno::ToErrno;
133
134		// This propagates any unsafety requirements of `f` to the caller.
135		if false {
136			$f($arg1, $arg2);
137		}
138
139		#[allow(unreachable_code)]
140		#[allow(unused_unsafe)]
141		unsafe {
142			$crate::arch::switch::kernel_function2($f, $arg1, $arg2).set_errno()
143		}
144	}};
145
146	($f:ident($arg1:expr, $arg2:expr, $arg3:expr)) => {{
147		use $crate::errno::ToErrno;
148
149		// This propagates any unsafety requirements of `f` to the caller.
150		if false {
151			$f($arg1, $arg2, $arg3);
152		}
153
154		#[allow(unreachable_code)]
155		#[allow(unused_unsafe)]
156		unsafe {
157			$crate::arch::switch::kernel_function3($f, $arg1, $arg2, $arg3).set_errno()
158		}
159	}};
160
161	($f:ident($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr)) => {{
162		use $crate::errno::ToErrno;
163
164		// This propagates any unsafety requirements of `f` to the caller.
165		if false {
166			$f($arg1, $arg2, $arg3, $arg4);
167		}
168
169		#[allow(unreachable_code)]
170		#[allow(unused_unsafe)]
171		unsafe {
172			$crate::arch::switch::kernel_function4($f, $arg1, $arg2, $arg3, $arg4).set_errno()
173		}
174	}};
175
176	($f:ident($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr)) => {{
177		use $crate::errno::ToErrno;
178
179		// This propagates any unsafety requirements of `f` to the caller.
180		if false {
181			$f($arg1, $arg2, $arg3, $arg4, $arg5);
182		}
183
184		#[allow(unreachable_code)]
185		#[allow(unused_unsafe)]
186		unsafe {
187			$crate::arch::switch::kernel_function5($f, $arg1, $arg2, $arg3, $arg4, $arg5)
188				.set_errno()
189		}
190	}};
191
192	($f:ident($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr)) => {{
193		use $crate::errno::ToErrno;
194
195		// This propagates any unsafety requirements of `f` to the caller.
196		if false {
197			$f($arg1, $arg2, $arg3, $arg4, $arg5, $arg6);
198		}
199
200		#[allow(unreachable_code)]
201		#[allow(unused_unsafe)]
202		unsafe {
203			$crate::arch::switch::kernel_function6($f, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6)
204				.set_errno()
205		}
206	}};
207}
208
209// TODO: Properly switch kernel stack with newlib
210// https://github.com/hermit-os/kernel/issues/471
211// TODO: Switch kernel stack on RISC-V
212#[cfg(any(
213	target_arch = "riscv64",
214	all(target_arch = "x86_64", feature = "newlib"),
215	feature = "common-os"
216))]
217macro_rules! kernel_function {
218	($f:ident($($x:tt)*)) => {{
219		use $crate::errno::ToErrno;
220		#[allow(unreachable_code)]
221		$f($($x)*).set_errno()
222	}};
223}
224
225/// Returns the value of the specified environment variable.
226///
227/// The value is fetched from the current runtime environment and, if not
228/// present, falls back to the same environment variable set at compile time
229/// (might not be present as well).
230#[allow(unused_macros)]
231macro_rules! hermit_var {
232	($name:expr) => {{
233		use alloc::borrow::Cow;
234
235		match crate::env::var($name) {
236			Some(val) => Some(Cow::from(val)),
237			None => option_env!($name).map(Cow::Borrowed),
238		}
239	}};
240}
241
242/// Tries to fetch the specified environment variable with a default value.
243///
244/// Fetches according to [`hermit_var`] or returns the specified default value.
245#[allow(unused_macros)]
246macro_rules! hermit_var_or {
247	($name:expr, $default:expr) => {
248		hermit_var!($name).as_deref().unwrap_or($default)
249	};
250}