1extern crate proc_macro;
2#[macro_use]
3extern crate quote;
4extern crate core;
5extern crate proc_macro2;
6#[macro_use]
7extern crate syn;
8
9mod api_trait;
10mod arch;
11
12use darling::{FromMeta, ast::NestedMeta};
13use proc_macro::TokenStream;
14use proc_macro2::Span;
15use syn::{FnArg, ItemFn, PathArguments, Type, Visibility, parse, spanned::Spanned};
16
17#[proc_macro_attribute]
49pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
50 let f = parse_macro_input!(input as ItemFn);
51
52 if f.sig.inputs.len() > 3 {
54 return parse::Error::new(
55 f.sig.inputs.last().unwrap().span(),
56 "`#[entry]` function has too many arguments",
57 )
58 .to_compile_error()
59 .into();
60 }
61 for arg in &f.sig.inputs {
62 match arg {
63 FnArg::Receiver(_) => {
64 return parse::Error::new(arg.span(), "invalid argument")
65 .to_compile_error()
66 .into();
67 }
68 FnArg::Typed(t) => {
69 if !is_simple_type(&t.ty, "usize") {
70 return parse::Error::new(t.ty.span(), "argument type must be usize")
71 .to_compile_error()
72 .into();
73 }
74 }
75 }
76 }
77
78 let valid_signature = f.sig.constness.is_none()
80 && f.sig.asyncness.is_none()
81 && f.vis == Visibility::Inherited
82 && f.sig.abi.is_none()
83 && f.sig.generics.params.is_empty()
84 && f.sig.generics.where_clause.is_none()
85 && f.sig.variadic.is_none()
86 ;
91
92 if !valid_signature {
93 return parse::Error::new(
94 f.span(),
95 "`#[entry]` function must have signature `[unsafe] fn([arg0: usize, ...]) `",
96 )
97 .to_compile_error()
98 .into();
99 }
100
101 if !args.is_empty() {
102 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
103 .to_compile_error()
104 .into();
105 }
106
107 let attrs = f.attrs;
109 let unsafety = f.sig.unsafety;
110 let args = f.sig.inputs;
111 let stmts = f.block.stmts;
112
113 quote!(
114 #[allow(non_snake_case)]
115 #[unsafe(no_mangle)]
116 #(#attrs)*
117 pub #unsafety extern "C" fn __sparreal_rt_main(#args) {
118 #(#stmts)*
119 }
120 )
121 .into()
122}
123
124#[allow(unused)]
125fn is_simple_type(ty: &Type, name: &str) -> bool {
126 if let Type::Path(p) = ty {
127 if p.qself.is_none() && p.path.leading_colon.is_none() && p.path.segments.len() == 1 {
128 let segment = p.path.segments.first().unwrap();
129 if segment.ident == name && segment.arguments == PathArguments::None {
130 return true;
131 }
132 }
133 }
134 false
135}
136
137const NAMESPACE: &str = "sparreal_os";
138
139#[proc_macro_attribute]
140pub fn api_trait(_args: TokenStream, item: TokenStream) -> TokenStream {
141 abi_singleton::api_trait(item, NAMESPACE)
142}
143
144#[proc_macro_attribute]
145pub fn api_impl(_args: TokenStream, item: TokenStream) -> TokenStream {
146 abi_singleton::api_impl(item, NAMESPACE)
147}
148
149#[proc_macro]
150pub fn build_test_setup(_input: TokenStream) -> TokenStream {
151 quote! {
152 println!("cargo::rustc-link-arg-tests=-Tlink.x");
153 println!("cargo::rustc-link-arg-tests=-no-pie");
154 println!("cargo::rustc-link-arg-tests=-znostart-stop-gc");
155 }
156 .into()
157}
158
159#[proc_macro]
160pub fn module_driver(input: TokenStream) -> TokenStream {
161 rdrive_macro_utils::module_driver_with_linker(input, "sparreal_kernel::driver")
162}
163
164#[proc_macro]
165pub fn define_aarch64_tcb_switch(_input: TokenStream) -> TokenStream {
166 let fp = arch::aarch64::tcb_switch(true);
167 let sp = arch::aarch64::tcb_switch(false);
168
169 quote! {
170 #[cfg(hard_float)]
171 #fp
172
173 #[cfg(not(hard_float))]
174 #sp
175 }
176 .into()
177}
178
179#[derive(Debug, Clone, Copy, FromMeta)]
182#[darling(default)]
183enum Aarch64TrapHandlerKind {
184 Irq,
185 Fiq,
186 Sync,
187 #[darling(rename = "serror")]
188 SError,
189}
190
191#[derive(Debug, FromMeta)]
192struct Aarch64TrapHandlerArgs {
193 kind: Aarch64TrapHandlerKind,
194}
195
196#[proc_macro_attribute]
197pub fn aarch64_trap_handler(args: TokenStream, input: TokenStream) -> TokenStream {
198 let attr_args = match NestedMeta::parse_meta_list(args.into()) {
199 Ok(v) => v,
200 Err(e) => {
201 return TokenStream::from(darling::Error::from(e).write_errors());
202 }
203 };
204 let args = match Aarch64TrapHandlerArgs::from_list(&attr_args) {
205 Ok(v) => v,
206 Err(e) => {
207 return TokenStream::from(e.write_errors());
208 }
209 };
210
211 let func = parse_macro_input!(input as ItemFn);
212
213 match args.kind {
214 Aarch64TrapHandlerKind::Irq | Aarch64TrapHandlerKind::Fiq => {
215 arch::aarch64::trap_handle_irq(func).into()
216 }
217 Aarch64TrapHandlerKind::Sync => arch::aarch64::trap_handle_irq(func).into(),
218 Aarch64TrapHandlerKind::SError => arch::aarch64::trap_handle_irq(func).into(),
219 }
220}