1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Wrappers of assembly calls.
16 
17 /// Reads a value from a system register.
18 #[macro_export]
19 macro_rules! read_sysreg {
20     ($sysreg:literal) => {{
21         let mut r: usize;
22         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
23         // SAFETY: Reading a system register does not affect memory.
24         unsafe {
25             core::arch::asm!(
26                 concat!("mrs {}, ", $sysreg),
27                 out(reg) r,
28                 options(nomem, nostack, preserves_flags),
29             )
30         }
31         r
32     }};
33 }
34 
35 /// Writes a value to a system register.
36 ///
37 /// # Safety
38 ///
39 /// Callers must ensure that side effects of updating the system register are properly handled.
40 #[macro_export]
41 macro_rules! write_sysreg {
42     ($sysreg:literal, $val:expr) => {{
43         let value: usize = $val;
44         core::arch::asm!(
45             concat!("msr ", $sysreg, ", {}"),
46             in(reg) value,
47             options(nomem, nostack, preserves_flags),
48         )
49     }};
50 }
51 
52 /// Executes an instruction synchronization barrier.
53 #[macro_export]
54 macro_rules! isb {
55     () => {{
56         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
57         // SAFETY: memory barriers do not affect Rust's memory model.
58         unsafe {
59             core::arch::asm!("isb", options(nomem, nostack, preserves_flags));
60         }
61     }};
62 }
63 
64 /// Executes a data synchronization barrier.
65 #[macro_export]
66 macro_rules! dsb {
67     ($option:literal) => {{
68         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
69         // SAFETY: memory barriers do not affect Rust's memory model.
70         unsafe {
71             core::arch::asm!(concat!("dsb ", $option), options(nomem, nostack, preserves_flags));
72         }
73     }};
74 }
75 
76 /// Invalidates cached leaf PTE entries by virtual address.
77 #[macro_export]
78 macro_rules! tlbi {
79     ($option:literal, $asid:expr, $addr:expr) => {{
80         let asid: usize = $asid;
81         let addr: usize = $addr;
82         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
83         // SAFETY: Invalidating the TLB doesn't affect Rust. When the address matches a
84         // block entry larger than the page size, all translations for the block are invalidated.
85         unsafe {
86             core::arch::asm!(
87                 concat!("tlbi ", $option, ", {x}"),
88                 x = in(reg) (asid << 48) | (addr >> 12),
89                 options(nomem, nostack, preserves_flags)
90             );
91         }
92     }};
93 }
94