Skip to main content

islet_rmm/
asm.rs

1use core::arch::asm;
2
3pub const SMC_SUCCESS: usize = 0;
4#[cfg(any(kani, miri, test, fuzzing))]
5pub const SMC_ERROR: usize = 1;
6
7pub fn smc(cmd: usize, args: &[usize]) -> [usize; 8] {
8    let mut ret: [usize; 8] = [0usize; 8];
9    let mut padded_args: [usize; 8] = [0usize; 8];
10    let start = 1;
11    let end = start + args.len();
12
13    if end > ret.len() - 1 {
14        // TODO: need a more graceful way to return error value (Result?)
15        error!("{} arguments exceed the current limit of smc call. Please try assigning more registers to smc", args.len());
16        return ret;
17    }
18
19    let put = |arr: &mut [usize; 8]| {
20        arr[0] = cmd;
21        arr[start..end].copy_from_slice(args);
22    };
23    put(&mut ret);
24    put(&mut padded_args);
25    #[cfg(any(kani, miri, test, fuzzing))]
26    if cmd == crate::rmi::gpt::MARK_REALM {
27        use crate::get_granule;
28        use crate::granule::entry::GranuleGpt;
29        let addr = args[0];
30        let gpt = get_granule!(addr).map(|guard| guard.gpt).unwrap();
31        if gpt != GranuleGpt::GPT_NS {
32            ret[0] = SMC_ERROR;
33        } else {
34            let _ = get_granule!(addr).map(|mut guard| guard.set_gpt(GranuleGpt::GPT_REALM));
35            ret[0] = SMC_SUCCESS;
36        }
37    } else if cmd == crate::rmi::gpt::MARK_NONSECURE {
38        use crate::get_granule;
39        use crate::granule::entry::GranuleGpt;
40        let addr = args[0];
41        let is_valid = get_granule!(addr).map(|guard| guard.is_valid()).unwrap();
42        assert!(is_valid);
43        let gpt = get_granule!(addr).map(|guard| guard.gpt).unwrap();
44        if gpt != GranuleGpt::GPT_REALM {
45            ret[0] = SMC_ERROR;
46        } else {
47            let _ = get_granule!(addr).map(|mut guard| guard.set_gpt(GranuleGpt::GPT_NS));
48            ret[0] = SMC_SUCCESS;
49        }
50    }
51
52    // TODO: support more number of registers than 8 if needed
53    #[cfg(not(any(kani, miri, test, fuzzing)))]
54    unsafe {
55        asm!(
56            "smc #0x0",
57            inlateout("x0") padded_args[0] => ret[0],
58            inlateout("x1") padded_args[1] => ret[1],
59            inlateout("x2") padded_args[2] => ret[2],
60            inlateout("x3") padded_args[3] => ret[3],
61            inlateout("x4") padded_args[4] => ret[4],
62            inlateout("x5") padded_args[5] => ret[5],
63            inlateout("x6") padded_args[6] => ret[6],
64            inlateout("x7") padded_args[7] => ret[7],
65        )
66    }
67
68    ret
69}
70
71#[inline(always)]
72pub fn dcache_flush(addr: usize, len: usize) {
73    let mut cur_addr = addr;
74    let addr_end = addr + len;
75    unsafe {
76        while cur_addr < addr_end {
77            asm!("dc civac, {}", in(reg) cur_addr);
78            asm!("dsb ish");
79            asm!("isb");
80            cur_addr += 64; // the cache line size is 64
81        }
82    }
83}
84
85#[inline(always)]
86pub fn isb() {
87    #[cfg(target_arch = "aarch64")]
88    unsafe {
89        core::arch::asm!("isb", options(nomem, nostack))
90    }
91
92    #[cfg(not(target_arch = "aarch64"))]
93    unimplemented!()
94}