Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// Sound MMIO requires **indirection**
- #[macro_use]
- mod mmio {
- use ::core::marker::PhantomData;
- pub
- struct VolatileRef<'a, T : Copy + 'a> {
- ptr: *const T,
- lifetime: PhantomData<&'a T>,
- }
- pub
- struct VolatileRefMut<'a, T : Copy + 'a> {
- ptr: *mut T,
- lifetime: PhantomData<&'a mut T>,
- }
- impl<T : Copy> VolatileRef<'_, T> {
- #[inline]
- pub
- unsafe
- fn new (ptr: *const T) -> Self
- {
- Self { ptr, lifetime: PhantomData }
- }
- #[inline]
- pub
- fn read (self: &'_ Self) -> T
- {
- unsafe { ::core::ptr::read_volatile(self.ptr) }
- }
- }
- impl<T : Copy> VolatileRefMut<'_, T> {
- #[inline]
- pub
- unsafe
- fn new (ptr: *mut T) -> Self
- {
- Self { ptr, lifetime: PhantomData }
- }
- #[inline]
- pub
- fn read (self: &'_ Self) -> T
- {
- unsafe { ::core::ptr::read_volatile(self.ptr) }
- }
- #[inline]
- pub
- fn write (self: &'_ Self, value: T)
- {
- unsafe { ::core::ptr::write_volatile(self.ptr, value) }
- }
- }
- macro_rules! mmio_struct {(
- #[repr(C)]
- $(#[$struct_meta:meta])*
- $struct_vis:vis
- struct $StructName:ident {
- $(
- $(#[doc = $docstring:tt])*
- $field_vis:vis
- $field_name:ident : $field_ty:ty
- ),* $(,)?
- }
- ) => (
- #[repr(C)]
- $(#[$struct_meta])*
- $struct_vis
- struct $StructName {
- _private: [u8; 0],
- }
- mod offset_of {
- use super::*;
- #[repr(C)]
- struct OffsetComputer {
- $(
- pub(in super)
- $field_name : $field_ty ,
- )*
- }
- const OFFSET_COMPUTER: OffsetComputer = OffsetComputer {
- $(
- $field_name: 0,
- )*
- };
- $(
- #[allow(bad_style)]
- pub(in super)
- const $field_name: usize = {
- let base = &OFFSET_COMPUTER;
- (
- &base.$field_name as *const $field_ty as usize
- ) - (
- base as *const OffsetComputer as usize
- )
- };
- )*
- }
- impl $StructName {
- $(
- $(#[doc = $docstring])*
- $field_vis
- fn $field_name (self: &'_ mut Self)
- -> $crate::mmio::VolatileRefMut<'_, $field_ty>
- {
- unsafe {
- $crate::mmio::VolatileRefMut::<$field_ty>::new(
- (
- self
- as *mut Self
- as usize
- +
- offset_of::$field_name
- ) as *mut $field_ty
- )
- }
- }
- )*
- }
- )}
- }
- /// SAFETY BOUNDARY
- /// It must not be possible to trigger UB with safe code outside this
- /// module
- mod library {
- #[repr(u32)]
- pub
- enum AuxPeripheral {
- MiniUART = 1,
- SPI1 = 2,
- SPI2 = 4
- }
- mmio_struct! {
- #[repr(C)]
- struct Registers {
- /// read-only memory-mapped register
- pub aux_irq: u32,
- /// read-write memory-mapped register
- pub aux_enb: u32,
- }
- }
- const AUX_BASE_ADDR: *mut Registers = 0xfe000000 as _;
- // struct invariant: singleton type, _i.e._, at most one instance of Aux at any
- // given time.
- pub
- struct Aux {
- registers: *mut Registers,
- }
- /// # Safety
- ///
- /// - Given the invariant, there is no way in the public API to get aliasing
- /// &mut on AUX_BASE_ADDR registers.
- unsafe impl Sync for Aux {}
- impl Aux {
- /// # Safety
- ///
- /// - must be called at most once
- const
- unsafe
- fn new_unchecked () -> Aux
- {
- Aux {
- registers: AUX_BASE_ADDR,
- }
- }
- #[inline]
- fn registers (self: &'_ mut Self)
- -> &'_ mut Registers
- {
- unsafe {
- // # Safety
- //
- // - Singleton pattern guarantees unaliasing of the pointee
- &mut* self.registers
- }
- }
- pub
- fn enable (self: &'_ mut Self, p: AuxPeripheral)
- {
- let aux_enb = self.registers().aux_enb();
- aux_enb.write(aux_enb.read() | p as u32);
- }
- }
- pub
- static AUX: Aux = unsafe {
- Aux::new_unchecked()
- };
- }
- use library::{
- AUX,
- AuxPeripheral,
- };
- fn main ()
- {
- AUX.enable(AuxPeripheral::MiniUART);
- // UB attempt
- // let _ = library::Aux::new_unchecked();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement