• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 pub mod dbm;
18 pub mod exceptions;
19 pub mod hvc;
20 pub mod layout;
21 pub mod linker;
22 pub mod page_table;
23 pub mod platform;
24 pub mod rand;
25 pub mod uart;
26 
27 /// Reads a value from a system register.
28 #[macro_export]
29 macro_rules! read_sysreg {
30     ($sysreg:literal) => {{
31         let mut r: usize;
32         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
33         // SAFETY: Reading a system register does not affect memory.
34         unsafe {
35             core::arch::asm!(
36                 concat!("mrs {}, ", $sysreg),
37                 out(reg) r,
38                 options(nomem, nostack, preserves_flags),
39             )
40         }
41         r
42     }};
43 }
44 
45 /// Writes a value to a system register.
46 ///
47 /// # Safety
48 ///
49 /// Callers must ensure that side effects of updating the system register are properly handled.
50 #[macro_export]
51 macro_rules! write_sysreg {
52     ($sysreg:literal, $val:expr) => {{
53         let value: usize = $val;
54         core::arch::asm!(
55             concat!("msr ", $sysreg, ", {}"),
56             in(reg) value,
57             options(nomem, nostack, preserves_flags),
58         )
59     }};
60 }
61 
62 /// Executes an instruction synchronization barrier.
63 #[macro_export]
64 macro_rules! isb {
65     () => {{
66         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
67         // SAFETY: memory barriers do not affect Rust's memory model.
68         unsafe {
69             core::arch::asm!("isb", options(nomem, nostack, preserves_flags));
70         }
71     }};
72 }
73 
74 /// Executes a data synchronization barrier.
75 #[macro_export]
76 macro_rules! dsb {
77     ($option:literal) => {{
78         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
79         // SAFETY: memory barriers do not affect Rust's memory model.
80         unsafe {
81             core::arch::asm!(concat!("dsb ", $option), options(nomem, nostack, preserves_flags));
82         }
83     }};
84 }
85 
86 /// Executes a data cache operation.
87 #[macro_export]
88 macro_rules! dc {
89     ($option:literal, $addr:expr) => {{
90         let addr: usize = $addr;
91         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
92         // SAFETY: Clearing cache lines shouldn't have Rust-visible side effects.
93         unsafe {
94             core::arch::asm!(
95                 concat!("dc ", $option, ", {x}"),
96                 x = in(reg) addr,
97                 options(nomem, nostack, preserves_flags),
98             );
99         }
100     }};
101 }
102 
103 /// Invalidates cached leaf PTE entries by virtual address.
104 #[macro_export]
105 macro_rules! tlbi {
106     ($option:literal, $asid:expr, $addr:expr) => {{
107         let asid: usize = $asid;
108         let addr: usize = $addr;
109         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
110         // SAFETY: Invalidating the TLB doesn't affect Rust. When the address matches a
111         // block entry larger than the page size, all translations for the block are invalidated.
112         unsafe {
113             core::arch::asm!(
114                 concat!("tlbi ", $option, ", {x}"),
115                 x = in(reg) (asid << 48) | (addr >> 12),
116                 options(nomem, nostack, preserves_flags)
117             );
118         }
119     }};
120 }
121 
122 /// Reads the number of words in the smallest cache line of all the data caches and unified caches.
123 #[inline]
min_dcache_line_size() -> usize124 pub fn min_dcache_line_size() -> usize {
125     const DMINLINE_SHIFT: usize = 16;
126     const DMINLINE_MASK: usize = 0xf;
127     let ctr_el0 = read_sysreg!("ctr_el0");
128 
129     // DminLine: log2 of the number of words in the smallest cache line of all the data caches.
130     let dminline = (ctr_el0 >> DMINLINE_SHIFT) & DMINLINE_MASK;
131 
132     1 << dminline
133 }
134