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