1use std::ops::Deref;
2
3use darling::{FromMeta, ast::NestedMeta};
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{
7 ItemFn, Token,
8 parse::{Parse, ParseStream},
9 parse_macro_input,
10};
11
12mod trap;
13
14struct Asm(Vec<String>);
15
16impl From<String> for Asm {
17 fn from(value: String) -> Self {
18 Asm(value
19 .lines()
20 .map(|line| line.trim().to_string())
21 .filter(|o| !o.is_empty())
22 .collect())
23 }
24}
25
26impl Deref for Asm {
27 type Target = Vec<String>;
28
29 fn deref(&self) -> &Self::Target {
30 &self.0
31 }
32}
33
34fn dcache_line_size(reg: &str, tmp: &str) -> Asm {
35 format!(
36 "
37 mrs {tmp}, ctr_el0
38 ubfm {tmp}, {tmp}, #16, #19
39 mov {reg}, #4
40 lsl {reg}, {reg}, {tmp}"
41 )
42 .into()
43}
44
45struct DCacheMacroArgs {
46 section: Option<syn::LitStr>,
47}
48impl Parse for DCacheMacroArgs {
49 fn parse(input: ParseStream) -> syn::Result<Self> {
50 let mut section = None;
51
52 while !input.is_empty() {
53 let ident: syn::Ident = input.parse()?;
54 if ident == "section" {
55 input.parse::<Token![=]>()?;
56 let value: syn::LitStr = input.parse()?;
57 section = Some(value);
58 } else {
59 return Err(input.error("Unknown argument"));
60 }
61
62 if !input.is_empty() {
63 input.parse::<Token![,]>()?;
64 }
65 }
66
67 Ok(Self { section })
68 }
69}
70
71struct AdrLArgs {
72 reg: syn::Ident,
73 symbol: syn::LitStr,
74}
75
76impl Parse for AdrLArgs {
77 fn parse(input: ParseStream) -> syn::Result<Self> {
78 let reg: syn::Ident = input.parse()?;
79 input.parse::<Token![,]>()?;
80 let symbol: syn::LitStr = input.parse()?;
81 Ok(Self { reg, symbol })
82 }
83}
84#[proc_macro]
86pub fn def_dcache_inval_poc(input: TokenStream) -> TokenStream {
87 let args = parse_macro_input!(input as DCacheMacroArgs);
88
89 let section = args
91 .section
92 .map_or_else(|| String::from(".text"), |lit| lit.value());
93
94 let dcache_line_size = dcache_line_size("x2", "x3");
95
96 quote! {
97 #[unsafe(naked)]
104 #[unsafe(link_section = #section)]
105 pub unsafe extern "C" fn __dcache_inval_poc(_start: usize, _end: usize) {
106 core::arch::naked_asm!(
107 #(#dcache_line_size),*,
108"sub x3, x2, #1
109 tst x1, x3 // end cache line aligned?
110 bic x1, x1, x3
111 b.eq 1f
112 dc civac, x1 // clean & invalidate D / U line
1131: tst x0, x3 // start cache line aligned?
114 bic x0, x0, x3
115 b.eq 2f
116 dc civac, x0 // clean & invalidate D / U line
117 b 3f
1182: dc ivac, x0 // invalidate D / U line
1193: add x0, x0, x2
120 cmp x0, x1
121 b.lo 2b
122 dsb sy
123 ret"
124 )
125 }
126 }
127 .into()
128}
129
130#[proc_macro]
131pub fn adr_l(input: TokenStream) -> TokenStream {
132 let input = parse_macro_input!(input as AdrLArgs);
133 let reg = input.reg.to_string();
134 let symbol = input.symbol.value();
135
136 let combined = format!("adrp {reg}, {symbol}\n add {reg}, {reg}, :lo12:{symbol}");
137
138 quote! {
139 #combined
140 }
141 .into()
142}
143
144#[proc_macro]
145pub fn define_tcb_switch(_input: TokenStream) -> TokenStream {
146 let fp = trap::tcb_switch(true);
147 let sp = trap::tcb_switch(false);
148
149 quote! {
150 #[cfg(hard_float)]
151 #fp
152
153 #[cfg(not(hard_float))]
154 #sp
155 }
156 .into()
157}
158
159#[derive(Debug, Clone, Copy, FromMeta)]
162#[darling(default)]
163enum Aarch64TrapHandlerKind {
164 Irq,
165 Fiq,
166 Sync,
167 #[darling(rename = "serror")]
168 SError,
169}
170
171#[derive(Debug, FromMeta)]
172struct Aarch64TrapHandlerArgs {
173 kind: Aarch64TrapHandlerKind,
174}
175
176#[proc_macro_attribute]
177pub fn aarch64_trap_handler(args: TokenStream, input: TokenStream) -> TokenStream {
178 let attr_args = match NestedMeta::parse_meta_list(args.into()) {
179 Ok(v) => v,
180 Err(e) => {
181 return TokenStream::from(darling::Error::from(e).write_errors());
182 }
183 };
184 let args = match Aarch64TrapHandlerArgs::from_list(&attr_args) {
185 Ok(v) => v,
186 Err(e) => {
187 return TokenStream::from(e.write_errors());
188 }
189 };
190
191 let func = parse_macro_input!(input as ItemFn);
192
193 match args.kind {
194 Aarch64TrapHandlerKind::Irq | Aarch64TrapHandlerKind::Fiq => {
195 trap::trap_handle_irq(func).into()
196 }
197 Aarch64TrapHandlerKind::Sync => trap::trap_handle_irq(func).into(),
198 Aarch64TrapHandlerKind::SError => trap::trap_handle_irq(func).into(),
199 }
200}