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