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