use crate::asm::{tt, tta, ttat, ttt};
use bitfield::bitfield;
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum AccessType {
Current,
Unprivileged,
NonSecure,
NonSecureUnprivileged,
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct TestTarget {
tt_resp: TtResp,
access_type: AccessType,
}
bitfield! {
#[derive(PartialEq, Copy, Clone)]
struct TtResp(u32);
impl Debug;
mregion, _: 7, 0;
sregion, _: 15, 8;
mrvalid, _: 16;
srvalid, _: 17;
r, _: 18;
rw, _: 19;
nsr, _: 20;
nsrw, _: 21;
s, _: 22;
irvalid, _: 23;
iregion, _: 31, 24;
}
impl TestTarget {
#[inline]
pub fn check(addr: *mut u32, access_type: AccessType) -> Self {
let tt_resp = match access_type {
AccessType::Current => TtResp(tt(addr)),
AccessType::Unprivileged => TtResp(ttt(addr)),
AccessType::NonSecure => TtResp(tta(addr)),
AccessType::NonSecureUnprivileged => TtResp(ttat(addr)),
};
TestTarget {
tt_resp,
access_type,
}
}
#[inline]
pub fn check_range(addr: *mut u32, size: usize, access_type: AccessType) -> Option<Self> {
let begin: usize = addr as usize;
let end: usize = begin.checked_add(size.checked_sub(1)?)?;
let single_check: bool = (begin % 32).checked_add(size)? <= 32usize;
let test_start = TestTarget::check(addr, access_type);
if single_check {
Some(test_start)
} else {
let test_end = TestTarget::check(end as *mut u32, access_type);
if test_start != test_end {
None
} else {
Some(test_start)
}
}
}
#[inline]
pub fn access_type(self) -> AccessType {
self.access_type
}
#[inline]
pub fn as_u32(self) -> u32 {
self.tt_resp.0
}
#[inline]
pub fn readable(self) -> bool {
self.tt_resp.r()
}
#[inline]
pub fn read_and_writable(self) -> bool {
self.tt_resp.rw()
}
#[inline]
pub fn mpu_region(self) -> Option<u8> {
if self.tt_resp.srvalid() {
Some(self.tt_resp.sregion() as u8)
} else {
None
}
}
#[inline]
pub fn secure(self) -> bool {
self.tt_resp.s()
}
#[inline]
pub fn ns_readable(self) -> bool {
self.tt_resp.nsr()
}
#[inline]
pub fn ns_read_and_writable(self) -> bool {
self.tt_resp.nsrw()
}
#[inline]
pub fn idau_region(self) -> Option<u8> {
if self.tt_resp.irvalid() {
Some(self.tt_resp.iregion() as u8)
} else {
None
}
}
#[inline]
pub fn sau_region(self) -> Option<u8> {
if self.tt_resp.srvalid() {
Some(self.tt_resp.sregion() as u8)
} else {
None
}
}
}