@@ -63,26 +63,6 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
6363 . into ( ) ;
6464 }
6565
66- fn check_correct_type ( argument : & PatType , ty : & str ) -> Option < TokenStream > {
67- let inv_type_message = format ! ( "argument type must be {ty}" ) ;
68-
69- if !is_correct_type ( & argument. ty , ty) {
70- let error = parse:: Error :: new ( argument. ty . span ( ) , inv_type_message) ;
71-
72- Some ( error. to_compile_error ( ) . into ( ) )
73- } else {
74- None
75- }
76- }
77- fn check_argument_type ( argument : & FnArg , ty : & str ) -> Option < TokenStream > {
78- let argument_error = parse:: Error :: new ( argument. span ( ) , "invalid argument" ) ;
79- let argument_error = argument_error. to_compile_error ( ) . into ( ) ;
80-
81- match argument {
82- FnArg :: Typed ( argument) => check_correct_type ( argument, ty) ,
83- FnArg :: Receiver ( _) => Some ( argument_error) ,
84- }
85- }
8666 #[ cfg( not( feature = "u-boot" ) ) ]
8767 for argument in f. sig . inputs . iter ( ) {
8868 if let Some ( message) = check_argument_type ( argument, "usize" ) {
@@ -181,6 +161,28 @@ fn is_correct_type(ty: &Type, name: &str) -> bool {
181161 }
182162}
183163
164+ fn check_correct_type ( argument : & PatType , ty : & str ) -> Option < TokenStream > {
165+ let inv_type_message = format ! ( "argument type must be {ty}" ) ;
166+
167+ if !is_correct_type ( & argument. ty , ty) {
168+ let error = parse:: Error :: new ( argument. ty . span ( ) , inv_type_message) ;
169+
170+ Some ( error. to_compile_error ( ) . into ( ) )
171+ } else {
172+ None
173+ }
174+ }
175+
176+ fn check_argument_type ( argument : & FnArg , ty : & str ) -> Option < TokenStream > {
177+ let argument_error = parse:: Error :: new ( argument. span ( ) , "invalid argument" ) ;
178+ let argument_error = argument_error. to_compile_error ( ) . into ( ) ;
179+
180+ match argument {
181+ FnArg :: Typed ( argument) => check_correct_type ( argument, ty) ,
182+ FnArg :: Receiver ( _) => Some ( argument_error) ,
183+ }
184+ }
185+
184186/// Attribute to mark which function will be called at the beginning of the reset handler.
185187/// You must enable the `pre_init` feature in the `riscv-rt` crate to use this macro.
186188///
@@ -263,6 +265,93 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
263265 . into ( )
264266}
265267
268+ /// Attribute to mark which function will be called before jumping to the entry point.
269+ /// You must enable the `post-init` feature in the `riscv-rt` crate to use this macro.
270+ ///
271+ /// In contrast with `__pre_init`, this function is called after the static variables
272+ /// are initialized, so it is safe to access them. It is also safe to run Rust code.
273+ ///
274+ /// The function must have the signature of `[unsafe] fn([usize])`, where the argument
275+ /// corresponds to the hart ID of the current hart. This is useful for multi-hart systems
276+ /// to perform hart-specific initialization.
277+ ///
278+ /// # IMPORTANT
279+ ///
280+ /// This attribute can appear at most *once* in the dependency graph.
281+ ///
282+ /// # Examples
283+ ///
284+ /// ```
285+ /// use riscv_rt_macros::post_init;
286+ /// #[post_init]
287+ /// unsafe fn before_main(hart_id: usize) {
288+ /// // do something here
289+ /// }
290+ /// ```
291+ #[ proc_macro_attribute]
292+ pub fn post_init ( args : TokenStream , input : TokenStream ) -> TokenStream {
293+ let f = parse_macro_input ! ( input as ItemFn ) ;
294+
295+ // check the function arguments
296+ if f. sig . inputs . len ( ) > 1 {
297+ return parse:: Error :: new (
298+ f. sig . inputs . last ( ) . unwrap ( ) . span ( ) ,
299+ "`#[post_init]` function has too many arguments" ,
300+ )
301+ . to_compile_error ( )
302+ . into ( ) ;
303+ }
304+ for argument in f. sig . inputs . iter ( ) {
305+ if let Some ( message) = check_argument_type ( argument, "usize" ) {
306+ return message;
307+ } ;
308+ }
309+
310+ // check the function signature
311+ let valid_signature = f. sig . constness . is_none ( )
312+ && f. sig . asyncness . is_none ( )
313+ && f. vis == Visibility :: Inherited
314+ && f. sig . abi . is_none ( )
315+ && f. sig . generics . params . is_empty ( )
316+ && f. sig . generics . where_clause . is_none ( )
317+ && f. sig . variadic . is_none ( )
318+ && match f. sig . output {
319+ ReturnType :: Default => true ,
320+ ReturnType :: Type ( _, ref ty) => match * * ty {
321+ Type :: Tuple ( ref tuple) => tuple. elems . is_empty ( ) ,
322+ _ => false ,
323+ } ,
324+ } ;
325+
326+ if !valid_signature {
327+ return parse:: Error :: new (
328+ f. span ( ) ,
329+ "`#[post_init]` function must have signature `[unsafe] fn([usize])`" ,
330+ )
331+ . to_compile_error ( )
332+ . into ( ) ;
333+ }
334+
335+ if !args. is_empty ( ) {
336+ return parse:: Error :: new ( Span :: call_site ( ) , "This attribute accepts no arguments" )
337+ . to_compile_error ( )
338+ . into ( ) ;
339+ }
340+
341+ // XXX should we blacklist other attributes?
342+ let attrs = f. attrs ;
343+ let ident = f. sig . ident ;
344+ let args = f. sig . inputs ;
345+ let block = f. block ;
346+
347+ quote ! (
348+ #[ export_name = "__post_init" ]
349+ #( #attrs) *
350+ unsafe fn #ident( #args) #block
351+ )
352+ . into ( )
353+ }
354+
266355struct AsmLoopArgs {
267356 asm_template : String ,
268357 count_from : usize ,
0 commit comments