blob: 86a3a03c3add8b6d5e70f5315f2465db5b4fbab2 [file] [log] [blame]
Alice Wang81399f52023-05-26 14:23:43 +00001// 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
Michał Mazurekf08509a2025-01-24 11:39:24 +000017pub mod layout;
Bartłomiej Grzesik86f108d2024-11-29 15:48:00 +010018pub mod platform;
19
Alice Wang81399f52023-05-26 14:23:43 +000020/// Reads a value from a system register.
21#[macro_export]
22macro_rules! read_sysreg {
23 ($sysreg:literal) => {{
24 let mut r: usize;
Alice Wang81399f52023-05-26 14:23:43 +000025 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000026 // SAFETY: Reading a system register does not affect memory.
Alice Wang81399f52023-05-26 14:23:43 +000027 unsafe {
28 core::arch::asm!(
29 concat!("mrs {}, ", $sysreg),
30 out(reg) r,
31 options(nomem, nostack, preserves_flags),
32 )
33 }
34 r
35 }};
36}
37
38/// Writes a value to a system register.
39///
40/// # Safety
41///
42/// Callers must ensure that side effects of updating the system register are properly handled.
43#[macro_export]
44macro_rules! write_sysreg {
45 ($sysreg:literal, $val:expr) => {{
46 let value: usize = $val;
47 core::arch::asm!(
48 concat!("msr ", $sysreg, ", {}"),
49 in(reg) value,
50 options(nomem, nostack, preserves_flags),
51 )
52 }};
53}
54
55/// Executes an instruction synchronization barrier.
56#[macro_export]
57macro_rules! isb {
58 () => {{
Alice Wang81399f52023-05-26 14:23:43 +000059 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000060 // SAFETY: memory barriers do not affect Rust's memory model.
Alice Wang81399f52023-05-26 14:23:43 +000061 unsafe {
62 core::arch::asm!("isb", options(nomem, nostack, preserves_flags));
63 }
64 }};
65}
66
67/// Executes a data synchronization barrier.
68#[macro_export]
69macro_rules! dsb {
70 ($option:literal) => {{
Alice Wang81399f52023-05-26 14:23:43 +000071 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000072 // SAFETY: memory barriers do not affect Rust's memory model.
Alice Wang81399f52023-05-26 14:23:43 +000073 unsafe {
74 core::arch::asm!(concat!("dsb ", $option), options(nomem, nostack, preserves_flags));
75 }
76 }};
77}
78
Pierre-Clément Tosi8ab7c372024-10-30 20:46:04 +000079/// Executes a data cache operation.
80#[macro_export]
81macro_rules! dc {
82 ($option:literal, $addr:expr) => {{
83 let addr: usize = $addr;
84 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
85 // SAFETY: Clearing cache lines shouldn't have Rust-visible side effects.
86 unsafe {
87 core::arch::asm!(
88 concat!("dc ", $option, ", {x}"),
89 x = in(reg) addr,
90 options(nomem, nostack, preserves_flags),
91 );
92 }
93 }};
94}
95
Alice Wang81399f52023-05-26 14:23:43 +000096/// Invalidates cached leaf PTE entries by virtual address.
97#[macro_export]
98macro_rules! tlbi {
99 ($option:literal, $asid:expr, $addr:expr) => {{
100 let asid: usize = $asid;
101 let addr: usize = $addr;
Alice Wang81399f52023-05-26 14:23:43 +0000102 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +0000103 // SAFETY: Invalidating the TLB doesn't affect Rust. When the address matches a
104 // block entry larger than the page size, all translations for the block are invalidated.
Alice Wang81399f52023-05-26 14:23:43 +0000105 unsafe {
106 core::arch::asm!(
107 concat!("tlbi ", $option, ", {x}"),
108 x = in(reg) (asid << 48) | (addr >> 12),
109 options(nomem, nostack, preserves_flags)
110 );
111 }
112 }};
113}
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +0100114
Pierre-Clément Tosi043dfb72024-10-30 21:17:10 +0000115/// STRB intrinsics.
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +0100116///
117/// See https://github.com/rust-lang/rust/issues/131894
118///
119/// # Safety
120///
121/// `dst` must be valid for writes.
Pierre-Clément Tosi043dfb72024-10-30 21:17:10 +0000122#[inline]
123pub unsafe fn strb(dst: *mut u8, src: u8) {
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +0100124 // SAFETY: strb only modifies *dst, which must be valid for writes.
125 unsafe {
126 core::arch::asm!(
127 "strb {value:w}, [{ptr}]",
128 value = in(reg) src,
129 ptr = in(reg) dst,
130 options(preserves_flags),
131 );
132 }
133}
Pierre-Clément Tosi8ab7c372024-10-30 20:46:04 +0000134
135/// Reads the number of words in the smallest cache line of all the data caches and unified caches.
136#[inline]
137pub fn min_dcache_line_size() -> usize {
138 const DMINLINE_SHIFT: usize = 16;
139 const DMINLINE_MASK: usize = 0xf;
140 let ctr_el0 = read_sysreg!("ctr_el0");
141
142 // DminLine: log2 of the number of words in the smallest cache line of all the data caches.
143 let dminline = (ctr_el0 >> DMINLINE_SHIFT) & DMINLINE_MASK;
144
145 1 << dminline
146}