1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
//! AArch64 system registers.
use core::marker::PhantomData;
use super::*;
pub trait SystemRegisterSpec: RegisterSpec<Bits = u64> {
// HACK: since asm! doesn't like non-literal string values, we can't just have an associated
// constant with the system register name.
/// Returns the value of the system register, read with `mrs`.
unsafe fn mrs() -> u64;
/// Writes the provided value to the system register with `msr`.
unsafe fn msr(bits: u64);
}
impl<T: SystemRegisterSpec> RegisterSpec for T {
type Bits = u64;
}
/// An AArch64 system register accessed with the `mrs` and `msr` assembly instructions.
pub struct Register<S: SystemRegisterSpec>(PhantomData<S>);
impl<S: SystemRegisterSpec> Register<S> {
pub fn new() -> Self {
Self(Default::default())
}
}
impl<S: SystemRegisterSpec + RegisterReadable> Register<S> {
/// Reads the current value of the register, providing access through an instance of
/// [`RegisterReader`].
///
/// The register's value is only read once: when `read` is called. This is the value accessed
/// through bit or field getters on [`RegisterReader`] inside the `reader` closure.
///
/// The return value of the `reader` closure is returned by `read`.
pub fn read<R>(&self, reader: impl FnOnce(&RegisterReader<S>) -> R) -> R {
let r = RegisterReader::new(unsafe { S::mrs() });
reader(&r)
}
}
impl<S: SystemRegisterSpec + RegisterWritable> Register<S> {
/// Writes a value built by an instance of [`RegisterWriter`], initialised to zero, to the
/// register.
///
/// The register's value is only written once: when the `writer` closure returns. The value
/// written is the value built through bit or field setters on [`RegisterWriter`] inside the
/// `writer` closure.
///
/// # Safety
/// Setting bits or fields to zero may result in undefined behaviour, as zero is not guaranteed
/// to be a supported value. Refer to the register's definition to determine valid values.
pub unsafe fn write_zero(&self, writer: impl FnOnce(&mut RegisterWriter<S>)) {
let mut w = RegisterWriter::zero();
writer(&mut w);
unsafe { S::msr(w.bits) }
}
}
impl<S: SystemRegisterSpec + RegisterWritable + RegisterInitial> Register<S> {
/// Writes a value built by an instance of [`RegisterWriter`], initialised to the register's
/// initial value (provided by [`RegisterInitial`]), to the register.
///
/// The register's value is only written once: when the `writer` closure returns. The value
/// written is the value built through bit or field setters on [`RegisterWriter`] inside the
/// `writer` closure.
pub fn write_initial(&self, writer: impl FnOnce(&mut RegisterWriter<S>)) {
let mut w = RegisterWriter::initial();
writer(&mut w);
unsafe { S::msr(w.bits) }
}
}