lib.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. extern crate proc_macro;
  2. use proc_macro2::{Span, TokenStream};
  3. use quote::quote;
  4. use syn::{parse2, FnArg, Ident, ItemFn, LitStr};
  5. fn define_syscall_impl(attrs: TokenStream, item: TokenStream) -> TokenStream {
  6. if attrs.is_empty() {
  7. panic!("`define_syscall` attribute should take one argument: `syscall_no`");
  8. }
  9. let syscall_no = parse2::<Ident>(attrs).expect("Invalid syscall number");
  10. let item = parse2::<ItemFn>(item).unwrap();
  11. let attrs = item.attrs;
  12. let vis = item.vis;
  13. let args = item.sig.inputs.iter();
  14. let ty_ret = item.sig.output;
  15. assert!(
  16. item.sig.asyncness.is_some(),
  17. "Syscall must be async function"
  18. );
  19. let args_mapped = item
  20. .sig
  21. .inputs
  22. .iter()
  23. .enumerate()
  24. .map(|(idx, arg)| match arg {
  25. FnArg::Receiver(_) => panic!("&self is not permitted."),
  26. FnArg::Typed(arg) => {
  27. let arg_ident = Ident::new(&format!("arg_{}", idx), Span::call_site());
  28. let arg_ty = &arg.ty;
  29. quote! { let #arg_ident: #arg_ty = <#arg_ty>::from_arg(args[#idx]); }
  30. }
  31. });
  32. let args_call = item
  33. .sig
  34. .inputs
  35. .iter()
  36. .enumerate()
  37. .map(|(idx, arg)| match arg {
  38. FnArg::Receiver(_) => panic!("&self is not permitted."),
  39. FnArg::Typed(_) => {
  40. let arg_ident = Ident::new(&format!("arg_{}", idx), Span::call_site());
  41. quote! { #arg_ident }
  42. }
  43. });
  44. let syscall_name = item.sig.ident;
  45. let syscall_name_str = LitStr::new(&syscall_name.to_string(), Span::call_site());
  46. let body = item.block;
  47. let helper_fn = Ident::new(&format!("_do_syscall_{}", syscall_name), Span::call_site());
  48. let helper_fn_pointer = Ident::new(
  49. &format!("_SYSCALL_ENTRY_{}", syscall_name.to_string().to_uppercase()),
  50. Span::call_site(),
  51. );
  52. let real_fn = Ident::new(&format!("sys_{}", syscall_name), Span::call_site());
  53. let raw_syscall_section = LitStr::new(
  54. &format!(".raw_syscalls.{}", syscall_name),
  55. Span::call_site(),
  56. );
  57. let syscall_fn_section =
  58. LitStr::new(&format!(".syscall_fns.{}", syscall_name), Span::call_site());
  59. let trace_format_string = {
  60. let arg_count = item.sig.inputs.len();
  61. let brackets = (0..arg_count)
  62. .map(|_| String::from("{:x?}"))
  63. .collect::<Vec<_>>()
  64. .join(", ");
  65. LitStr::new(&brackets, Span::call_site())
  66. };
  67. let trace_format_args = {
  68. let args = item.sig.inputs.iter();
  69. let args = args.enumerate().map(|(idx, arg)| match arg {
  70. FnArg::Receiver(_) => panic!("&self is not permitted."),
  71. FnArg::Typed(_) => {
  72. let arg_ident = Ident::new(&format!("arg_{}", idx), Span::call_site());
  73. quote! { #arg_ident }
  74. }
  75. });
  76. quote! { #(#args,)* }
  77. };
  78. quote! {
  79. #[used]
  80. #[doc(hidden)]
  81. #[no_mangle]
  82. #[link_section = #raw_syscall_section]
  83. static #helper_fn_pointer: crate::kernel::syscall::RawSyscallHandler =
  84. crate::kernel::syscall::RawSyscallHandler {
  85. no: #syscall_no,
  86. handler: #helper_fn,
  87. name: #syscall_name_str,
  88. };
  89. #[link_section = #syscall_fn_section]
  90. fn #helper_fn <'thd, 'alloc>(
  91. thd: &'thd crate::kernel::task::Thread,
  92. thd_alloc: crate::kernel::task::ThreadAlloc<'alloc>,
  93. args: [usize; 6]
  94. ) -> core::pin::Pin<Box<
  95. dyn core::future::Future<Output = Option<usize>> + Send + 'thd,
  96. crate::kernel::task::ThreadAlloc<'alloc>
  97. >> {
  98. use crate::kernel::syscall::{FromSyscallArg, SyscallRetVal};
  99. use alloc::boxed::Box;
  100. #(#args_mapped)*
  101. unsafe {
  102. core::pin::Pin::new_unchecked(
  103. Box::new_in(
  104. async move {
  105. eonix_log::println_trace!(
  106. feat: "trace_syscall",
  107. "tid{}: {}({}) => {{",
  108. thd.tid,
  109. #syscall_name_str,
  110. format_args!(#trace_format_string, #trace_format_args),
  111. );
  112. let retval = #real_fn(thd, #(#args_call),*).await.into_retval();
  113. eonix_log::println_trace!(
  114. feat: "trace_syscall",
  115. "}} => {:x?}",
  116. retval,
  117. );
  118. retval
  119. },
  120. thd_alloc
  121. )
  122. )
  123. }
  124. }
  125. #(#attrs)*
  126. #[link_section = #syscall_fn_section]
  127. #vis async fn #real_fn(
  128. thread: &crate::kernel::task::Thread,
  129. #(#args),*
  130. ) #ty_ret #body
  131. }
  132. }
  133. /// Define a syscall used by the kernel. The syscall handler will be generated in the
  134. /// `.syscalls` section and then linked into the kernel binary.
  135. ///
  136. /// One hidden parameter will be passed to the syscall handler:
  137. /// - `thread: &Thread`
  138. ///
  139. /// The arguments of the syscall MUST implement `FromSyscallArg` trait and the return value
  140. /// types MUST implement `SyscallRetVal` trait.
  141. ///
  142. /// # Usage
  143. /// ```no_run
  144. /// # use eonix_macros::define_syscall;
  145. /// #[define_syscall]
  146. /// fn read(fd: u32, buf: *mut u8, count: u32) -> u32
  147. /// {
  148. /// /* ... */
  149. /// }
  150. /// ```
  151. #[proc_macro_attribute]
  152. pub fn define_syscall(
  153. attrs: proc_macro::TokenStream,
  154. item: proc_macro::TokenStream,
  155. ) -> proc_macro::TokenStream {
  156. define_syscall_impl(attrs.into(), item.into()).into()
  157. }