blob: 9c4d2569fc56e0a78d26a84e6995276546c0f885 [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ł Mazurek747c08d2024-11-29 13:26:22 +010018pub mod exceptions;
Michał Mazurek3a9ecbf2024-11-29 13:09:12 +010019pub mod hvc;
Michał Mazurekf08509a2025-01-24 11:39:24 +000020pub mod layout;
Michał Mazurek6cd065f2024-11-29 13:07:11 +010021pub mod linker;
Michał Mazurek5b294692024-11-29 13:05:46 +010022pub mod page_table;
Bartłomiej Grzesik86f108d2024-11-29 15:48:00 +010023pub mod platform;
Bartłomiej Grzesikee0a5c62025-02-04 09:06:17 +000024pub mod rand;
Bartłomiej Grzesik3d7fccf2025-01-30 15:10:01 +000025pub mod uart;
Bartłomiej Grzesik86f108d2024-11-29 15:48:00 +010026
Alice Wang81399f52023-05-26 14:23:43 +000027/// Reads a value from a system register.
28#[macro_export]
29macro_rules! read_sysreg {
30 ($sysreg:literal) => {{
31 let mut r: usize;
Alice Wang81399f52023-05-26 14:23:43 +000032 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000033 // SAFETY: Reading a system register does not affect memory.
Alice Wang81399f52023-05-26 14:23:43 +000034 unsafe {
35 core::arch::asm!(
36 concat!("mrs {}, ", $sysreg),
37 out(reg) r,
38 options(nomem, nostack, preserves_flags),
39 )
40 }
41 r
42 }};
43}
44
45/// Writes a value to a system register.
46///
47/// # Safety
48///
49/// Callers must ensure that side effects of updating the system register are properly handled.
50#[macro_export]
51macro_rules! write_sysreg {
52 ($sysreg:literal, $val:expr) => {{
53 let value: usize = $val;
54 core::arch::asm!(
55 concat!("msr ", $sysreg, ", {}"),
56 in(reg) value,
57 options(nomem, nostack, preserves_flags),
58 )
59 }};
60}
61
62/// Executes an instruction synchronization barrier.
63#[macro_export]
64macro_rules! isb {
65 () => {{
Alice Wang81399f52023-05-26 14:23:43 +000066 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000067 // SAFETY: memory barriers do not affect Rust's memory model.
Alice Wang81399f52023-05-26 14:23:43 +000068 unsafe {
69 core::arch::asm!("isb", options(nomem, nostack, preserves_flags));
70 }
71 }};
72}
73
74/// Executes a data synchronization barrier.
75#[macro_export]
76macro_rules! dsb {
77 ($option:literal) => {{
Alice Wang81399f52023-05-26 14:23:43 +000078 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +000079 // SAFETY: memory barriers do not affect Rust's memory model.
Alice Wang81399f52023-05-26 14:23:43 +000080 unsafe {
81 core::arch::asm!(concat!("dsb ", $option), options(nomem, nostack, preserves_flags));
82 }
83 }};
84}
85
Pierre-Clément Tosi8ab7c372024-10-30 20:46:04 +000086/// Executes a data cache operation.
87#[macro_export]
88macro_rules! dc {
89 ($option:literal, $addr:expr) => {{
90 let addr: usize = $addr;
91 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
92 // SAFETY: Clearing cache lines shouldn't have Rust-visible side effects.
93 unsafe {
94 core::arch::asm!(
95 concat!("dc ", $option, ", {x}"),
96 x = in(reg) addr,
97 options(nomem, nostack, preserves_flags),
98 );
99 }
100 }};
101}
102
Alice Wang81399f52023-05-26 14:23:43 +0000103/// Invalidates cached leaf PTE entries by virtual address.
104#[macro_export]
105macro_rules! tlbi {
106 ($option:literal, $asid:expr, $addr:expr) => {{
107 let asid: usize = $asid;
108 let addr: usize = $addr;
Alice Wang81399f52023-05-26 14:23:43 +0000109 #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
Andrew Walbranc06e7342023-07-05 14:00:51 +0000110 // SAFETY: Invalidating the TLB doesn't affect Rust. When the address matches a
111 // block entry larger than the page size, all translations for the block are invalidated.
Alice Wang81399f52023-05-26 14:23:43 +0000112 unsafe {
113 core::arch::asm!(
114 concat!("tlbi ", $option, ", {x}"),
115 x = in(reg) (asid << 48) | (addr >> 12),
116 options(nomem, nostack, preserves_flags)
117 );
118 }
119 }};
120}
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +0100121
Pierre-Clément Tosi043dfb72024-10-30 21:17:10 +0000122/// STRB intrinsics.
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +0100123///
124/// See https://github.com/rust-lang/rust/issues/131894
125///
126/// # Safety
127///
128/// `dst` must be valid for writes.
Pierre-Clément Tosi043dfb72024-10-30 21:17:10 +0000129#[inline]
130pub unsafe fn strb(dst: *mut u8, src: u8) {
Pierre-Clément Tosi4ec3a932024-10-08 18:10:25 +0100131 // SAFETY: strb only modifies *dst, which must be valid for writes.
132 unsafe {
133 core::arch::asm!(
134 "strb {value:w}, [{ptr}]",
135 value = in(reg) src,
136 ptr = in(reg) dst,
137 options(preserves_flags),
138 );
139 }
140}
Pierre-Clément Tosi8ab7c372024-10-30 20:46:04 +0000141
142/// Reads the number of words in the smallest cache line of all the data caches and unified caches.
143#[inline]
144pub fn min_dcache_line_size() -> usize {
145 const DMINLINE_SHIFT: usize = 16;
146 const DMINLINE_MASK: usize = 0xf;
147 let ctr_el0 = read_sysreg!("ctr_el0");
148
149 // DminLine: log2 of the number of words in the smallest cache line of all the data caches.
150 let dminline = (ctr_el0 >> DMINLINE_SHIFT) & DMINLINE_MASK;
151
152 1 << dminline
153}