blob: 992ab274f2de331f220558b164b7084e735b8da8 [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
17/// Reads a value from a system register.
18#[macro_export]
19macro_rules! read_sysreg {
20 ($sysreg:literal) => {{
21 let mut r: usize;
Alice Wang81399f52023-05-26 14:23:43 +000022 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000023 // SAFETY: Reading a system register does not affect memory.
Alice Wang81399f52023-05-26 14:23:43 +000024 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]
41macro_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]
54macro_rules! isb {
55 () => {{
Alice Wang81399f52023-05-26 14:23:43 +000056 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000057 // SAFETY: memory barriers do not affect Rust's memory model.
Alice Wang81399f52023-05-26 14:23:43 +000058 unsafe {
59 core::arch::asm!("isb", options(nomem, nostack, preserves_flags));
60 }
61 }};
62}
63
64/// Executes a data synchronization barrier.
65#[macro_export]
66macro_rules! dsb {
67 ($option:literal) => {{
Alice Wang81399f52023-05-26 14:23:43 +000068 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000069 // SAFETY: memory barriers do not affect Rust's memory model.
Alice Wang81399f52023-05-26 14:23:43 +000070 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]
78macro_rules! tlbi {
79 ($option:literal, $asid:expr, $addr:expr) => {{
80 let asid: usize = $asid;
81 let addr: usize = $addr;
Alice Wang81399f52023-05-26 14:23:43 +000082 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000083 // 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.
Alice Wang81399f52023-05-26 14:23:43 +000085 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}
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +010094
95/// Write with well-defined compiled behavior.
96///
97/// See https://github.com/rust-lang/rust/issues/131894
98///
99/// # Safety
100///
101/// `dst` must be valid for writes.
102pub unsafe fn write_volatile_u8(dst: *mut u8, src: u8) {
103 // SAFETY: strb only modifies *dst, which must be valid for writes.
104 unsafe {
105 core::arch::asm!(
106 "strb {value:w}, [{ptr}]",
107 value = in(reg) src,
108 ptr = in(reg) dst,
109 options(preserves_flags),
110 );
111 }
112}