x86_64/instructions/
port.rs

1//! Access to I/O ports
2
3use core::arch::asm;
4use core::fmt;
5use core::marker::PhantomData;
6
7use crate::sealed::Sealed;
8pub use crate::structures::port::{PortRead, PortWrite};
9
10impl PortRead for u8 {
11    #[inline]
12    unsafe fn read_from_port(port: u16) -> u8 {
13        let value: u8;
14        unsafe {
15            asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags));
16        }
17        value
18    }
19}
20
21impl PortRead for u16 {
22    #[inline]
23    unsafe fn read_from_port(port: u16) -> u16 {
24        let value: u16;
25        unsafe {
26            asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags));
27        }
28        value
29    }
30}
31
32impl PortRead for u32 {
33    #[inline]
34    unsafe fn read_from_port(port: u16) -> u32 {
35        let value: u32;
36        unsafe {
37            asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags));
38        }
39        value
40    }
41}
42
43impl PortWrite for u8 {
44    #[inline]
45    unsafe fn write_to_port(port: u16, value: u8) {
46        unsafe {
47            asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags));
48        }
49    }
50}
51
52impl PortWrite for u16 {
53    #[inline]
54    unsafe fn write_to_port(port: u16, value: u16) {
55        unsafe {
56            asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags));
57        }
58    }
59}
60
61impl PortWrite for u32 {
62    #[inline]
63    unsafe fn write_to_port(port: u16, value: u32) {
64        unsafe {
65            asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags));
66        }
67    }
68}
69
70/// A marker trait for access types which allow accessing port values.
71pub trait PortAccess: Sealed {
72    /// A string representation for debug output.
73    const DEBUG_STR: &'static str;
74}
75
76/// A marker trait for access types which allow reading port values.
77pub trait PortReadAccess: PortAccess {}
78
79/// A marker trait for access types which allow writing port values.
80pub trait PortWriteAccess: PortAccess {}
81
82/// An access marker type indicating that a port is only allowed to read values.
83#[derive(Debug)]
84pub struct ReadOnlyAccess(());
85
86impl Sealed for ReadOnlyAccess {}
87impl PortAccess for ReadOnlyAccess {
88    const DEBUG_STR: &'static str = "ReadOnly";
89}
90impl PortReadAccess for ReadOnlyAccess {}
91
92/// An access marker type indicating that a port is only allowed to write values.
93#[derive(Debug)]
94pub struct WriteOnlyAccess(());
95
96impl Sealed for WriteOnlyAccess {}
97impl PortAccess for WriteOnlyAccess {
98    const DEBUG_STR: &'static str = "WriteOnly";
99}
100impl PortWriteAccess for WriteOnlyAccess {}
101
102/// An access marker type indicating that a port is allowed to read or write values.
103#[derive(Debug)]
104pub struct ReadWriteAccess(());
105
106impl Sealed for ReadWriteAccess {}
107impl PortAccess for ReadWriteAccess {
108    const DEBUG_STR: &'static str = "ReadWrite";
109}
110impl PortReadAccess for ReadWriteAccess {}
111impl PortWriteAccess for ReadWriteAccess {}
112
113/// An I/O port.
114///
115/// The port reads or writes values of type `T` and has read/write access specified by `A`.
116///
117/// Use the provided marker types or aliases to get a port type with the access you need:
118/// * `PortGeneric<T, ReadWriteAccess>` -> `Port<T>`
119/// * `PortGeneric<T, ReadOnlyAccess>` -> `PortReadOnly<T>`
120/// * `PortGeneric<T, WriteOnlyAccess>` -> `PortWriteOnly<T>`
121pub struct PortGeneric<T, A> {
122    port: u16,
123    phantom: PhantomData<(T, A)>,
124}
125
126/// A read-write I/O port.
127pub type Port<T> = PortGeneric<T, ReadWriteAccess>;
128
129/// A read-only I/O port.
130pub type PortReadOnly<T> = PortGeneric<T, ReadOnlyAccess>;
131
132/// A write-only I/O port.
133pub type PortWriteOnly<T> = PortGeneric<T, WriteOnlyAccess>;
134
135impl<T, A> PortGeneric<T, A> {
136    /// Creates an I/O port with the given port number.
137    #[inline]
138    pub const fn new(port: u16) -> PortGeneric<T, A> {
139        PortGeneric {
140            port,
141            phantom: PhantomData,
142        }
143    }
144}
145
146impl<T: PortRead, A: PortReadAccess> PortGeneric<T, A> {
147    /// Reads from the port.
148    ///
149    /// ## Safety
150    ///
151    /// This function is unsafe because the I/O port could have side effects that violate memory
152    /// safety.
153    #[doc(alias = "in")]
154    #[doc(alias = "inb")]
155    #[doc(alias = "inw")]
156    #[doc(alias = "inl")]
157    #[inline]
158    pub unsafe fn read(&mut self) -> T {
159        unsafe { T::read_from_port(self.port) }
160    }
161}
162
163impl<T: PortWrite, A: PortWriteAccess> PortGeneric<T, A> {
164    /// Writes to the port.
165    ///
166    /// ## Safety
167    ///
168    /// This function is unsafe because the I/O port could have side effects that violate memory
169    /// safety.
170    #[doc(alias = "out")]
171    #[doc(alias = "outb")]
172    #[doc(alias = "outw")]
173    #[doc(alias = "outl")]
174    #[inline]
175    pub unsafe fn write(&mut self, value: T) {
176        unsafe { T::write_to_port(self.port, value) }
177    }
178}
179
180impl<T, A: PortAccess> fmt::Debug for PortGeneric<T, A> {
181    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182        f.debug_struct("PortGeneric")
183            .field("port", &self.port)
184            .field("size", &core::mem::size_of::<T>())
185            .field("access", &format_args!("{}", A::DEBUG_STR))
186            .finish()
187    }
188}
189
190impl<T, A> Clone for PortGeneric<T, A> {
191    fn clone(&self) -> Self {
192        Self {
193            port: self.port,
194            phantom: PhantomData,
195        }
196    }
197}
198
199impl<T, A> PartialEq for PortGeneric<T, A> {
200    fn eq(&self, other: &Self) -> bool {
201        self.port == other.port
202    }
203}
204
205impl<T, A> Eq for PortGeneric<T, A> {}