Skip to main content

kasm_aarch64/
lib.rs

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///`pub fn __dcache_inval_poc(_start: usize, _end: usize)`
85#[proc_macro]
86pub fn def_dcache_inval_poc(input: TokenStream) -> TokenStream {
87    let args = parse_macro_input!(input as DCacheMacroArgs);
88
89    // 默认 section 名称
90    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    /// 确保 [start, end) 区间内的 D-cache 行被无效化。区间两端的非对齐 cache line 也会被清理以防止数据丢失。
98    ///
99    /// # 参数
100    ///
101    /// - `start`: 要操作区域的起始地址(内核虚拟地址)
102    /// - `end`: 要操作区域的结束地址(内核虚拟地址)
103    #[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/// A speaking volume. Deriving `FromMeta` will cause this to be usable
160/// as a string value for a meta-item key.
161#[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}