@@ -63,26 +63,6 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
63
63
. into ( ) ;
64
64
}
65
65
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
- }
86
66
#[ cfg( not( feature = "u-boot" ) ) ]
87
67
for argument in f. sig . inputs . iter ( ) {
88
68
if let Some ( message) = check_argument_type ( argument, "usize" ) {
@@ -181,6 +161,28 @@ fn is_correct_type(ty: &Type, name: &str) -> bool {
181
161
}
182
162
}
183
163
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
+
184
186
/// Attribute to mark which function will be called at the beginning of the reset handler.
185
187
/// You must enable the `pre_init` feature in the `riscv-rt` crate to use this macro.
186
188
///
@@ -263,6 +265,93 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
263
265
. into ( )
264
266
}
265
267
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
+
266
355
struct AsmLoopArgs {
267
356
asm_template : String ,
268
357
count_from : usize ,
0 commit comments