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 /// Executes a data cache operation.
77 #[macro_export]
78 macro_rules! dc {
79 ($option:literal, $addr:expr) => {{
80 let addr: usize = $addr;
81 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
82 // SAFETY: Clearing cache lines shouldn't have Rust-visible side effects.
83 unsafe {
84 core::arch::asm!(
85 concat!("dc ", $option, ", {x}"),
86 x = in(reg) addr,
87 options(nomem, nostack, preserves_flags),
88 );
89 }
90 }};
91 }
92
93 /// Invalidates cached leaf PTE entries by virtual address.
94 #[macro_export]
95 macro_rules! tlbi {
96 ($option:literal, $asid:expr, $addr:expr) => {{
97 let asid: usize = $asid;
98 let addr: usize = $addr;
99 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
100 // SAFETY: Invalidating the TLB doesn't affect Rust. When the address matches a
101 // block entry larger than the page size, all translations for the block are invalidated.
102 unsafe {
103 core::arch::asm!(
104 concat!("tlbi ", $option, ", {x}"),
105 x = in(reg) (asid << 48) | (addr >> 12),
106 options(nomem, nostack, preserves_flags)
107 );
108 }
109 }};
110 }
111
112 /// STRB intrinsics.
113 ///
114 /// See https://github.com/rust-lang/rust/issues/131894
115 ///
116 /// # Safety
117 ///
118 /// `dst` must be valid for writes.
119 #[inline]
strb(dst: *mut u8, src: u8)120 pub unsafe fn strb(dst: *mut u8, src: u8) {
121 // SAFETY: strb only modifies *dst, which must be valid for writes.
122 unsafe {
123 core::arch::asm!(
124 "strb {value:w}, [{ptr}]",
125 value = in(reg) src,
126 ptr = in(reg) dst,
127 options(preserves_flags),
128 );
129 }
130 }
131
132 /// Reads the number of words in the smallest cache line of all the data caches and unified caches.
133 #[inline]
min_dcache_line_size() -> usize134 pub fn min_dcache_line_size() -> usize {
135 const DMINLINE_SHIFT: usize = 16;
136 const DMINLINE_MASK: usize = 0xf;
137 let ctr_el0 = read_sysreg!("ctr_el0");
138
139 // DminLine: log2 of the number of words in the smallest cache line of all the data caches.
140 let dminline = (ctr_el0 >> DMINLINE_SHIFT) & DMINLINE_MASK;
141
142 1 << dminline
143 }
144