Skip to content

Commit 988b2e6

Browse files
committed
Add TLBI (TLB Invalidate) instruction wrappers
Add safe wrappers for AArch64 TLBI system instructions at EL1, following the existing pattern established by barrier.rs. Covered instructions: - VMALLE1 / VMALLE1IS — invalidate all EL1&0 TLB entries - VAE1 / VAE1IS — invalidate by VA (with ASID) - VALE1 / VALE1IS — invalidate by VA, last level only - VAAE1 / VAAE1IS — invalidate by VA, all ASIDs - VAALE1 / VAALE1IS — invalidate by VA, all ASIDs, last level - ASIDE1 / ASIDE1IS — invalidate by ASID Each wrapper includes documentation with operand encoding details per Arm ARM §C5.5 / §D8.10. Signed-off-by: ZhiHong Niu <z.h.niu@outlook.com> Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
1 parent 5e4403c commit 988b2e6

File tree

4 files changed

+385
-0
lines changed

4 files changed

+385
-0
lines changed
Binary file not shown.

lib.rmeta

10.7 MB
Binary file not shown.

src/asm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
pub mod barrier;
1212
pub mod random;
13+
pub mod tlbi;
1314

1415
/// The classic no-op
1516
#[inline(always)]

src/asm/tlbi.rs

Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Copyright (c) 2018-2026 by the author(s)
4+
//
5+
// Author(s):
6+
// - ZhiHong Niu <zhihong@nzhnb.com>
7+
8+
//! TLB Invalidate (TLBI) instructions.
9+
//!
10+
//! Provides Rust wrappers around AArch64 TLBI system instructions for
11+
//! invalidating TLB entries at EL1. All functions are `unsafe` and require
12+
//! the caller to uphold the documented safety requirements.
13+
//!
14+
//! # Operand Encoding
15+
//!
16+
//! For address-based TLBI operations (`vae1`, `vale1`, `vaae1`, `vaale1`),
17+
//! the `u64` operand is encoded as specified in the Arm ARM:
18+
//!
19+
//! - Bits \[55:48\]: ASID (for non-"AA" variants)
20+
//! - Bits \[43:0\]: VA\[55:12\] (the virtual address shifted right by 12)
21+
//!
22+
//! It is the caller's responsibility to construct the operand correctly.
23+
//!
24+
//! # References
25+
//!
26+
//! - [Arm ARM §C5.5 - A64 system instructions for TLB maintenance](https://developer.arm.com/documentation/ddi0487/latest)
27+
//! - [Arm ARM §D8.10 - TLB maintenance instructions](https://developer.arm.com/documentation/ddi0487/latest)
28+
//!
29+
//! # Example
30+
//!
31+
//! ```no_run
32+
//! use aarch64_cpu::asm::{barrier, tlbi};
33+
//!
34+
//! // Invalidate all EL1&0 regime TLB entries.
35+
//! // A DSB before ensures prior stores to page tables are visible;
36+
//! // a DSB+ISB after ensures the invalidation completes before
37+
//! // subsequent memory accesses.
38+
//! unsafe {
39+
//! barrier::dsb(barrier::SY);
40+
//! tlbi::vmalle1();
41+
//! barrier::dsb(barrier::SY);
42+
//! barrier::isb(barrier::SY);
43+
//! }
44+
//!
45+
//! // Invalidate by VA: encode operand as VA[55:12] | (ASID << 48).
46+
//! let vaddr: u64 = 0x8000_0000;
47+
//! let asid: u64 = 1;
48+
//! let operand = (vaddr >> 12) | (asid << 48);
49+
//! unsafe {
50+
//! barrier::dsb(barrier::SY);
51+
//! tlbi::vae1(operand);
52+
//! barrier::dsb(barrier::SY);
53+
//! barrier::isb(barrier::SY);
54+
//! }
55+
//! ```
56+
57+
/// Invalidate all EL1&0 regime TLB entries in the current VMID.
58+
///
59+
/// Executes `TLBI VMALLE1`.
60+
///
61+
/// # Safety
62+
///
63+
/// This is a privileged instruction that requires EL1 or higher.
64+
/// The caller must ensure that it is appropriate to invalidate all
65+
/// TLB entries at this point, and must perform the required
66+
/// DSB/ISB synchronization (see [`barrier`](super::barrier)).
67+
#[inline(always)]
68+
pub unsafe fn vmalle1() {
69+
match () {
70+
#[cfg(target_arch = "aarch64")]
71+
() => core::arch::asm!("TLBI VMALLE1", options(nostack)),
72+
73+
#[cfg(not(target_arch = "aarch64"))]
74+
() => unimplemented!(),
75+
}
76+
}
77+
78+
/// Invalidate all EL1&0 regime TLB entries in the current VMID
79+
/// on all PEs in the same Inner Shareable domain.
80+
///
81+
/// Executes `TLBI VMALLE1IS`.
82+
///
83+
/// # Safety
84+
///
85+
/// This is a privileged instruction that requires EL1 or higher.
86+
/// The caller must ensure that it is appropriate to broadcast a
87+
/// TLB invalidation to other PEs, and must perform the required
88+
/// DSB/ISB synchronization (see [`barrier`](super::barrier)).
89+
#[inline(always)]
90+
pub unsafe fn vmalle1is() {
91+
match () {
92+
#[cfg(target_arch = "aarch64")]
93+
() => core::arch::asm!("TLBI VMALLE1IS", options(nostack)),
94+
95+
#[cfg(not(target_arch = "aarch64"))]
96+
() => unimplemented!(),
97+
}
98+
}
99+
100+
/// Invalidate TLB entries by VA, EL1&0, current VMID.
101+
///
102+
/// Executes `TLBI VAE1, <Xt>`.
103+
///
104+
/// # Operand Encoding
105+
///
106+
/// - Bits \[55:48\]: ASID
107+
/// - Bits \[43:0\]: VA\[55:12\]
108+
///
109+
/// # Safety
110+
///
111+
/// This is a privileged instruction that requires EL1 or higher.
112+
/// The caller must provide a correctly encoded operand and perform
113+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
114+
#[inline(always)]
115+
pub unsafe fn vae1(val: u64) {
116+
match () {
117+
#[cfg(target_arch = "aarch64")]
118+
() => core::arch::asm!("TLBI VAE1, {v}", v = in(reg) val, options(nostack)),
119+
120+
#[cfg(not(target_arch = "aarch64"))]
121+
() => {
122+
let _ = val;
123+
unimplemented!()
124+
}
125+
}
126+
}
127+
128+
/// Invalidate TLB entries by VA, EL1&0, current VMID,
129+
/// Inner Shareable.
130+
///
131+
/// Executes `TLBI VAE1IS, <Xt>`.
132+
///
133+
/// # Operand Encoding
134+
///
135+
/// - Bits \[55:48\]: ASID
136+
/// - Bits \[43:0\]: VA\[55:12\]
137+
///
138+
/// # Safety
139+
///
140+
/// This is a privileged instruction that requires EL1 or higher.
141+
/// The caller must provide a correctly encoded operand and perform
142+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
143+
#[inline(always)]
144+
pub unsafe fn vae1is(val: u64) {
145+
match () {
146+
#[cfg(target_arch = "aarch64")]
147+
() => core::arch::asm!("TLBI VAE1IS, {v}", v = in(reg) val, options(nostack)),
148+
149+
#[cfg(not(target_arch = "aarch64"))]
150+
() => {
151+
let _ = val;
152+
unimplemented!()
153+
}
154+
}
155+
}
156+
157+
/// Invalidate TLB entries by VA, last level, EL1&0, current VMID.
158+
///
159+
/// Executes `TLBI VALE1, <Xt>`.
160+
///
161+
/// Only invalidates entries from the last level of the translation
162+
/// table walk (leaf entries), which can be more efficient than `vae1`
163+
/// when intermediate entries are known to be unaffected.
164+
///
165+
/// # Operand Encoding
166+
///
167+
/// - Bits \[55:48\]: ASID
168+
/// - Bits \[43:0\]: VA\[55:12\]
169+
///
170+
/// # Safety
171+
///
172+
/// This is a privileged instruction that requires EL1 or higher.
173+
/// The caller must provide a correctly encoded operand and perform
174+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
175+
#[inline(always)]
176+
pub unsafe fn vale1(val: u64) {
177+
match () {
178+
#[cfg(target_arch = "aarch64")]
179+
() => core::arch::asm!("TLBI VALE1, {v}", v = in(reg) val, options(nostack)),
180+
181+
#[cfg(not(target_arch = "aarch64"))]
182+
() => {
183+
let _ = val;
184+
unimplemented!()
185+
}
186+
}
187+
}
188+
189+
/// Invalidate TLB entries by VA, last level, EL1&0, current VMID,
190+
/// Inner Shareable.
191+
///
192+
/// Executes `TLBI VALE1IS, <Xt>`.
193+
///
194+
/// # Operand Encoding
195+
///
196+
/// - Bits \[55:48\]: ASID
197+
/// - Bits \[43:0\]: VA\[55:12\]
198+
///
199+
/// # Safety
200+
///
201+
/// This is a privileged instruction that requires EL1 or higher.
202+
/// The caller must provide a correctly encoded operand and perform
203+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
204+
#[inline(always)]
205+
pub unsafe fn vale1is(val: u64) {
206+
match () {
207+
#[cfg(target_arch = "aarch64")]
208+
() => core::arch::asm!("TLBI VALE1IS, {v}", v = in(reg) val, options(nostack)),
209+
210+
#[cfg(not(target_arch = "aarch64"))]
211+
() => {
212+
let _ = val;
213+
unimplemented!()
214+
}
215+
}
216+
}
217+
218+
/// Invalidate TLB entries by VA, all ASIDs, EL1&0, current VMID.
219+
///
220+
/// Executes `TLBI VAAE1, <Xt>`.
221+
///
222+
/// Invalidates entries matching the VA regardless of ASID.
223+
///
224+
/// # Operand Encoding
225+
///
226+
/// - Bits \[43:0\]: VA\[55:12\]
227+
///
228+
/// # Safety
229+
///
230+
/// This is a privileged instruction that requires EL1 or higher.
231+
/// The caller must provide a correctly encoded operand and perform
232+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
233+
#[inline(always)]
234+
pub unsafe fn vaae1(val: u64) {
235+
match () {
236+
#[cfg(target_arch = "aarch64")]
237+
() => core::arch::asm!("TLBI VAAE1, {v}", v = in(reg) val, options(nostack)),
238+
239+
#[cfg(not(target_arch = "aarch64"))]
240+
() => {
241+
let _ = val;
242+
unimplemented!()
243+
}
244+
}
245+
}
246+
247+
/// Invalidate TLB entries by VA, all ASIDs, EL1&0, current VMID,
248+
/// Inner Shareable.
249+
///
250+
/// Executes `TLBI VAAE1IS, <Xt>`.
251+
///
252+
/// # Operand Encoding
253+
///
254+
/// - Bits \[43:0\]: VA\[55:12\]
255+
///
256+
/// # Safety
257+
///
258+
/// This is a privileged instruction that requires EL1 or higher.
259+
/// The caller must provide a correctly encoded operand and perform
260+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
261+
#[inline(always)]
262+
pub unsafe fn vaae1is(val: u64) {
263+
match () {
264+
#[cfg(target_arch = "aarch64")]
265+
() => core::arch::asm!("TLBI VAAE1IS, {v}", v = in(reg) val, options(nostack)),
266+
267+
#[cfg(not(target_arch = "aarch64"))]
268+
() => {
269+
let _ = val;
270+
unimplemented!()
271+
}
272+
}
273+
}
274+
275+
/// Invalidate TLB entries by VA, all ASIDs, last level, EL1&0,
276+
/// current VMID.
277+
///
278+
/// Executes `TLBI VAALE1, <Xt>`.
279+
///
280+
/// # Operand Encoding
281+
///
282+
/// - Bits \[43:0\]: VA\[55:12\]
283+
///
284+
/// # Safety
285+
///
286+
/// This is a privileged instruction that requires EL1 or higher.
287+
/// The caller must provide a correctly encoded operand and perform
288+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
289+
#[inline(always)]
290+
pub unsafe fn vaale1(val: u64) {
291+
match () {
292+
#[cfg(target_arch = "aarch64")]
293+
() => core::arch::asm!("TLBI VAALE1, {v}", v = in(reg) val, options(nostack)),
294+
295+
#[cfg(not(target_arch = "aarch64"))]
296+
() => {
297+
let _ = val;
298+
unimplemented!()
299+
}
300+
}
301+
}
302+
303+
/// Invalidate TLB entries by VA, all ASIDs, last level, EL1&0,
304+
/// current VMID, Inner Shareable.
305+
///
306+
/// Executes `TLBI VAALE1IS, <Xt>`.
307+
///
308+
/// # Operand Encoding
309+
///
310+
/// - Bits \[43:0\]: VA\[55:12\]
311+
///
312+
/// # Safety
313+
///
314+
/// This is a privileged instruction that requires EL1 or higher.
315+
/// The caller must provide a correctly encoded operand and perform
316+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
317+
#[inline(always)]
318+
pub unsafe fn vaale1is(val: u64) {
319+
match () {
320+
#[cfg(target_arch = "aarch64")]
321+
() => core::arch::asm!("TLBI VAALE1IS, {v}", v = in(reg) val, options(nostack)),
322+
323+
#[cfg(not(target_arch = "aarch64"))]
324+
() => {
325+
let _ = val;
326+
unimplemented!()
327+
}
328+
}
329+
}
330+
331+
/// Invalidate TLB entries by ASID, EL1&0, current VMID.
332+
///
333+
/// Executes `TLBI ASIDE1, <Xt>`.
334+
///
335+
/// # Operand Encoding
336+
///
337+
/// - Bits \[55:48\]: ASID
338+
///
339+
/// # Safety
340+
///
341+
/// This is a privileged instruction that requires EL1 or higher.
342+
/// The caller must provide a correctly encoded operand and perform
343+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
344+
#[inline(always)]
345+
pub unsafe fn aside1(val: u64) {
346+
match () {
347+
#[cfg(target_arch = "aarch64")]
348+
() => core::arch::asm!("TLBI ASIDE1, {v}", v = in(reg) val, options(nostack)),
349+
350+
#[cfg(not(target_arch = "aarch64"))]
351+
() => {
352+
let _ = val;
353+
unimplemented!()
354+
}
355+
}
356+
}
357+
358+
/// Invalidate TLB entries by ASID, EL1&0, current VMID,
359+
/// Inner Shareable.
360+
///
361+
/// Executes `TLBI ASIDE1IS, <Xt>`.
362+
///
363+
/// # Operand Encoding
364+
///
365+
/// - Bits \[55:48\]: ASID
366+
///
367+
/// # Safety
368+
///
369+
/// This is a privileged instruction that requires EL1 or higher.
370+
/// The caller must provide a correctly encoded operand and perform
371+
/// the required DSB/ISB synchronization (see [`barrier`](super::barrier)).
372+
#[inline(always)]
373+
pub unsafe fn aside1is(val: u64) {
374+
match () {
375+
#[cfg(target_arch = "aarch64")]
376+
() => core::arch::asm!("TLBI ASIDE1IS, {v}", v = in(reg) val, options(nostack)),
377+
378+
#[cfg(not(target_arch = "aarch64"))]
379+
() => {
380+
let _ = val;
381+
unimplemented!()
382+
}
383+
}
384+
}

0 commit comments

Comments
 (0)