lib.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. extern crate proc_macro;
  2. use proc_macro2::{Span, TokenStream};
  3. use quote::quote;
  4. use syn::{parse2, FnArg, Ident, ItemFn, LitInt, 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::<LitInt>(attrs).expect("Invalid syscall number");
  10. let syscall_no = syscall_no
  11. .base10_parse::<usize>()
  12. .expect("Invalid syscall number");
  13. assert!(syscall_no < 512, "Syscall number must be less than 512");
  14. let item = parse2::<ItemFn>(item).unwrap();
  15. let attrs = item.attrs;
  16. let vis = item.vis;
  17. let args = item.sig.inputs.iter();
  18. let ty_ret = item.sig.output;
  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_{:03}", syscall_no),
  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. quote! {
  60. #[used]
  61. #[doc(hidden)]
  62. #[no_mangle]
  63. #[link_section = #raw_syscall_section]
  64. static #helper_fn_pointer: crate::kernel::syscall::RawSyscallHandler =
  65. crate::kernel::syscall::RawSyscallHandler {
  66. no: #syscall_no,
  67. handler: #helper_fn,
  68. name: #syscall_name_str,
  69. };
  70. #[link_section = #syscall_fn_section]
  71. fn #helper_fn (
  72. thd: &crate::kernel::task::Thread,
  73. args: [usize; 6]
  74. ) -> Option<usize> {
  75. use crate::kernel::syscall::{FromSyscallArg, SyscallRetVal};
  76. #(#args_mapped)*
  77. // eonix_log::println_trace!(
  78. // "trace_syscall",
  79. // "tid{}: {}({}) => {{",
  80. // crate::kernel::task::Thread::current().tid,
  81. // #syscall_name_str,
  82. // crate::kernel::syscall::format_expand!($($arg, $arg),*),
  83. // );
  84. let retval = #real_fn(thd, #(#args_call),*).into_retval();
  85. // eonix_log::println_trace!(
  86. // "trace_syscall",
  87. // "tid{}: {}({}) => {{",
  88. // crate::kernel::task::Thread::current().tid,
  89. // #syscall_name_str,
  90. // crate::kernel::syscall::format_expand!($($arg, $arg),*),
  91. // );
  92. retval
  93. }
  94. #(#attrs)*
  95. #[link_section = #syscall_fn_section]
  96. #vis fn #real_fn(
  97. thread: &crate::kernel::task::Thread,
  98. #(#args),*
  99. ) #ty_ret #body
  100. }
  101. }
  102. /// Define a syscall used by the kernel. The syscall handler will be generated in the
  103. /// `.syscalls` section and then linked into the kernel binary.
  104. ///
  105. /// One hidden parameter will be passed to the syscall handler:
  106. /// - `thread: &Thread`
  107. ///
  108. /// The arguments of the syscall MUST implement `FromSyscallArg` trait and the return value
  109. /// types MUST implement `SyscallRetVal` trait.
  110. ///
  111. /// # Usage
  112. /// ```no_run
  113. /// # use eonix_macros::define_syscall;
  114. /// #[define_syscall]
  115. /// fn read(fd: u32, buf: *mut u8, count: u32) -> u32
  116. /// {
  117. /// /* ... */
  118. /// }
  119. /// ```
  120. #[proc_macro_attribute]
  121. pub fn define_syscall(
  122. attrs: proc_macro::TokenStream,
  123. item: proc_macro::TokenStream,
  124. ) -> proc_macro::TokenStream {
  125. define_syscall_impl(attrs.into(), item.into()).into()
  126. }