x86_64/instructions/
port.rs

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