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 && p.qself.is_none()
128 && p.path.leading_colon.is_none()
129 && p.path.segments.len() == 1
130 {
131 let segment = p.path.segments.first().unwrap();
132 if segment.ident == name && segment.arguments == PathArguments::None {
133 return true;
134 }
135 }
136 false
137}
138
139const NAMESPACE: &str = "sparreal_os";
140
141#[proc_macro_attribute]
142pub fn api_trait(_args: TokenStream, item: TokenStream) -> TokenStream {
143 abi_singleton::api_trait(item, NAMESPACE)
144}
145
146#[proc_macro_attribute]
147pub fn api_impl(_args: TokenStream, item: TokenStream) -> TokenStream {
148 abi_singleton::api_impl(item, NAMESPACE)
149}
150
151#[proc_macro]
152pub fn build_test_setup(_input: TokenStream) -> TokenStream {
153 quote! {
154 println!("cargo::rustc-link-arg-tests=-Tlink.x");
155 println!("cargo::rustc-link-arg-tests=-no-pie");
156 println!("cargo::rustc-link-arg-tests=-znostart-stop-gc");
157 }
158 .into()
159}
160
161#[proc_macro]
162pub fn define_aarch64_tcb_switch(_input: TokenStream) -> TokenStream {
163 let fp = arch::aarch64::tcb_switch(true);
164 let sp = arch::aarch64::tcb_switch(false);
165
166 quote! {
167 #[cfg(hard_float)]
168 #fp
169
170 #[cfg(not(hard_float))]
171 #sp
172 }
173 .into()
174}
175
176#[derive(Debug, Clone, Copy, FromMeta)]
179#[darling(default)]
180enum Aarch64TrapHandlerKind {
181 Irq,
182 Fiq,
183 Sync,
184 #[darling(rename = "serror")]
185 SError,
186}
187
188#[derive(Debug, FromMeta)]
189struct Aarch64TrapHandlerArgs {
190 kind: Aarch64TrapHandlerKind,
191}
192
193#[proc_macro_attribute]
194pub fn aarch64_trap_handler(args: TokenStream, input: TokenStream) -> TokenStream {
195 let attr_args = match NestedMeta::parse_meta_list(args.into()) {
196 Ok(v) => v,
197 Err(e) => {
198 return TokenStream::from(darling::Error::from(e).write_errors());
199 }
200 };
201 let args = match Aarch64TrapHandlerArgs::from_list(&attr_args) {
202 Ok(v) => v,
203 Err(e) => {
204 return TokenStream::from(e.write_errors());
205 }
206 };
207
208 let func = parse_macro_input!(input as ItemFn);
209
210 match args.kind {
211 Aarch64TrapHandlerKind::Irq | Aarch64TrapHandlerKind::Fiq => {
212 arch::aarch64::trap_handle_irq(func).into()
213 }
214 Aarch64TrapHandlerKind::Sync => arch::aarch64::trap_handle_irq(func).into(),
215 Aarch64TrapHandlerKind::SError => arch::aarch64::trap_handle_irq(func).into(),
216 }
217}