#![allow(dead_code)]
use core::sync::atomic::{AtomicBool, Ordering};
static MTE_AVAILABLE: AtomicBool = AtomicBool::new(false);
#[cfg(target_arch = "aarch64")]
pub unsafe fn init() {
const AT_HWCAP2: libc::c_ulong = 26;
const HWCAP2_MTE: libc::c_ulong = 1 << 18;
let hwcap2 = libc::getauxval(AT_HWCAP2);
if hwcap2 & HWCAP2_MTE == 0 {
return;
}
const PR_SET_TAGGED_ADDR_CTRL: libc::c_int = 55;
const PR_TAGGED_ADDR_ENABLE: libc::c_ulong = 1;
const PR_MTE_TCF_SYNC: libc::c_ulong = 1 << 1;
const PR_MTE_TAG_MASK: libc::c_ulong = 0xfffe << 3;
let ret = libc::prctl(
PR_SET_TAGGED_ADDR_CTRL,
PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TAG_MASK,
0,
0,
0,
);
if ret == 0 {
MTE_AVAILABLE.store(true, Ordering::Release);
}
}
#[cfg(not(target_arch = "aarch64"))]
pub unsafe fn init() {}
#[inline(always)]
pub fn is_available() -> bool {
MTE_AVAILABLE.load(Ordering::Relaxed)
}
#[cfg(target_arch = "aarch64")]
#[inline(always)]
pub unsafe fn tag_alloc(ptr: *mut u8) -> *mut u8 {
let tagged: *mut u8;
core::arch::asm!(
"irg {out}, {inp}",
inp = in(reg) ptr,
out = out(reg) tagged,
options(nomem, nostack, preserves_flags),
);
tagged
}
#[cfg(not(target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn tag_alloc(ptr: *mut u8) -> *mut u8 {
ptr
}
#[cfg(target_arch = "aarch64")]
#[inline]
pub unsafe fn tag_region(ptr: *mut u8, size: usize) {
let mut offset = 0usize;
while offset < size {
core::arch::asm!(
"stg {ptr}, [{ptr}]",
ptr = in(reg) ptr.add(offset),
options(nostack, preserves_flags),
);
offset += 16;
}
}
#[cfg(not(target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn tag_region(_ptr: *mut u8, _size: usize) {}
#[cfg(target_arch = "aarch64")]
#[inline]
pub unsafe fn tag_freed(ptr: *mut u8, size: usize) {
let new_tagged = tag_alloc(ptr);
tag_region(new_tagged, size);
}
#[cfg(not(target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn tag_freed(_ptr: *mut u8, _size: usize) {}
#[cfg(target_arch = "aarch64")]
pub unsafe fn map_anonymous_mte(size: usize) -> *mut u8 {
const PROT_MTE: libc::c_int = 0x20;
let result = libc::mmap(
core::ptr::null_mut(),
size,
libc::PROT_READ | libc::PROT_WRITE | PROT_MTE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
);
if result == libc::MAP_FAILED {
core::ptr::null_mut()
} else {
result as *mut u8
}
}
#[cfg(not(target_arch = "aarch64"))]
pub unsafe fn map_anonymous_mte(size: usize) -> *mut u8 {
crate::platform::map_anonymous(size)
}