diff --git a/src/device/net/mod.rs b/src/device/net/mod.rs index fa13b44..8375946 100644 --- a/src/device/net/mod.rs +++ b/src/device/net/mod.rs @@ -82,7 +82,7 @@ bitflags! { bitflags! { #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] - struct Status: u16 { + pub(crate) struct Status: u16 { const LINK_UP = 1; const ANNOUNCE = 2; } diff --git a/src/transport/pci/bus.rs b/src/transport/pci/bus.rs index 0a3014b..52f861e 100644 --- a/src/transport/pci/bus.rs +++ b/src/transport/pci/bus.rs @@ -202,7 +202,19 @@ impl PciRoot { // resulting pointer is within the MMIO range of the CAM. unsafe { // Right shift to convert from byte offset to word offset. - (self.mmio_base.add((address >> 2) as usize)).write_volatile(data) + let ptr = self.mmio_base.add((address >> 2) as usize); + #[cfg(not(target_arch = "aarch64"))] + { + ptr.write_volatile(data) + } + #[cfg(target_arch = "aarch64")] + { + core::arch::asm!( + "str {value:w}, [{ptr}]", + value = in(reg) data, + ptr = in(reg) ptr, + ) + } } } diff --git a/src/volatile.rs b/src/volatile.rs index b7059d1..67ebba3 100644 --- a/src/volatile.rs +++ b/src/volatile.rs @@ -33,12 +33,14 @@ pub trait VolatileReadable { unsafe fn vread(self) -> T; } +#[cfg(not(target_arch = "aarch64"))] impl VolatileReadable for *const ReadOnly { unsafe fn vread(self) -> T { self.read_volatile().0 } } +#[cfg(not(target_arch = "aarch64"))] impl VolatileReadable for *const Volatile { unsafe fn vread(self) -> T { self.read_volatile().0 @@ -51,18 +53,173 @@ pub trait VolatileWritable { unsafe fn vwrite(self, value: T); } +#[cfg(not(target_arch = "aarch64"))] impl VolatileWritable for *mut WriteOnly { unsafe fn vwrite(self, value: T) { (self as *mut T).write_volatile(value) } } +#[cfg(not(target_arch = "aarch64"))] impl VolatileWritable for *mut Volatile { unsafe fn vwrite(self, value: T) { (self as *mut T).write_volatile(value) } } +#[cfg(target_arch = "aarch64")] +mod aarch64_mmio { + use super::{ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly}; + use crate::{device::net::Status, transport::DeviceStatus}; + use core::arch::asm; + + macro_rules! asm_mmio_write { + ($t:ty, $assembly:literal) => { + impl VolatileWritable<$t> for *mut WriteOnly<$t> { + unsafe fn vwrite(self, value: $t) { + asm!( + $assembly, + value = in(reg) value, + ptr = in(reg) (self as *mut $t), + ); + } + } + + impl VolatileWritable<$t> for *mut Volatile<$t> { + unsafe fn vwrite(self, value: $t) { + asm!( + $assembly, + value = in(reg) value, + ptr = in(reg) (self as *mut $t), + ); + } + } + }; + } + + macro_rules! asm_mmio_read { + ($t:ty, $assembly:literal) => { + impl VolatileReadable<$t> for *const ReadOnly<$t> { + unsafe fn vread(self) -> $t { + let value; + asm!( + $assembly, + value = out(reg) value, + ptr = in(reg) (self as *const $t), + ); + value + } + } + + impl VolatileReadable<$t> for *const Volatile<$t> { + unsafe fn vread(self) -> $t { + let value; + asm!( + $assembly, + value = out(reg) value, + ptr = in(reg) (self as *const $t), + ); + value + } + } + }; + } + + asm_mmio_write!(u8, "strb {value:w}, [{ptr}]"); + asm_mmio_write!(u16, "strh {value:w}, [{ptr}]"); + asm_mmio_write!(u32, "str {value:w}, [{ptr}]"); + asm_mmio_write!(u64, "str {value:x}, [{ptr}]"); + + impl VolatileWritable for *mut WriteOnly { + unsafe fn vwrite(self, value: DeviceStatus) { + let value: u32 = value.bits(); + asm!( + "str {value:w}, [{ptr}]", + value = in(reg) value, + ptr = in(reg) (self as *mut u32), + ); + } + } + + impl VolatileWritable for *mut Volatile { + unsafe fn vwrite(self, value: DeviceStatus) { + let value: u32 = value.bits(); + asm!( + "str {value:w}, [{ptr}]", + value = in(reg) value, + ptr = in(reg) (self as *mut u32), + ); + } + } + + asm_mmio_read!(u8, "ldrb {value:w}, [{ptr}]"); + asm_mmio_read!(u16, "ldrh {value:w}, [{ptr}]"); + asm_mmio_read!(u32, "ldr {value:w}, [{ptr}]"); + asm_mmio_read!(u64, "ldr {value:x}, [{ptr}]"); + + impl VolatileReadable for *const ReadOnly { + unsafe fn vread(self) -> DeviceStatus { + let value: u32; + asm!( + "ldr {value:w}, [{ptr}]", + value = out(reg) value, + ptr = in(reg) (self as *const u32), + ); + DeviceStatus::from_bits_retain(value) + } + } + + impl VolatileReadable for *const Volatile { + unsafe fn vread(self) -> DeviceStatus { + let value: u32; + asm!( + "ldr {value:w}, [{ptr}]", + value = out(reg) value, + ptr = in(reg) (self as *const u32), + ); + DeviceStatus::from_bits_retain(value) + } + } + + impl VolatileReadable for *const ReadOnly { + unsafe fn vread(self) -> Status { + let value: u16; + asm!( + "ldrh {value:w}, [{ptr}]", + value = out(reg) value, + ptr = in(reg) (self as *const u16), + ); + Status::from_bits_retain(value) + } + } + + impl VolatileReadable for *const Volatile { + unsafe fn vread(self) -> Status { + let value: u16; + asm!( + "ldrh {value:w}, [{ptr}]", + value = out(reg) value, + ptr = in(reg) (self as *const u16), + ); + Status::from_bits_retain(value) + } + } + + impl VolatileReadable<[u8; SIZE]> for *const ReadOnly<[u8; SIZE]> { + unsafe fn vread(self) -> [u8; SIZE] { + let mut value = [0; SIZE]; + for i in 0..SIZE { + asm!( + "ldrb {value:w}, [{ptr}]", + value = out(reg) value[i], + ptr = in(reg) (self as *const u8).add(i), + ); + } + value + } + } +} + /// Performs a volatile read from the given field of pointer to a struct representing an MMIO region. /// /// # Usage