x86_64/instructions/
port.rsuse core::arch::asm;
use core::fmt;
use core::marker::PhantomData;
use crate::sealed::Sealed;
pub use crate::structures::port::{PortRead, PortWrite};
impl PortRead for u8 {
#[inline]
unsafe fn read_from_port(port: u16) -> u8 {
let value: u8;
unsafe {
asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags));
}
value
}
}
impl PortRead for u16 {
#[inline]
unsafe fn read_from_port(port: u16) -> u16 {
let value: u16;
unsafe {
asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags));
}
value
}
}
impl PortRead for u32 {
#[inline]
unsafe fn read_from_port(port: u16) -> u32 {
let value: u32;
unsafe {
asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags));
}
value
}
}
impl PortWrite for u8 {
#[inline]
unsafe fn write_to_port(port: u16, value: u8) {
unsafe {
asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags));
}
}
}
impl PortWrite for u16 {
#[inline]
unsafe fn write_to_port(port: u16, value: u16) {
unsafe {
asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags));
}
}
}
impl PortWrite for u32 {
#[inline]
unsafe fn write_to_port(port: u16, value: u32) {
unsafe {
asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags));
}
}
}
pub trait PortAccess: Sealed {
const DEBUG_STR: &'static str;
}
pub trait PortReadAccess: PortAccess {}
pub trait PortWriteAccess: PortAccess {}
#[derive(Debug)]
pub struct ReadOnlyAccess(());
impl Sealed for ReadOnlyAccess {}
impl PortAccess for ReadOnlyAccess {
const DEBUG_STR: &'static str = "ReadOnly";
}
impl PortReadAccess for ReadOnlyAccess {}
#[derive(Debug)]
pub struct WriteOnlyAccess(());
impl Sealed for WriteOnlyAccess {}
impl PortAccess for WriteOnlyAccess {
const DEBUG_STR: &'static str = "WriteOnly";
}
impl PortWriteAccess for WriteOnlyAccess {}
#[derive(Debug)]
pub struct ReadWriteAccess(());
impl Sealed for ReadWriteAccess {}
impl PortAccess for ReadWriteAccess {
const DEBUG_STR: &'static str = "ReadWrite";
}
impl PortReadAccess for ReadWriteAccess {}
impl PortWriteAccess for ReadWriteAccess {}
pub struct PortGeneric<T, A> {
port: u16,
phantom: PhantomData<(T, A)>,
}
pub type Port<T> = PortGeneric<T, ReadWriteAccess>;
pub type PortReadOnly<T> = PortGeneric<T, ReadOnlyAccess>;
pub type PortWriteOnly<T> = PortGeneric<T, WriteOnlyAccess>;
impl<T, A> PortGeneric<T, A> {
#[inline]
pub const fn new(port: u16) -> PortGeneric<T, A> {
PortGeneric {
port,
phantom: PhantomData,
}
}
}
impl<T: PortRead, A: PortReadAccess> PortGeneric<T, A> {
#[inline]
pub unsafe fn read(&mut self) -> T {
unsafe { T::read_from_port(self.port) }
}
}
impl<T: PortWrite, A: PortWriteAccess> PortGeneric<T, A> {
#[inline]
pub unsafe fn write(&mut self, value: T) {
unsafe { T::write_to_port(self.port, value) }
}
}
impl<T, A: PortAccess> fmt::Debug for PortGeneric<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PortGeneric")
.field("port", &self.port)
.field("size", &core::mem::size_of::<T>())
.field("access", &format_args!("{}", A::DEBUG_STR))
.finish()
}
}
impl<T, A> Clone for PortGeneric<T, A> {
fn clone(&self) -> Self {
Self {
port: self.port,
phantom: PhantomData,
}
}
}
impl<T, A> PartialEq for PortGeneric<T, A> {
fn eq(&self, other: &Self) -> bool {
self.port == other.port
}
}
impl<T, A> Eq for PortGeneric<T, A> {}