lib.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #![deny(warnings)]
  2. extern crate proc_macro;
  3. extern crate rand;
  4. #[macro_use]
  5. extern crate quote;
  6. extern crate core;
  7. extern crate proc_macro2;
  8. #[macro_use]
  9. extern crate syn;
  10. use proc_macro2::Span;
  11. use rand::Rng;
  12. use rand::SeedableRng;
  13. use std::sync::atomic::{AtomicUsize, Ordering};
  14. use std::time::{SystemTime, UNIX_EPOCH};
  15. use syn::{
  16. parse, spanned::Spanned, Ident, ItemFn, ReturnType, Type, Visibility,
  17. };
  18. static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
  19. use proc_macro::TokenStream;
  20. /// Attribute to declare the entry point of the program
  21. ///
  22. /// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
  23. /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
  24. /// private modules between the item and the root of the crate); if the item is in the root of the
  25. /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases.
  26. ///
  27. /// The specified function will be called by the reset handler *after* RAM has been initialized.
  28. /// If present, the FPU will also be enabled before the function is called.
  29. ///
  30. /// The type of the specified function must be `[unsafe] fn() -> !` (never ending function)
  31. ///
  32. /// # Properties
  33. ///
  34. /// The entry point will be called by the reset handler. The program can't reference to the entry
  35. /// point, much less invoke it.
  36. ///
  37. /// # Examples
  38. ///
  39. /// - Simple entry point
  40. ///
  41. /// ``` no_run
  42. /// # #![no_main]
  43. /// # use riscv_rt_macros::entry;
  44. /// #[entry]
  45. /// fn main() -> ! {
  46. /// loop {
  47. /// /* .. */
  48. /// }
  49. /// }
  50. /// ```
  51. #[proc_macro_attribute]
  52. pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
  53. let f = parse_macro_input!(input as ItemFn);
  54. // check the function signature
  55. let valid_signature = f.constness.is_none()
  56. && f.vis == Visibility::Inherited
  57. && f.abi.is_none()
  58. && f.decl.inputs.is_empty()
  59. && f.decl.generics.params.is_empty()
  60. && f.decl.generics.where_clause.is_none()
  61. && f.decl.variadic.is_none()
  62. && match f.decl.output {
  63. ReturnType::Default => false,
  64. ReturnType::Type(_, ref ty) => match **ty {
  65. Type::Never(_) => true,
  66. _ => false,
  67. },
  68. };
  69. if !valid_signature {
  70. return parse::Error::new(
  71. f.span(),
  72. "`#[entry]` function must have signature `[unsafe] fn() -> !`",
  73. )
  74. .to_compile_error()
  75. .into();
  76. }
  77. if !args.is_empty() {
  78. return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
  79. .to_compile_error()
  80. .into();
  81. }
  82. // XXX should we blacklist other attributes?
  83. let attrs = f.attrs;
  84. let unsafety = f.unsafety;
  85. let hash = random_ident();
  86. let stmts = f.block.stmts;
  87. quote!(
  88. #[export_name = "main"]
  89. #(#attrs)*
  90. pub #unsafety fn #hash() -> ! {
  91. #(#stmts)*
  92. }
  93. )
  94. .into()
  95. }
  96. /// Attribute to mark which function will be called at the beginning of the reset handler.
  97. ///
  98. /// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you
  99. /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
  100. /// private modules between the item and the root of the crate); if the item is in the root of the
  101. /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer
  102. /// releases.
  103. ///
  104. /// The function must have the signature of `unsafe fn()`.
  105. ///
  106. /// The function passed will be called before static variables are initialized. Any access of static
  107. /// variables will result in undefined behavior.
  108. ///
  109. /// # Examples
  110. ///
  111. /// ```
  112. /// # use riscv_rt_macros::pre_init;
  113. /// #[pre_init]
  114. /// unsafe fn before_main() {
  115. /// // do something here
  116. /// }
  117. ///
  118. /// # fn main() {}
  119. /// ```
  120. #[proc_macro_attribute]
  121. pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
  122. let f = parse_macro_input!(input as ItemFn);
  123. // check the function signature
  124. let valid_signature = f.constness.is_none()
  125. && f.vis == Visibility::Inherited
  126. && f.unsafety.is_some()
  127. && f.abi.is_none()
  128. && f.decl.inputs.is_empty()
  129. && f.decl.generics.params.is_empty()
  130. && f.decl.generics.where_clause.is_none()
  131. && f.decl.variadic.is_none()
  132. && match f.decl.output {
  133. ReturnType::Default => true,
  134. ReturnType::Type(_, ref ty) => match **ty {
  135. Type::Tuple(ref tuple) => tuple.elems.is_empty(),
  136. _ => false,
  137. },
  138. };
  139. if !valid_signature {
  140. return parse::Error::new(
  141. f.span(),
  142. "`#[pre_init]` function must have signature `unsafe fn()`",
  143. )
  144. .to_compile_error()
  145. .into();
  146. }
  147. if !args.is_empty() {
  148. return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
  149. .to_compile_error()
  150. .into();
  151. }
  152. // XXX should we blacklist other attributes?
  153. let attrs = f.attrs;
  154. let ident = f.ident;
  155. let block = f.block;
  156. quote!(
  157. #[export_name = "__pre_init"]
  158. #(#attrs)*
  159. pub unsafe fn #ident() #block
  160. )
  161. .into()
  162. }
  163. // Creates a random identifier
  164. fn random_ident() -> Ident {
  165. let secs = SystemTime::now()
  166. .duration_since(UNIX_EPOCH)
  167. .unwrap()
  168. .as_secs();
  169. let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
  170. let mut seed: [u8; 16] = [0; 16];
  171. for (i, v) in seed.iter_mut().take(8).enumerate() {
  172. *v = ((secs >> (i * 8)) & 0xFF) as u8
  173. }
  174. for (i, v) in seed.iter_mut().skip(8).enumerate() {
  175. *v = ((count >> (i * 8)) & 0xFF) as u8
  176. }
  177. let mut rng = rand::rngs::SmallRng::from_seed(seed);
  178. Ident::new(
  179. &(0..16)
  180. .map(|i| {
  181. if i == 0 || rng.gen() {
  182. ('a' as u8 + rng.gen::<u8>() % 25) as char
  183. } else {
  184. ('0' as u8 + rng.gen::<u8>() % 10) as char
  185. }
  186. })
  187. .collect::<String>(),
  188. Span::call_site(),
  189. )
  190. }